diff --git a/sandbox-providers/tmrk-enterprisecloud/src/main/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineAsyncClient.java b/sandbox-providers/tmrk-enterprisecloud/src/main/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineAsyncClient.java index bc417fd072..ca10fc8846 100644 --- a/sandbox-providers/tmrk-enterprisecloud/src/main/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineAsyncClient.java +++ b/sandbox-providers/tmrk-enterprisecloud/src/main/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineAsyncClient.java @@ -134,4 +134,24 @@ public interface VirtualMachineAsyncClient { @JAXBResponseParser @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture shutdown(@EndpointParam URI uri); + +/** + * @see VirtualMachineClient#mountTools + */ + @POST + @Path("/tools/action/mount") + @Consumes("application/vnd.tmrk.cloud.task") + @JAXBResponseParser + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture mountTools(@EndpointParam URI uri); + +/** + * @see VirtualMachineClient#unmountTools + */ + @POST + @Path("/tools/action/unmount") + @Consumes("application/vnd.tmrk.cloud.task") + @JAXBResponseParser + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture unmountTools(@EndpointParam URI uri); } diff --git a/sandbox-providers/tmrk-enterprisecloud/src/main/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineClient.java b/sandbox-providers/tmrk-enterprisecloud/src/main/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineClient.java index a543c3056f..a1da7809d6 100644 --- a/sandbox-providers/tmrk-enterprisecloud/src/main/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineClient.java +++ b/sandbox-providers/tmrk-enterprisecloud/src/main/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineClient.java @@ -84,7 +84,7 @@ public interface VirtualMachineClient { /** * The Action Virtual Machines Power On call powers on a specified virtual machine. * If successful, the call returns the task that powered on the virtual machine. - * Note: To power on requires a value of false. + * Note: To power on requires a PoweredOn value of false. * @param uri the uri of the virtual machine * @return Task */ @@ -96,7 +96,7 @@ public interface VirtualMachineClient { * shutdown requests the virtual machine to end all processes and turn itself off * when all processes complete. * If successful, the call returns the task that powered off the virtual machine. - * Note: To power off requires a value of true. + * Note: To power off requires a PoweredOn value of true. * @param uri the uri of the virtual machine * @return Task */ @@ -105,7 +105,7 @@ public interface VirtualMachineClient { /** * The Action Virtual Machines Power Reboot call reboots a specified virtual machine. * If successful, the call returns the task that rebooted the virtual machine. - * Note: To reboot requires a value of Current or OutOfDate and a value of true. + * Note: To reboot requires a ToolsStatus value of Current or OutOfDate and a PoweredOn value of true. * @param uri the uri of the virtual machine * @return Task */ @@ -115,10 +115,30 @@ public interface VirtualMachineClient { * The Action Virtual Machines Power Shutdown call shuts down a specified virtual machine. * Shutdown requests the virtual machine to end all processes and turn itself off when all processes complete whereas power off simply terminates the virtual machine. * If successful, the call returns the task that shut down the virtual machine. - * Note: To shutdown requires a value of Current or OutOfDate and a value of true. + * Note: To shutdown requires a ToolsStatus value of Current or OutOfDate and a PoweredOn value of true. * @param uri the uri of the virtual machine * @return Task */ Task shutdown(URI uri); + /** + * The Action Virtual Machines Tools Mount call mounts the virtual volume + * for VMware Tools on a specified virtual machine. + * If successful, the call returns the task that mounted the tools. + * Note: To mount VMware Tools requires a PoweredOn value of true. + * @param uri the uri of the virtual machine + * @return Task + */ + Task mountTools(URI uri); + + /** + * The Action Virtual Machines Tools Unmount call unmounts the virtual volume for VMware Tools + * on a specified virtual machine. + * If successful, the call returns the task that unmounted the tools. + * Note: To unmount VMware Tools requires a PoweredOn value of true. + * @param uri the uri of the virtual machine + * @return Task + */ + Task unmountTools(URI uri); + } diff --git a/sandbox-providers/tmrk-enterprisecloud/src/test/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineAsyncClientTest.java b/sandbox-providers/tmrk-enterprisecloud/src/test/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineAsyncClientTest.java index 8eca645fe6..2b7dcf10a3 100644 --- a/sandbox-providers/tmrk-enterprisecloud/src/test/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineAsyncClientTest.java +++ b/sandbox-providers/tmrk-enterprisecloud/src/test/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineAsyncClientTest.java @@ -165,6 +165,34 @@ public class VirtualMachineAsyncClientTest extends BaseTerremarkEnterpriseCloudA checkFilters(httpRequest); } + public void testMountTools() throws SecurityException, NoSuchMethodException, IOException, URISyntaxException { + Method method = VirtualMachineAsyncClient.class.getMethod("mountTools", URI.class); + HttpRequest httpRequest = processor.createRequest(method,new URI("/cloudapi/ecloud/virtualmachines/5504")); + + assertRequestLineEquals(httpRequest, "POST https://services-beta.enterprisecloud.terremark.com/cloudapi/ecloud/virtualmachines/5504/tools/action/mount HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/vnd.tmrk.cloud.task\nx-tmrk-version: 2011-07-01\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseXMLWithJAXB.class); + assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class); + + checkFilters(httpRequest); + } + + public void testUnmountTools() throws SecurityException, NoSuchMethodException, IOException, URISyntaxException { + Method method = VirtualMachineAsyncClient.class.getMethod("unmountTools", URI.class); + HttpRequest httpRequest = processor.createRequest(method,new URI("/cloudapi/ecloud/virtualmachines/5504")); + + assertRequestLineEquals(httpRequest, "POST https://services-beta.enterprisecloud.terremark.com/cloudapi/ecloud/virtualmachines/5504/tools/action/unmount HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/vnd.tmrk.cloud.task\nx-tmrk-version: 2011-07-01\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseXMLWithJAXB.class); + assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class); + + checkFilters(httpRequest); + } + @Override protected TypeLiteral> createTypeLiteral() { return new TypeLiteral>() { diff --git a/sandbox-providers/tmrk-enterprisecloud/src/test/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineClientActionsLiveTest.java b/sandbox-providers/tmrk-enterprisecloud/src/test/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineClientActionsLiveTest.java index 35e036b6ff..f9740944fc 100644 --- a/sandbox-providers/tmrk-enterprisecloud/src/test/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineClientActionsLiveTest.java +++ b/sandbox-providers/tmrk-enterprisecloud/src/test/java/org/jclouds/tmrk/enterprisecloud/features/VirtualMachineClientActionsLiveTest.java @@ -21,6 +21,7 @@ package org.jclouds.tmrk.enterprisecloud.features; import com.google.common.base.Predicate; import org.jclouds.predicates.RetryablePredicate; import org.jclouds.tmrk.enterprisecloud.domain.Task; +import org.jclouds.tmrk.enterprisecloud.domain.software.ToolsStatus; import org.jclouds.tmrk.enterprisecloud.domain.vm.VirtualMachine; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; @@ -51,10 +52,10 @@ public class VirtualMachineClientActionsLiveTest extends BaseTerremarkEnterprise public void testPowerOn() throws Exception { vm = client.getVirtualMachine(new URI(vmURI)); assertFalse(vm.isPoweredOn()); - Task task = client.powerOn(vm.getHref()); + RetryablePredicate retryablePredicate = new RetryablePredicate(taskFinished(), 1000*60); - if (!retryablePredicate.apply(task)) { - fail("Did not manage to powerOn VM within timeout"); + if (!retryablePredicate.apply(client.powerOn(vm.getHref()))) { + fail("Did not manage to finish powerOn task"); } vm = client.getVirtualMachine(vm.getHref()); @@ -62,46 +63,84 @@ public class VirtualMachineClientActionsLiveTest extends BaseTerremarkEnterprise } @Test(dependsOnMethods = "testPowerOn") - public void testShutdown() { - //System.out.println("shutdown"); - //Needs tool status Current/OutOfDate - //check state - //shutdown - //wait until done - //power on + public void testMountTools() { + if (!mountTools(vm.getHref())) { + fail("Did not manage to finish mount tools task"); + } } - @Test(dependsOnMethods = "testShutdown") - public void testReboot() { - //System.out.println("reboot"); - //Needs tool status Current/OutOfDate - //check state - //reboot - //wait until done - } - - //@Test(dependsOnMethods = "testReboot") - @Test(dependsOnMethods = "testPowerOn") - public void testPowerOff() { - Task task = client.powerOff(vm.getHref()); + @Test(dependsOnMethods = "testMountTools") + public void testUnmountTools() { RetryablePredicate retryablePredicate = new RetryablePredicate(taskFinished(), 1000*60); - if (!retryablePredicate.apply(task)) { - fail("Did not manage to powerOff VM within timeout"); + if (!retryablePredicate.apply(client.unmountTools(vm.getHref()))) { + fail("Did not manage finish unmount tools task"); + } + //ToolsStatus remains in 'OutOfDate' after un-mounting. + //There is no way to tell, other than to try un-mounting again. + } + + @Test(dependsOnMethods = "testUnmountTools") + public void testShutdown() { + //Seems to work as ToolsStatus remains in OutOfDate state + RetryablePredicate retryablePredicate = new RetryablePredicate(taskFinished(), 1000*60); + if (!retryablePredicate.apply(client.shutdown(vm.getHref()))) { + fail("Did not manage to finish shutdown task"); + } + // Takes a while to powerOff + retryablePredicate = new RetryablePredicate(poweredOff(), 1000*60); + if (!retryablePredicate.apply(vm.getHref())) { + fail("Did not manage to powerOff after shutdown"); } vm = client.getVirtualMachine(vm.getHref()); assertFalse(vm.isPoweredOn()); } + @Test(dependsOnMethods = "testShutdown") + public void testReboot() { + RetryablePredicate retryablePredicate = new RetryablePredicate(taskFinished(), 1000*60); + if (!retryablePredicate.apply(client.powerOn(vm.getHref()))) { + fail("Did not manage to finish powerOn task"); + } + + if (!mountTools(vm.getHref())) { + fail("Did not manage to mount tools"); + } + + retryablePredicate = new RetryablePredicate(taskFinished(), 1000*60); + if (!retryablePredicate.apply(client.reboot(vm.getHref()))) { + fail("Did not manage to finish reboot task"); + } + + vm = client.getVirtualMachine(vm.getHref()); + assertTrue(vm.isPoweredOn()); + } + + @Test(dependsOnMethods = "testReboot") + public void testPowerOff() { + RetryablePredicate retryablePredicate = new RetryablePredicate(taskFinished(), 1000*60); + if (!retryablePredicate.apply(client.powerOff(vm.getHref()))) { + fail("Did not manage to finish powerOff task"); + } + + vm = client.getVirtualMachine(vm.getHref()); + assertFalse(vm.isPoweredOn()); + } + + private boolean mountTools(URI uri) { + // Wait for task to finish AND tools to get into currentOrOutOfDate state + return new RetryablePredicate(taskFinished(), 1000*60).apply(client.mountTools(uri)) && + new RetryablePredicate(toolsCurrentOrOutOfDate(), 1000*60).apply(uri); + } + // Probably generally useful private Predicate taskFinished() { return new Predicate() { @Override - public boolean apply(@Nullable Task task) { + public boolean apply(Task task) { TaskClient taskClient = context.getApi().getTaskClient(); task = taskClient.getTask(task.getHref()); - Task.Status status = task.getStatus(); - switch(status) { + switch(task.getStatus()) { case QUEUED: case RUNNING: return false; @@ -109,10 +148,40 @@ public class VirtualMachineClientActionsLiveTest extends BaseTerremarkEnterprise case SUCCESS: return true; default: - throw new RuntimeException("Task Failed:"+task.getHref()+", Status:"+status); + throw new RuntimeException("Task Failed:"+task.getHref()+", Status:"+task.getStatus()); } } }; } + // Probably generally useful + private Predicate toolsCurrentOrOutOfDate() { + return new Predicate() { + @Override + public boolean apply(URI uri) { + VirtualMachine virtualMachine = client.getVirtualMachine(uri); + ToolsStatus toolsStatus = virtualMachine.getToolsStatus(); + switch(toolsStatus) { + case NOT_INSTALLED: + case NOT_RUNNING: + return false; + case CURRENT: + case OUT_OF_DATE: + return true; + default: + throw new RuntimeException("Unable to determine toolsStatus for:"+uri+", ToolsStatus:"+toolsStatus); + } + } + }; + } + + private Predicate poweredOff() { + return new Predicate() { + @Override + public boolean apply(URI uri) { + VirtualMachine virtualMachine = client.getVirtualMachine(uri); + return !virtualMachine.isPoweredOn(); + } + }; + } }