diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcAsyncClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcAsyncClient.java index 1131a083d6..ddfbf935f2 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcAsyncClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcAsyncClient.java @@ -21,13 +21,22 @@ package org.jclouds.vcloud.director.v1_5.features; import java.net.URI; import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.JAXBResponseParser; import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType; import org.jclouds.vcloud.director.v1_5.domain.AdminVdc; +import org.jclouds.vcloud.director.v1_5.domain.Task; +import org.jclouds.vcloud.director.v1_5.features.MetadataAsyncClient.Writable; import org.jclouds.vcloud.director.v1_5.filters.AddVCloudAuthorizationToRequest; import org.jclouds.vcloud.director.v1_5.functions.ThrowVCloudErrorOn4xx; @@ -40,13 +49,45 @@ import com.google.common.util.concurrent.ListenableFuture; @RequestFilters(AddVCloudAuthorizationToRequest.class) public interface AdminVdcAsyncClient extends VdcAsyncClient { - /** - * @see AdminVdcClient#getVdc(URI) - */ + // TODO Should we use MetadataClient? + @GET @Consumes @JAXBResponseParser @ExceptionParser(ThrowVCloudErrorOn4xx.class) @Override ListenableFuture getVdc(@EndpointParam URI vdcRef); + + @PUT + @Consumes + @Produces(VCloudDirectorMediaType.ADMIN_VDC) + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture editVdc(@EndpointParam URI vdcRef, AdminVdc vdc); + + @DELETE + @Consumes + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture deleteVdc(@EndpointParam URI vdcRef); + + @POST + @Consumes + @Path("/action/enable") + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture enableVdc(@EndpointParam URI vdcRef); + + @POST + @Consumes + @Path("/action/disable") + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture disableVdc(@EndpointParam URI vdcRef); + + /** + * @return asynchronous access to {@link Writable} features + */ + @Delegate + MetadataAsyncClient.Writable getMetadataClient(); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcClient.java index 1254b2fcd6..db6546b397 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcClient.java @@ -22,7 +22,11 @@ import java.net.URI; import java.util.concurrent.TimeUnit; import org.jclouds.concurrent.Timeout; +import org.jclouds.rest.annotations.Delegate; +import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.vcloud.director.v1_5.domain.AdminVdc; +import org.jclouds.vcloud.director.v1_5.domain.Task; +import org.jclouds.vcloud.director.v1_5.features.MetadataAsyncClient.Writable; /** * Provides synchronous access to Network. @@ -46,4 +50,36 @@ public interface AdminVdcClient extends VdcClient { */ @Override AdminVdc getVdc(URI vdcRef); + + /** + * Modifies a Virtual Data Center. Virtual Data Center could be enabled or disabled. + * Additionally it could have one of these states FAILED_CREATION(-1), NOT_READY(0), + * READY(1), UNKNOWN(1) and UNRECOGNIZED(3). + */ + Task editVdc(URI vdcRef, AdminVdc vdc); + + /** + * Deletes a Virtual Data Center. The Virtual Data Center should be disabled when delete is issued. + * Otherwise error code 400 Bad Request is returned. + */ + // TODO Saw what exception, instead of 400 + Task deleteVdc(URI vdcRef); + + /** + * Enables a Virtual Data Center. This operation enables disabled Virtual Data Center. + * If it is already enabled this operation has no effect. + */ + void enableVdc(@EndpointParam URI vdcRef); + + /** + * Disables a Virtual Data Center. If the Virtual Data Center is disabled this operation does not + * have an effect. + */ + void disableVdc(URI vdcRef); + + /** + * @return synchronous access to {@link Writable} features + */ + @Delegate + MetadataClient.Writeable getMetadataClient(); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MetadataClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MetadataClient.java index e524985e3e..3c6688db8c 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MetadataClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MetadataClient.java @@ -35,6 +35,9 @@ import org.jclouds.vcloud.director.v1_5.domain.Task; * @author danikov */ public interface MetadataClient { + + // FIXME Correct spelling of Writeable -> Writable + @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS) public static interface Readable extends MetadataClient { /** diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/AbstractVAppClientLiveTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/AbstractVAppClientLiveTest.java index 5a049a9a6a..0618e5c8d5 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/AbstractVAppClientLiveTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/AbstractVAppClientLiveTest.java @@ -23,9 +23,9 @@ import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.O import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.TASK_COMPLETE_TIMELY; import static org.jclouds.vcloud.director.v1_5.domain.Checks.checkGuestCustomizationSection; import static org.jclouds.vcloud.director.v1_5.domain.Checks.checkNetworkConnectionSection; +import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertFalse; import java.io.IOException; import java.math.BigInteger; @@ -38,9 +38,7 @@ import org.jclouds.vcloud.director.v1_5.domain.GuestCustomizationSection; import org.jclouds.vcloud.director.v1_5.domain.NetworkConnectionSection; import org.jclouds.vcloud.director.v1_5.domain.RasdItemsList; import org.jclouds.vcloud.director.v1_5.domain.Reference; -import org.jclouds.vcloud.director.v1_5.domain.ResourceEntityType.Status; import org.jclouds.vcloud.director.v1_5.domain.Task; -import org.jclouds.vcloud.director.v1_5.domain.UndeployVAppParams; 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; @@ -125,7 +123,7 @@ public abstract class AbstractVAppClientLiveTest extends BaseVCloudDirectorClien * @see #cleanUp() */ @BeforeClass(inheritGroups = true, description = "Cleans up the environment") - protected void setupEnvironment() { + protected void setupEnvironment() throws Exception { // Get the configured Vdc for the tests vdc = vdcClient.getVdc(vdcURI); assertNotNull(vdc, String.format(ENTITY_NON_NULL, VDC)); @@ -187,7 +185,7 @@ public abstract class AbstractVAppClientLiveTest extends BaseVCloudDirectorClien // NOTE This method is also called by the BeforeClass method setupRequiredClients @AfterClass(alwaysRun = true, description = "Cleans up the environment by deleting created VApps named 'test-vapp-*' or 'new-name-*'") - protected void cleanUp() { + protected void cleanUp() throws Exception { // Find references in the Vdc with the VApp type and named 'test-vapp' or 'new-name' Iterable vApps = Iterables.filter( vdc.getResourceEntities().getResourceEntities(), @@ -203,25 +201,7 @@ public abstract class AbstractVAppClientLiveTest extends BaseVCloudDirectorClien // If we found any references, delete the VApp they point to if (vApps != null && !Iterables.isEmpty(vApps)) { for (Reference ref : vApps) { - VApp found = vAppClient.getVApp(ref.getHref()); - // debug(found); - - // Shutdown and power off the VApp if necessary - if (found.getStatus().equals(Status.POWERED_ON.getValue())) { - Task shutdownTask = vAppClient.shutdown(found.getHref()); - retryTaskSuccess.apply(shutdownTask); - } - - // Undeploy the VApp if necessary - if (found.isDeployed()) { - UndeployVAppParams params = UndeployVAppParams.builder().build(); - Task undeployTask = vAppClient.undeploy(found.getHref(), params); - retryTaskSuccess.apply(undeployTask); - } - - // Delete the VApp - Task deleteTask = vAppClient.deleteVApp(found.getHref()); - retryTaskSuccess.apply(deleteTask); + cleanUpVApp(ref.getHref()); } } } diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcClientLiveTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcClientLiveTest.java index e6cfbfd1dc..068db8db64 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcClientLiveTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/AdminVdcClientLiveTest.java @@ -20,11 +20,21 @@ package org.jclouds.vcloud.director.v1_5.features; import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_REQ_LIVE; import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.REF_REQ_LIVE; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; +import java.net.URI; + +import org.jclouds.vcloud.director.v1_5.VCloudDirectorException; import org.jclouds.vcloud.director.v1_5.domain.AdminVdc; import org.jclouds.vcloud.director.v1_5.domain.Checks; +import org.jclouds.vcloud.director.v1_5.domain.Metadata; +import org.jclouds.vcloud.director.v1_5.domain.MetadataEntry; +import org.jclouds.vcloud.director.v1_5.domain.MetadataValue; +import org.jclouds.vcloud.director.v1_5.domain.Task; import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorClientLiveTest; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -42,22 +52,177 @@ public class AdminVdcClientLiveTest extends BaseVCloudDirectorClientLiveTest { * Convenience reference to API client. */ protected AdminVdcClient vdcClient; - + protected MetadataClient.Writeable metadataClient; + + protected URI adminVdcUri; + + private String metadataKey; + private String metadataValue; + @Override @BeforeClass(inheritGroups = true) public void setupRequiredClients() { vdcClient = context.getApi().getAdminVdcClient(); + metadataClient = vdcClient.getMetadataClient(); + assertNotNull(vdcURI, String.format(REF_REQ_LIVE, VDC)); + adminVdcUri = toAdminUri(vdcURI); + } + + @AfterClass(groups = { "live" }) + public void cleanUp() throws Exception { + if (metadataKey != null) { + try { + Task task = metadataClient.deleteMetadataEntry(adminVdcUri, metadataKey); + assertTaskSucceeds(task); + } catch (VCloudDirectorException e) { + logger.warn(e, "Error deleting metadata-value (perhaps it doesn't exist?); continuing..."); + } + } } @Test(testName = "GET /admin/vdc/{id}") - public void testGetNetwork() { - // required for testing - assertNotNull(vdcURI, String.format(REF_REQ_LIVE, VDC)); - - AdminVdc vdc = vdcClient.getVdc(toAdminUri(vdcURI)); + public void testGetVdc() { + AdminVdc vdc = vdcClient.getVdc(adminVdcUri); assertNotNull(vdc, String.format(OBJ_REQ_LIVE, VDC)); // parent type Checks.checkAdminVdc(vdc); } + + // TODO insufficient permissions to test + @Test(testName = "PUT /admin/vdc/{id}", enabled=false) + public void testEditVdc() throws Exception { + String origName = vdcClient.getVdc(adminVdcUri).getName(); + String newName = "a"+random.nextInt(Integer.MAX_VALUE); + Exception exception = null; + + AdminVdc vdc = AdminVdc.builder() + .name(newName) + .build(); + + try { + Task task = vdcClient.editVdc(adminVdcUri, vdc); + assertTaskSucceeds(task); + + AdminVdc modified = vdcClient.getVdc(adminVdcUri); + assertEquals(modified.getName(), newName); + + // parent type + Checks.checkAdminVdc(vdc); + } catch (Exception e) { + exception = e; + } finally { + try { + AdminVdc restorableVdc = AdminVdc.builder().name(origName).build(); + Task task = vdcClient.editVdc(adminVdcUri, restorableVdc); + assertTaskSucceeds(task); + } catch (Exception e) { + if (exception != null) { + logger.warn(e, "Error resetting adminVdc.name; rethrowing original test exception..."); + throw exception; + } else { + throw e; + } + } + } + } + + // TODO insufficient permissions to test + @Test(testName = "DELETE /admin/vdc/{id}", enabled=false) + public void testDeleteVdc() throws Exception { + // TODO Need to have a VDC that we're happy to delete! + Task task = vdcClient.deleteVdc(adminVdcUri); + assertTaskSucceeds(task); + + try { + vdcClient.getVdc(adminVdcUri); + } catch (VCloudDirectorException e) { + // success; unreachable because it has been deleted + } + } + + // TODO insufficient permissions to test + @Test(testName = "DISABLE/ENABLE /admin/vdc/{id}", enabled=false) + public void testDisableAndEnableVdc() throws Exception { + // TODO Need to have a VDC that we're happy to delete! + Exception exception = null; + + try { + vdcClient.disableVdc(adminVdcUri); + } catch (Exception e) { + exception = e; + } finally { + try { + vdcClient.enableVdc(adminVdcUri); + } catch (Exception e) { + if (exception != null) { + logger.warn(e, "Error resetting adminVdc.name; rethrowing original test exception..."); + throw exception; + } else { + throw e; + } + } + } + } + + @Test(testName = "PUT /admin/vdc/{id}/metadata") + public void testGetMetadata() throws Exception { + Metadata metadata = metadataClient.getMetadata(adminVdcUri); + + Checks.checkMetadata(metadata); + } + + // TODO insufficient permissions to test + @Test(testName = "PUT /admin/vdc/{id}/metadata", enabled=false) + public void testSetMetadata() throws Exception { + metadataKey = ""+random.nextInt(Integer.MAX_VALUE); + metadataValue = ""+random.nextInt(Integer.MAX_VALUE); + Metadata metadata = Metadata.builder() + .entry(MetadataEntry.builder().entry(metadataKey, metadataValue).build()) + .build(); + + Task task = metadataClient.mergeMetadata(adminVdcUri, metadata); + assertTaskSucceeds(task); + + MetadataValue modified = metadataClient.getMetadataValue(adminVdcUri, metadataKey); + Checks.checkMetadataValueFor("AdminVdc", modified, metadataValue); + Checks.checkMetadata(metadata); + } + + // TODO insufficient permissions to test + @Test(testName = "PUT /admin/vdc/{id}/metadata", dependsOnMethods = { "testSetMetadata" }, enabled=false) + public void testGetMetadataValue() throws Exception { + MetadataValue retrievedMetadataValue = metadataClient.getMetadataValue(adminVdcUri, metadataKey); + + Checks.checkMetadataValueFor("AdminVdc", retrievedMetadataValue, metadataValue); + } + + // TODO insufficient permissions to test + @Test(testName = "PUT /admin/vdc/{id}/metadata", dependsOnMethods = { "testGetMetadataValue" }, enabled=false ) + public void testSetMetadataValue() throws Exception { + metadataValue = ""+random.nextInt(Integer.MAX_VALUE); + MetadataValue newV = MetadataValue.builder().value(metadataValue).build(); + + Task task = metadataClient.setMetadata(adminVdcUri, metadataKey, newV); + assertTaskSucceeds(task); + + MetadataValue retrievedMetadataValue = metadataClient.getMetadataValue(adminVdcUri, metadataKey); + Checks.checkMetadataValueFor("AdminVdc", retrievedMetadataValue, metadataValue); + } + + // TODO insufficient permissions to test + @Test(testName = "PUT /admin/vdc/{id}/metadata", dependsOnMethods = { "testSetMetadataValue" }, enabled=false ) + public void testDeleteMetadataValue() throws Exception { + // TODO Remove dependency on other tests; make cleanUp delete a list of metadata entries? + + Task task = metadataClient.deleteMetadataEntry(adminVdcUri, metadataKey); + assertTaskSucceeds(task); + + try { + metadataClient.getMetadataValue(adminVdcUri, metadataKey); + fail("Retrieval of metadata value "+metadataKey+" should have fail after deletion"); + } catch (VCloudDirectorException e) { + // success; should not be accessible + } + } } diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/VAppTemplateClientLiveTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/VAppTemplateClientLiveTest.java index a21690cbc2..0568997603 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/VAppTemplateClientLiveTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/VAppTemplateClientLiveTest.java @@ -288,15 +288,34 @@ public class VAppTemplateClientLiveTest extends AbstractVAppClientLiveTest { assertEquals(modified.getComputerName(), computerName); } - @Test // FIXME deploymentLeaseInSeconds returned is null + @Test + public void testEditCustomizationSection() { + boolean oldVal = vAppTemplateClient.getVAppTemplateCustomizationSection(vAppTemplateURI).isCustomizeOnInstantiate(); + boolean newVal = !oldVal; + + CustomizationSection customizationSection = CustomizationSection.builder() + .info("my info") + .customizeOnInstantiate(newVal) + .build(); + + final Task task = vAppTemplateClient.editVAppTemplateCustomizationSection(vAppTemplateURI, customizationSection); + retryTaskSuccess.apply(task); + + CustomizationSection newCustomizationSection = vAppTemplateClient.getVAppTemplateCustomizationSection(vAppTemplateURI); + assertEquals(newCustomizationSection.isCustomizeOnInstantiate(), newVal); + } + + @Test public void testEditLeaseSettingsSection() throws Exception { + // FIXME deploymentLeaseInSeconds returned is null + //int deploymentLeaseInSeconds = random.nextInt(10000)+1; + // Note: use smallish number for storageLeaseInSeconds; it seems to be capped at 5184000? int storageLeaseInSeconds = random.nextInt(10000)+1; - int deploymentLeaseInSeconds = random.nextInt(10000)+1; LeaseSettingsSection leaseSettingSection = LeaseSettingsSection.builder() .info("my info") .storageLeaseInSeconds(storageLeaseInSeconds) - .deploymentLeaseInSeconds(deploymentLeaseInSeconds) + //.deploymentLeaseInSeconds(deploymentLeaseInSeconds) .build(); final Task task = vAppTemplateClient.editVappTemplateLeaseSettingsSection(vAppTemplateURI, leaseSettingSection); @@ -304,7 +323,7 @@ public class VAppTemplateClientLiveTest extends AbstractVAppClientLiveTest { LeaseSettingsSection newLeaseSettingsSection = vAppTemplateClient.getVappTemplateLeaseSettingsSection(vAppTemplateURI); assertEquals(newLeaseSettingsSection.getStorageLeaseInSeconds(), (Integer)storageLeaseInSeconds); - assertEquals(newLeaseSettingsSection.getDeploymentLeaseInSeconds(), (Integer)deploymentLeaseInSeconds); + //assertEquals(newLeaseSettingsSection.getDeploymentLeaseInSeconds(), (Integer)deploymentLeaseInSeconds); } @Test