Merge pull request #776 from andreaturli/vcloud-director

added compose and recompose vapp live test
This commit is contained in:
Adrian Cole 2012-08-09 11:36:04 -07:00
commit d2d476e912
8 changed files with 231 additions and 38 deletions

View File

@ -74,7 +74,7 @@ public class VAppTemplate extends ResourceEntity {
public static abstract class Builder<B extends Builder<B>> extends ResourceEntity.Builder<B> {
private Owner owner;
private Set<VAppTemplate> children = Sets.newLinkedHashSet();
private Set<Vm> children = Sets.newLinkedHashSet();
private Set<SectionType> sections = Sets.newLinkedHashSet();
private String vAppScopedLocalId;
private Boolean ovfDescriptorUploaded;
@ -91,7 +91,7 @@ public class VAppTemplate extends ResourceEntity {
/**
* @see VAppTemplate#getChildren()
*/
public B children(Iterable<VAppTemplate> children) {
public B children(Iterable<Vm> children) {
this.children = Sets.newLinkedHashSet(checkNotNull(children, "children"));
return self();
}
@ -148,7 +148,7 @@ public class VAppTemplate extends ResourceEntity {
private Owner owner;
@XmlElementWrapper(name = "Children")
@XmlElement(name = "Vm")
private Set<VAppTemplate> children = Sets.newLinkedHashSet();
private Set<Vm> children = Sets.newLinkedHashSet();
@XmlElementRefs({
@XmlElementRef(type = VirtualHardwareSection.class),
@XmlElementRef(type = LeaseSettingsSection.class),
@ -179,7 +179,7 @@ public class VAppTemplate extends ResourceEntity {
protected VAppTemplate(Builder<?> builder) {
super(builder);
this.owner = builder.owner;
this.children = builder.children.isEmpty() ? Collections.<VAppTemplate>emptySet() : ImmutableSet.copyOf(builder.children);
this.children = builder.children.isEmpty() ? Collections.<Vm>emptySet() : ImmutableSet.copyOf(builder.children);
this.sections = builder.sections.isEmpty() ? null : ImmutableSet.copyOf(builder.sections);
this.vAppScopedLocalId = builder.vAppScopedLocalId;
this.ovfDescriptorUploaded = builder.ovfDescriptorUploaded;
@ -200,7 +200,7 @@ public class VAppTemplate extends ResourceEntity {
/**
* Gets the value of the children property.
*/
public Set<VAppTemplate> getChildren() {
public Set<Vm> getChildren() {
return children;
}

View File

@ -180,5 +180,4 @@ public interface VdcApi {
*/
@Delegate
MetadataApi.Readable getMetadataApi();
}

View File

@ -691,8 +691,8 @@ public class Checks {
// Check optional fields
Owner owner = template.getOwner();
if (owner != null) checkOwner(owner);
for (VAppTemplate child : template.getChildren()) {
checkVAppTemplate(child);
for (Vm child : template.getChildren()) {
checkVm(child);
}
for (SectionType section : template.getSections()) {
checkSectionType(section);
@ -735,8 +735,8 @@ public class Checks {
if (params.isSharedToEveryone()) {
assertNotNull(params.getEveryoneAccessLevel(), String.format(OBJ_FIELD_REQ, "ControlAccessParams", "EveryoneAccessLevel"));
assertNotNull(params.getAccessSettings(), String.format(OBJ_FIELD_REQ, "ControlAccessParams", "AccessSettings when isSharedToEveryone"));
assertTrue(params.getAccessSettings().size() >= 1, String.format(OBJ_FIELD_GTE_1, "ControlAccessParams", "AccessSettings.size", params.getAccessSettings().size()));
} else {
assertTrue(params.getAccessSettings().size() >= 1, String.format(OBJ_FIELD_GTE_1, "ControlAccessParams", "AccessSettings.size", params.getAccessSettings().size()));
for (AccessSetting setting : params.getAccessSettings()) {
checkAccessSetting(setting);
}

View File

@ -51,6 +51,7 @@ import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -75,19 +76,36 @@ import org.jclouds.vcloud.director.v1_5.domain.Reference;
import org.jclouds.vcloud.director.v1_5.domain.ResourceEntity.Status;
import org.jclouds.vcloud.director.v1_5.domain.Task;
import org.jclouds.vcloud.director.v1_5.domain.VApp;
import org.jclouds.vcloud.director.v1_5.domain.VAppTemplate;
import org.jclouds.vcloud.director.v1_5.domain.Vm;
import org.jclouds.vcloud.director.v1_5.domain.network.NetworkAssignment;
import org.jclouds.vcloud.director.v1_5.domain.network.NetworkConnection;
import org.jclouds.vcloud.director.v1_5.domain.network.VAppNetworkConfiguration;
import org.jclouds.vcloud.director.v1_5.domain.params.ComposeVAppParams;
import org.jclouds.vcloud.director.v1_5.domain.params.ControlAccessParams;
import org.jclouds.vcloud.director.v1_5.domain.params.DeployVAppParams;
import org.jclouds.vcloud.director.v1_5.domain.params.InstantiationParams;
import org.jclouds.vcloud.director.v1_5.domain.params.RecomposeVAppParams;
import org.jclouds.vcloud.director.v1_5.domain.params.SourcedCompositionItemParam;
import org.jclouds.vcloud.director.v1_5.domain.params.UndeployVAppParams;
import org.jclouds.vcloud.director.v1_5.domain.query.QueryResultRecordType;
import org.jclouds.vcloud.director.v1_5.domain.query.QueryResultRecords;
import org.jclouds.vcloud.director.v1_5.domain.section.GuestCustomizationSection;
import org.jclouds.vcloud.director.v1_5.domain.section.LeaseSettingsSection;
import org.jclouds.vcloud.director.v1_5.domain.section.NetworkConfigSection;
import org.jclouds.vcloud.director.v1_5.domain.section.NetworkConnectionSection;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.CharMatcher;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
/**
* Tests behavior of the {@link VAppApi}.
@ -191,6 +209,62 @@ public class VAppApiLiveTest extends AbstractVAppApiLiveTest {
assertVAppStatus(vAppURI, Status.POWERED_OFF);
}
@Test(description = "POST /vApp/{id}/action/recomposeVApp")
public void testRecomposeVApp() {
Set<Vm> vms = getAvailableVMsFromVAppTemplates();
VApp composedVApp = vdcApi.composeVApp(vdcURI, ComposeVAppParams.builder()
.name(name("composed-"))
.instantiationParams(instantiationParams())
.build());
// get the first vm to be added to vApp
Vm toAddVm = Iterables.get(vms, 0);
RecomposeVAppParams params = createRecomposeParams(composedVApp, toAddVm);
// The method under test
Task recomposeVApp = vAppApi.recompose(composedVApp.getHref(), params);
assertTaskSucceedsLong(recomposeVApp);
// add another vm instance to vApp
params = createRecomposeParams(composedVApp, toAddVm);
recomposeVApp = vAppApi.recompose(composedVApp.getHref(), params);
assertTaskSucceedsLong(recomposeVApp);
// delete a vm
VApp configured = vAppApi.getVApp(composedVApp.getHref());
List<Vm> vmsToBeDeleted = configured.getChildren().getVms();
Vm toBeDeleted = Iterables.get(vmsToBeDeleted, 0);
Task deleteVm = vmApi.deleteVm(toBeDeleted.getHref());
assertTaskSucceedsLong(deleteVm);
Task deleteVApp = vAppApi.deleteVApp(composedVApp.getHref());
assertTaskSucceedsLong(deleteVApp);
}
private Set<Vm> getAvailableVMsFromVAppTemplates() {
Set<Vm> vms = Sets.newLinkedHashSet();
QueryResultRecords templatesRecords = queryApi.vAppTemplatesQueryAll();
for (QueryResultRecordType templateRecord : templatesRecords.getRecords()) {
VAppTemplate vAppTemplate = vAppTemplateApi.getVAppTemplate(templateRecord.getHref());
vms.addAll(vAppTemplate.getChildren());
}
return ImmutableSet.copyOf(Iterables.filter(vms, new Predicate<Vm>() {
// filter out vms in the vApp template with computer name that contains underscores, dots, or both.
@Override
public boolean apply(Vm input) {
GuestCustomizationSection guestCustomizationSection = vmApi.getGuestCustomizationSection(input.getHref());
String computerName = guestCustomizationSection.getComputerName();
String retainComputerName = CharMatcher.inRange('0', '9')
.or(CharMatcher.inRange('a', 'z'))
.or(CharMatcher.inRange('A', 'Z'))
.or(CharMatcher.is('-'))
.retainFrom(computerName);
return computerName.equals(retainComputerName);
}
}));
}
/**
* @see VAppApi#modifyVApp(URI, VApp)
*/
@ -274,14 +348,14 @@ public class VAppApiLiveTest extends AbstractVAppApiLiveTest {
vApp = powerOnVApp(vApp.getHref());
// The method under test
Task shutdown = vAppApi.shutdown(vAppURI);
Task shutdown = vAppApi.shutdown(vApp.getHref());
assertTaskSucceedsLong(shutdown);
// Get the updated VApp
vApp = vAppApi.getVApp(vAppURI);
vApp = vAppApi.getVApp(vApp.getHref());
// Check status
assertVAppStatus(vAppURI, Status.POWERED_OFF);
assertVAppStatus(vApp.getHref(), Status.POWERED_OFF);
// Power on the VApp again
vApp = powerOnVApp(vApp.getHref());
@ -378,6 +452,7 @@ public class VAppApiLiveTest extends AbstractVAppApiLiveTest {
@Test(description = "POST /vApp/{id}/action/controlAccess", dependsOnMethods = { "testControlAccessUser" })
public void testControlAccessEveryone() {
ControlAccessParams params = ControlAccessParams.builder()
.sharedToEveryone()
.everyoneAccessLevel("FullControl")
@ -404,8 +479,9 @@ public class VAppApiLiveTest extends AbstractVAppApiLiveTest {
assertTrue(retryTaskSuccess.apply(discardSuspendedState), String.format(TASK_COMPLETE_TIMELY, "discardSuspendedState"));
}
@Test(description = "POST /vApp/{id}/action/enterMaintenanceMode")
@Test(description = "POST /vApp/{id}/action/enterMaintenanceMode", groups = {"systemAdmin"})
public void testEnterMaintenanceMode() {
// Do this to a new vApp, so don't mess up subsequent tests by making the vApp read-only
VApp temp = instantiateVApp();
DeployVAppParams params = DeployVAppParams.builder()
@ -430,7 +506,7 @@ public class VAppApiLiveTest extends AbstractVAppApiLiveTest {
}
}
@Test(description = "POST /vApp/{id}/action/exitMaintenanceMode", dependsOnMethods = { "testEnterMaintenanceMode" })
@Test(description = "POST /vApp/{id}/action/exitMaintenanceMode", dependsOnMethods = { "testEnterMaintenanceMode" }, groups = {"systemAdmin"})
public void testExitMaintenanceMode() {
// Do this to a new vApp, so don't mess up subsequent tests by making the vApp read-only
VApp temp = instantiateVApp();
@ -456,18 +532,6 @@ public class VAppApiLiveTest extends AbstractVAppApiLiveTest {
}
}
// FIXME "Could not bind object to request[method=POST, endpoint=https://mycloud.greenhousedata.com/api/vApp/vapp-e124f3f0-adb9-4268-ad49-e54fb27e40af/action/recomposeVApp,
// headers={Accept=[application/vnd.vmware.vcloud.task+xml]}, payload=[content=true, contentMetadata=[contentDisposition=null, contentEncoding=null, contentLanguage=null,
// contentLength=0, contentMD5=null, contentType=application/vnd.vmware.vcloud.recomposeVAppParams+xml], written=false]]: Could not marshall object"
@Test(description = "POST /vApp/{id}/action/recomposeVApp", dependsOnMethods = { "testGetVApp" })
public void testRecomposeVApp() {
RecomposeVAppParams params = RecomposeVAppParams.builder().build();
// The method under test
Task recomposeVApp = vAppApi.recompose(vApp.getHref(), params);
assertTrue(retryTaskSuccess.apply(recomposeVApp), String.format(TASK_COMPLETE_TIMELY, "recomposeVApp"));
}
@Test(description = "GET /vApp/{id}/controlAccess", dependsOnMethods = { "testGetVApp" })
public void testGetControlAccess() {
// The method under test
@ -640,7 +704,7 @@ public class VAppApiLiveTest extends AbstractVAppApiLiveTest {
assertEquals(modified.getProductSections().size(), oldSections.getProductSections().size() + 1);
// Check the section was modified correctly
assertEquals(modified, newSections, String.format(ENTITY_EQUAL, "ProductSectionList"));
assertEquals(modified, newSections);
}
@Test(description = "GET /vApp/{id}/startupSection", dependsOnMethods = { "testGetVApp" })
@ -689,6 +753,11 @@ public class VAppApiLiveTest extends AbstractVAppApiLiveTest {
@Test(description = "GET /vApp/{id}/metadata", dependsOnMethods = { "testSetMetadataValue" })
public void testGetMetadata() {
key = name("key-");
String value = name("value-");
metadataValue = MetadataValue.builder().value(value).build();
vAppApi.getMetadataApi().setMetadata(vApp.getHref(), key, metadataValue);
// Call the method being tested
Metadata metadata = vAppApi.getMetadataApi().getMetadata(vApp.getHref());
@ -762,4 +831,73 @@ public class VAppApiLiveTest extends AbstractVAppApiLiveTest {
VApp deleted = vAppApi.getVApp(temp.getHref());
assertNull(deleted, "The VApp "+temp.getName()+" should have been deleted");
}
/**
* Create the recompose vapp params.
*
* @param vappTemplateRef
* @param vdc
* @return
* @throws VCloudException
*/
public RecomposeVAppParams createRecomposeParams(VApp vApp, Vm vm) {
// creating an item element. this item will contain the vm which should be added to the vapp.
Reference reference = Reference.builder().name(name("vm-")).href(vm.getHref()).type(vm.getType()).build();
SourcedCompositionItemParam vmItem = SourcedCompositionItemParam.builder().source(reference).build();
InstantiationParams vmInstantiationParams = null;
// if the vm contains a network connection and the vApp does not contain any configured network
if (vmHasNetworkConnectionConfigured(vm) && vAppHasNetworkConfigured(vApp)) {
// creating empty network connection section for the vm.
NetworkConnectionSection networkConnectionSection = NetworkConnectionSection.builder()
.info("Empty network configuration parameters")
.build();
// adding the network connection section to the instantiation params of the vapp.
vmInstantiationParams = InstantiationParams.builder().sections(ImmutableSet.of(networkConnectionSection)).build();
}
// if the vm already contains a network connection section and if the vapp contains a configured network -> vm could be mapped to that network.
NetworkAssignment networkAssignment = null;
if (vmHasNetworkConnectionConfigured(vm) && !vAppHasNetworkConfigured(vApp)) {
for (NetworkConnection networkConnection : vmApi.getNetworkConnectionSection(vm.getHref())
.getNetworkConnections()) {
if (networkConnection.getNetworkConnectionIndex() == vmApi.getNetworkConnectionSection(vm.getHref())
.getPrimaryNetworkConnectionIndex()) {
networkAssignment = NetworkAssignment.builder().innerNetwork(networkConnection.getNetwork())
.containerNetwork(getVAppNetworkConfig(vApp).getNetworkName()).build();
}
}
}
if (vmInstantiationParams != null)
vmItem = SourcedCompositionItemParam.builder().fromSourcedCompositionItemParam(vmItem)
.instantiationParams(vmInstantiationParams)
.build();
if (networkAssignment != null)
vmItem = SourcedCompositionItemParam.builder().fromSourcedCompositionItemParam(vmItem)
.networkAssignment(ImmutableSet.of(networkAssignment))
.build();
return RecomposeVAppParams.builder().name(name("recompose-"))
// adding the vm item.
.sourcedItems(ImmutableList.of(vmItem)).build();
}
private VAppNetworkConfiguration getVAppNetworkConfig(VApp vApp) {
Set<VAppNetworkConfiguration> vAppNetworkConfigs = vAppApi.getNetworkConfigSection(vApp.getHref()).getNetworkConfigs();
return Iterables.tryFind(vAppNetworkConfigs, Predicates.notNull()).orNull();
}
private boolean vAppHasNetworkConfigured(VApp vApp) {
return getVAppNetworkConfig(vApp) != null;
}
private boolean vmHasNetworkConnectionConfigured(Vm vm) {
return vmApi.getNetworkConnectionSection(vm.getHref()).getNetworkConnections().size() > 0;
}
}

View File

@ -49,6 +49,7 @@ import org.jclouds.vcloud.director.v1_5.domain.Owner;
import org.jclouds.vcloud.director.v1_5.domain.Reference;
import org.jclouds.vcloud.director.v1_5.domain.Task;
import org.jclouds.vcloud.director.v1_5.domain.VAppTemplate;
import org.jclouds.vcloud.director.v1_5.domain.Vm;
import org.jclouds.vcloud.director.v1_5.domain.params.RelocateParams;
import org.jclouds.vcloud.director.v1_5.domain.section.CustomizationSection;
import org.jclouds.vcloud.director.v1_5.domain.section.GuestCustomizationSection;
@ -482,7 +483,7 @@ public class VAppTemplateApiExpectTest extends VCloudDirectorAdminApiExpectTest
return VAppTemplate.builder().href(URI.create("https://vcloudbeta.bluelock.com/api/vAppTemplate/vappTemplate-ef4415e6-d413-4cbb-9262-f9bbec5f2ea9"))
.links(ImmutableSet.of(aLink, bLink))
.children(ImmutableSet.<VAppTemplate>of())
.children(ImmutableSet.<Vm>of())
.type("application/vnd.vmware.vcloud.vAppTemplate+xml")
.description("For testing")
.id("urn:vcloud:vapptemplate:ef4415e6-d413-4cbb-9262-f9bbec5f2ea9")

View File

@ -23,6 +23,9 @@ import static org.testng.Assert.assertNull;
import static org.testng.Assert.fail;
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorException;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType;
@ -32,6 +35,9 @@ import org.jclouds.vcloud.director.v1_5.domain.ComputeCapacity;
import org.jclouds.vcloud.director.v1_5.domain.Error;
import org.jclouds.vcloud.director.v1_5.domain.Link;
import org.jclouds.vcloud.director.v1_5.domain.Media;
import org.jclouds.vcloud.director.v1_5.domain.Owner;
import org.jclouds.vcloud.director.v1_5.domain.Task;
import org.jclouds.vcloud.director.v1_5.domain.User;
import org.jclouds.vcloud.director.v1_5.domain.Media.ImageType;
import org.jclouds.vcloud.director.v1_5.domain.Metadata;
import org.jclouds.vcloud.director.v1_5.domain.MetadataValue;
@ -39,6 +45,7 @@ import org.jclouds.vcloud.director.v1_5.domain.Reference;
import org.jclouds.vcloud.director.v1_5.domain.VApp;
import org.jclouds.vcloud.director.v1_5.domain.VAppTemplate;
import org.jclouds.vcloud.director.v1_5.domain.Vdc;
import org.jclouds.vcloud.director.v1_5.domain.org.Org;
import org.jclouds.vcloud.director.v1_5.domain.params.CaptureVAppParams;
import org.jclouds.vcloud.director.v1_5.domain.params.CloneMediaParams;
import org.jclouds.vcloud.director.v1_5.domain.params.CloneVAppParams;
@ -217,11 +224,11 @@ public class VdcApiExpectTest extends VCloudDirectorAdminApiExpectTest {
}
@Test(enabled = false)
public void testComposeVApp() {
public void testComposeVApp() throws ParseException {
VCloudDirectorApi api = requestsSendResponses(loginRequest, sessionResponse,
new VcloudHttpRequestPrimer()
.apiCommand("POST", "/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f/action/composeVApp")
.xmlFilePayload("/vdc/params/composeVApp.xml", VCloudDirectorMediaType.COMPOSE_VAPP_PARAMS)
.xmlFilePayload("/vdc/composeVAppParams.xml", VCloudDirectorMediaType.COMPOSE_VAPP_PARAMS)
.acceptAnyMedia()
.httpRequestBuilder().build(),
new VcloudHttpResponsePrimer()
@ -513,9 +520,56 @@ public class VdcApiExpectTest extends VCloudDirectorAdminApiExpectTest {
return null;
}
private VApp composeVApp() {
// TODO Auto-generated method stub
return null;
private VApp composeVApp() throws ParseException {
return VApp
.builder()
.status(0)
.name("test-vapp")
.id("urn:vcloud:vapp:d0e2b6b9-4381-4ddc-9572-cdfae54059be")
.type("application/vnd.vmware.vcloud.vApp+xml")
.description("Test VApp")
.href(URI.create("https://mycloud.greenhousedata.com/api/vApp/vapp-d0e2b6b9-4381-4ddc-9572-cdfae54059be"))
.link(Link
.builder()
.name("orgNet-cloudsoft-External")
.rel("down")
.type("application/vnd.vmware.vcloud.vAppNetwork+xml")
.href(URI.create("https://mycloud.greenhousedata.com/api/network/2a2e2da4-446a-4ebc-a086-06df7c9570f0"))
.build())
.link(Link
.builder()
.rel("down")
.type("application/vnd.vmware.vcloud.controlAccess+xml")
.href(URI.create("https://mycloud.greenhousedata.com/api/vApp/vapp-d0e2b6b9-4381-4ddc-9572-cdfae54059be/controlAccess/"))
.build())
.link(Link
.builder()
.rel("up")
.type("application/vnd.vmware.vcloud.vdc+xml")
.href(URI.create("https://mycloud.greenhousedata.com/api/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f"))
.build())
.link(Link
.builder()
.rel("down")
.type("application/vnd.vmware.vcloud.owner+xml")
.href(URI.create("https://mycloud.greenhousedata.com/api/vApp/vapp-d0e2b6b9-4381-4ddc-9572-cdfae54059be/owner"))
.build())
.link(Link
.builder()
.rel("down")
.type("application/vnd.vmware.vcloud.metadata+xml")
.href(URI.create("https://mycloud.greenhousedata.com/api/vApp/vapp-d0e2b6b9-4381-4ddc-9572-cdfae54059be/metadata"))
.build())
.owner(Owner
.builder()
.type("application/vnd.vmware.vcloud.owner+xml")
.user(User
.builder()
.type("application/vnd.vmware.admin.user+xml")
.name("acole")
.href(URI.create("https://mycloud.greenhousedata.com/api/admin/user/c090335b-708c-4c1c-9e3d-89560d002120"))
.build().getRole()).build()).build();
}
private VApp instantiateVAppTemplate() {
@ -537,4 +591,5 @@ public class VdcApiExpectTest extends VCloudDirectorAdminApiExpectTest {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -358,7 +358,7 @@ public abstract class BaseVCloudDirectorApiLiveTest extends BaseContextLiveTest<
}
/** Build an {@link InstantiationParams} object. */
private InstantiationParams instantiationParams() {
protected InstantiationParams instantiationParams() {
InstantiationParams instantiationParams = InstantiationParams.builder()
.sections(ImmutableSet.of(networkConfigSection()))
.build();