From 17fa631e8f8d4c6555f4db99e74b923c66b3a115 Mon Sep 17 00:00:00 2001 From: Michael Wilson Date: Wed, 16 Dec 2015 17:16:39 -0500 Subject: [PATCH] JCLOUDS-1001: Adding preemptible support to the Google Compute provider 1.9.x backport of https://github.com/jclouds/jclouds/commit/962980cd9d22fc2e7b54cab45a4d17550d1fb137 --- .../compute/GoogleComputeEngineServiceAdapter.java | 22 ++++++++++++++++++--- .../GoogleComputeEngineTemplateOptions.java | 17 ++++++++++++++++ .../googlecomputeengine/domain/Instance.java | 8 +++++--- .../googlecomputeengine/domain/NewInstance.java | 6 +++++- .../googlecomputeengine/features/InstanceApi.java | 23 ++++++++++++++++++++++ .../GoogleComputeEngineServiceLiveTest.java | 5 +++-- .../features/InstanceApiLiveTest.java | 4 +++- .../features/InstanceApiMockTest.java | 10 ++++++++++ .../parse/ParseInstanceTest.java | 2 +- .../src/test/resources/instance_get.json | 3 ++- .../src/test/resources/instance_insert_2.json | 5 +++++ .../src/test/resources/instance_insert_ssd.json | 5 +++++ .../src/test/resources/instance_list.json | 3 ++- 13 files changed, 100 insertions(+), 13 deletions(-) diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java index 653388e..ee50d92 100644 --- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java +++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java @@ -119,12 +119,15 @@ List disks = Lists.newArrayList(); disks.add(AttachDisk.newBootDisk(template.getImage().getUri(), getDiskTypeArgument(options, zone))); + Scheduling scheduling = getScheduling(options); + NewInstance newInstance = NewInstance.create( name, // name template.getHardware().getUri(), // machineType options.network(), // network disks, // disks - group // description + group, // description + scheduling ); // Add tags from template and for security groups @@ -163,8 +166,8 @@ null, // disks newInstance.metadata(), // metadata null, // serviceAccounts - Scheduling.create(OnHostMaintenance.MIGRATE, true) // scheduling - )); + scheduling) // scheduling + ); checkState(instanceVisible.apply(instance), "instance %s is not api visible!", instance.get()); // Add lookup for InstanceToNodeMetadata @@ -300,4 +303,17 @@ private URI getDiskTypeArgument(GoogleComputeEngineTemplateOptions options, Stri return null; } + + public Scheduling getScheduling(GoogleComputeEngineTemplateOptions options) { + OnHostMaintenance onHostMaintenance = OnHostMaintenance.MIGRATE; + boolean automaticRestart = true; + + // Preemptible instances cannot use a MIGRATE maintenance strategy or automatic restarts + if (options.preemptible()) { + onHostMaintenance = OnHostMaintenance.TERMINATE; + automaticRestart = false; + } + + return Scheduling.create(onHostMaintenance, automaticRestart, options.preemptible()); + } } diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java index 666454a..7b4350e 100644 --- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java +++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java @@ -30,6 +30,7 @@ private URI network = null; private boolean autoCreateKeyPair = true; private String bootDiskType; + private boolean preemptible = false; @Override public GoogleComputeEngineTemplateOptions clone() { @@ -46,6 +47,7 @@ public void copyTo(TemplateOptions to) { eTo.network(network()); eTo.autoCreateKeyPair(autoCreateKeyPair()); eTo.bootDiskType(bootDiskType()); + eTo.preemptible(preemptible()); } } @@ -76,6 +78,21 @@ public String bootDiskType() { } /** + * Sets whether the resulting instance should be preemptible. + */ + public GoogleComputeEngineTemplateOptions preemptible(boolean preemptible) { + this.preemptible = preemptible; + return this; + } + + /** + * Gets whether the resulting instance should be preemptible. + */ + public boolean preemptible() { + return preemptible; + } + + /** * Sets whether an SSH key pair should be created automatically. */ public GoogleComputeEngineTemplateOptions autoCreateKeyPair(boolean autoCreateKeyPair) { diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Instance.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Instance.java index dcbc344..71176d8 100644 --- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Instance.java +++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Instance.java @@ -186,16 +186,18 @@ public static ServiceAccount create(String email, List scopes) { * If you would like your instance to be restarted, set the automaticRestart flag to true. * Your instance may be restarted more than once, and it may be restarted outside the window * of maintenance events. + * If you would like your instance to be preemptible, set the preemptible flag to true. */ TERMINATE } public abstract OnHostMaintenance onHostMaintenance(); public abstract boolean automaticRestart(); + public abstract boolean preemptible(); - @SerializedNames({ "onHostMaintenance", "automaticRestart" }) - public static Scheduling create(OnHostMaintenance onHostMaintenance, boolean automaticRestart) { - return new AutoValue_Instance_Scheduling(onHostMaintenance, automaticRestart); + @SerializedNames({ "onHostMaintenance", "automaticRestart", "preemptible" }) + public static Scheduling create(OnHostMaintenance onHostMaintenance, boolean automaticRestart, boolean preemptible) { + return new AutoValue_Instance_Scheduling(onHostMaintenance, automaticRestart, preemptible); } Scheduling() { diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java index 57b22a8..3d3aa0f 100644 --- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java +++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java @@ -81,6 +81,10 @@ public static NewInstance create(String name, URI machineType, URI network, URI } public static NewInstance create(String name, URI machineType, URI network, List disks, String description) { + return create(name, machineType, network, disks, description, null); + } + + public static NewInstance create(String name, URI machineType, URI network, List disks, String description, Scheduling scheduling) { checkArgument(disks.get(0).boot(), "disk 0 must be a boot disk! %s", disks); boolean foundBoot = false; for (AttachDisk disk : disks) { @@ -90,7 +94,7 @@ public static NewInstance create(String name, URI machineType, URI network, List } } return create(name, machineType, null, ImmutableList.of(NetworkInterface.create(network)), ImmutableList.copyOf(disks), - description, Tags.create(), Metadata.create(), null, null); + description, Tags.create(), Metadata.create(), null, scheduling); } @SerializedNames({ "name", "machineType", "canIpForward", "networkInterfaces", "disks", "description", "tags", "metadata", diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java index 5405de2..43d708a 100644 --- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java +++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java @@ -237,6 +237,7 @@ Operation setDiskAutoDelete(@PathParam("instance") String instanceName, * Sets an instance's scheduling options. * @see * + * @deprecated See {@link #setScheduling(String, org.jclouds.googlecomputeengine.domain.Instance.Scheduling.OnHostMaintenance, boolean, boolean)}. Will be removed in 2.0 * @param instanceName The name of the instance * @param onHostMaintenance either MIGRATE or TERMINATE the default is MIGRATE (Live Migration). * @param automaticRestart Defines whether the Instance should be automatically @@ -244,6 +245,7 @@ Operation setDiskAutoDelete(@PathParam("instance") String instanceName, * Used when onHostMaintenance is set to TERMINATE. * @return */ + @Deprecated @Named("Instances:setScheduling") @POST @Path("/{instance}/setScheduling") @@ -253,6 +255,27 @@ Operation setScheduling(@PathParam("instance") String instanceName, @PayloadParam("automaticRestart") boolean automaticRestart); /** + * Sets an instance's scheduling options. + * @see + * + * @param instanceName The name of the instance + * @param onHostMaintenance either MIGRATE or TERMINATE the default is MIGRATE (Live Migration). + * @param automaticRestart Defines whether the Instance should be automatically + * restarted when it is terminated by Compute Engine (not terminated by user). + * Used when onHostMaintenance is set to TERMINATE. + * @param preemptible Defines whether the Instance should be launched as spot instance + * @return + */ + @Named("Instances:setScheduling") + @POST + @Path("/{instance}/setScheduling") + @MapBinder(BindToJsonPayload.class) + Operation setScheduling(@PathParam("instance") String instanceName, + @PayloadParam("onHostMaintenance") Scheduling.OnHostMaintenance onHostMaintenance, + @PayloadParam("automaticRestart") boolean automaticRestart, + @PayloadParam("preemptible") boolean preemptible); + + /** * This method starts an instance that was stopped using the using the {@link #stop(String)} method. * @param instance - name of the instance to be started */ diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceLiveTest.java index b4ee392..550cb5c 100644 --- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceLiveTest.java +++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceLiveTest.java @@ -74,12 +74,12 @@ public void testListHardwareProfiles() throws Exception { } } - public void testCreateNodeWithSsd() throws Exception { + public void testCreatePreemptibleNodeWithSsd() throws Exception { String group = this.group + "ssd"; try { TemplateOptions options = client.templateOptions(); - options.as(GoogleComputeEngineTemplateOptions.class).bootDiskType("pd-ssd"); + options.as(GoogleComputeEngineTemplateOptions.class).bootDiskType("pd-ssd").preemptible(true); // create a node Set nodes = @@ -92,6 +92,7 @@ public void testCreateNodeWithSsd() throws Exception { Instance instance = api.instancesInZone(node.getLocation().getId()).get(node.getName()); Disk disk = api.disksInZone(node.getLocation().getId()).get(toName(instance.disks().get(0).source())); assertTrue(disk.type().toString().endsWith("pd-ssd")); + assertTrue(instance.scheduling().preemptible()); } finally { client.destroyNodesMatching(NodePredicates.inGroup(group)); diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java index 4c74a3d..a61d196 100644 --- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java +++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java @@ -185,12 +185,14 @@ public void testSetDiskAutoDelete() { public void testSetScheduling() { Instance instance = api().get(INSTANCE_NAME); assertEquals(instance.scheduling().automaticRestart(), true); + assertEquals(instance.scheduling().preemptible(), false); assertEquals(instance.scheduling().onHostMaintenance(), Scheduling.OnHostMaintenance.MIGRATE); - assertOperationDoneSuccessfully(api().setScheduling(INSTANCE_NAME, Scheduling.OnHostMaintenance.TERMINATE, false)); + assertOperationDoneSuccessfully(api().setScheduling(INSTANCE_NAME, Scheduling.OnHostMaintenance.TERMINATE, false, false)); Instance instanceAltered = api().get(INSTANCE_NAME); assertEquals(instanceAltered.scheduling().automaticRestart(), false); + assertEquals(instanceAltered.scheduling().preemptible(), false); assertEquals(instanceAltered.scheduling().onHostMaintenance(), Scheduling.OnHostMaintenance.TERMINATE); } diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiMockTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiMockTest.java index 067dada..1bc3821 100644 --- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiMockTest.java +++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiMockTest.java @@ -231,6 +231,16 @@ public void setScheduling() throws Exception { "{\"onHostMaintenance\": \"TERMINATE\",\"automaticRestart\": true}"); } + public void setScheduling_preemtible() throws Exception { + server.enqueue(jsonResponse("/zone_operation.json")); + + assertEquals(instanceApi().setScheduling("test-1", OnHostMaintenance.TERMINATE, true, false), + new ParseZoneOperationTest().expected(url("/projects"))); + + assertSent(server, "POST", "/projects/party/zones/us-central1-a/instances/test-1/setScheduling", + "{\"onHostMaintenance\": \"TERMINATE\",\"automaticRestart\": true,\"preemptible\": false}"); + } + public void start_test() throws Exception { server.enqueue(jsonResponse("/zone_operation.json")); diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceTest.java index bf699cf..8671b52 100644 --- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceTest.java +++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceTest.java @@ -89,7 +89,7 @@ public Instance expected(String baseUrl) { .put("jclouds-image", baseUrl + "/debian-cloud/global/images/debian-7-wheezy-v20140718") .put("jclouds-delete-boot-disk", "true"), // metadata ImmutableList.of(ServiceAccount.create("default", ImmutableList.of("myscope"))), // serviceAccounts - Instance.Scheduling.create(OnHostMaintenance.MIGRATE, false) // scheduling + Instance.Scheduling.create(OnHostMaintenance.MIGRATE, false, false) // scheduling ); } } diff --git a/google-compute-engine/src/test/resources/instance_get.json b/google-compute-engine/src/test/resources/instance_get.json index b2795b6..788450b 100644 --- a/google-compute-engine/src/test/resources/instance_get.json +++ b/google-compute-engine/src/test/resources/instance_get.json @@ -73,6 +73,7 @@ }, "scheduling": { "onHostMaintenance": "MIGRATE", - "automaticRestart": false + "automaticRestart": false, + "preemptible": false } } diff --git a/google-compute-engine/src/test/resources/instance_insert_2.json b/google-compute-engine/src/test/resources/instance_insert_2.json index 78002a6..0310aba 100644 --- a/google-compute-engine/src/test/resources/instance_insert_2.json +++ b/google-compute-engine/src/test/resources/instance_insert_2.json @@ -35,5 +35,10 @@ "value": "test" } ] + }, + "scheduling": { + "onHostMaintenance": "MIGRATE", + "automaticRestart": true, + "preemptible": false } } \ No newline at end of file diff --git a/google-compute-engine/src/test/resources/instance_insert_ssd.json b/google-compute-engine/src/test/resources/instance_insert_ssd.json index 797aa4a..b6d6b7b 100644 --- a/google-compute-engine/src/test/resources/instance_insert_ssd.json +++ b/google-compute-engine/src/test/resources/instance_insert_ssd.json @@ -36,5 +36,10 @@ "value": "test" } ] + }, + "scheduling": { + "onHostMaintenance": "MIGRATE", + "automaticRestart": true, + "preemptible": false } } \ No newline at end of file diff --git a/google-compute-engine/src/test/resources/instance_list.json b/google-compute-engine/src/test/resources/instance_list.json index ee31a1a..ef60ead 100644 --- a/google-compute-engine/src/test/resources/instance_list.json +++ b/google-compute-engine/src/test/resources/instance_list.json @@ -78,7 +78,8 @@ }, "scheduling": { "onHostMaintenance": "MIGRATE", - "automaticRestart": false + "automaticRestart": false, + "preemptible": false } } ]