Skip to content

Commit 54c352d

Browse files
docs(samples): Adding samples for Spot VMs (#285)
* docs(samples): Adding samples for Spot VMs * Fixing tests perhaps * Update samples/snippets/instances/spot/__init__.py Co-authored-by: Leah E. Cole <[email protected]> * Update samples/recipes/instances/spot/__init__.py Co-authored-by: Leah E. Cole <[email protected]> Co-authored-by: Leah E. Cole <[email protected]>
1 parent 4ec8432 commit 54c352d

30 files changed

+832
-71
lines changed

compute/compute/ingredients/instances/create_instance.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import re
2121
from typing import List
22+
import warnings
2223

2324
from google.cloud import compute_v1
2425

@@ -37,6 +38,8 @@ def create_instance(
3738
external_ipv4: str = None,
3839
accelerators: List[compute_v1.AcceleratorConfig] = None,
3940
preemptible: bool = False,
41+
spot: bool = False,
42+
instance_termination_action: str = "STOP",
4043
custom_hostname: str = None,
4144
delete_protection: bool = False,
4245
) -> compute_v1.Instance:
@@ -69,7 +72,10 @@ def create_instance(
6972
accelerators: a list of AcceleratorConfig objects describing the accelerators that will
7073
be attached to the new instance.
7174
preemptible: boolean value indicating if the new instance should be preemptible
72-
or not.
75+
or not. Preemptible VMs have been deprecated and you should now use Spot VMs.
76+
spot: boolean value indicating if the new instance should be a Spot VM or not.
77+
instance_termination_action: What action should be taken once a Spot VM is terminated.
78+
Possible values: "STOP", "DELETE"
7379
custom_hostname: Custom hostname of the new VM instance.
7480
Custom hostnames must conform to RFC 1035 requirements for valid hostnames.
7581
delete_protection: boolean value indicating if the new virtual machine should be
@@ -97,8 +103,10 @@ def create_instance(
97103
access.nat_i_p = external_ipv4
98104
network_interface.access_configs = [access]
99105

106+
100107
# Collect information into the Instance object.
101108
instance = compute_v1.Instance()
109+
instance.network_interfaces = [network_interface]
102110
instance.name = instance_name
103111
instance.disks = disks
104112
if re.match(r"^zones/[a-z\d\-]+/machineTypes/[a-z\d\-]+$", machine_type):
@@ -109,13 +117,18 @@ def create_instance(
109117
if accelerators:
110118
instance.guest_accelerators = accelerators
111119

112-
instance.network_interfaces = [network_interface]
113-
114120
if preemptible:
115121
# Set the preemptible setting
122+
warnings.warn("Preemptible VMs are being replaced by Spot VMs.", DeprecationWarning)
116123
instance.scheduling = compute_v1.Scheduling()
117124
instance.scheduling.preemptible = True
118125

126+
if spot:
127+
# Set the Spot VM setting
128+
instance.scheduling = compute_v1.Scheduling()
129+
instance.scheduling.provisioning_model = compute_v1.Scheduling.ProvisioningModel.SPOT.name
130+
instance.scheduling.instance_termination_action = instance_termination_action
131+
119132
if custom_hostname is not None:
120133
# Set the custom hostname for the instance
121134
instance.hostname = custom_hostname

compute/compute/ingredients/instances/create_instance_from_template_with_overrides.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def create_instance_from_template_with_overrides(
7272
instance = compute_v1.Instance()
7373
instance.name = instance_name
7474
instance.machine_type = machine_type
75-
instance.disks = instance_template.properties.disks
75+
instance.disks = list(instance_template.properties.disks)
7676

7777
new_disk = compute_v1.AttachedDisk()
7878
new_disk.initialize_params.disk_size_gb = 50

compute/compute/ingredients/instances/preemptible/create.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
# This is an ingredient file. It is not meant to be run directly. Check the samples/snippets
16-
# folder for complete code samples that are ready to be used.
17-
# Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check.
18-
# flake8: noqa
19-
#
20-
# Licensed under the Apache License, Version 2.0 (the "License");
21-
# you may not use this file except in compliance with the License.
22-
# You may obtain a copy of the License at
23-
#
24-
# http://www.apache.org/licenses/LICENSE-2.0
25-
#
26-
# Unless required by applicable law or agreed to in writing, software
27-
# distributed under the License is distributed on an "AS IS" BASIS,
28-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29-
# See the License for the specific language governing permissions and
30-
# limitations under the License.
31-
3215
# This is an ingredient file. It is not meant to be run directly. Check the samples/snippets
3316
# folder for complete code samples that are ready to be used.
3417
# Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# This is an ingredient file. It is not meant to be run directly. Check the samples/snippets
16+
# folder for complete code samples that are ready to be used.
17+
# Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check.
18+
# flake8: noqa
19+
20+
from google.cloud import compute_v1
21+
22+
23+
# <INGREDIENT create_spot_instance>
24+
def create_spot_instance(project_id: str, zone: str, instance_name: str) -> compute_v1.Instance:
25+
"""
26+
Create a new Spot VM instance with Debian 10 operating system.
27+
28+
Args:
29+
project_id: project ID or project number of the Cloud project you want to use.
30+
zone: name of the zone to create the instance in. For example: "us-west3-b"
31+
instance_name: name of the new virtual machine (VM) instance.
32+
33+
Returns:
34+
Instance object.
35+
"""
36+
newest_debian = get_image_from_family(
37+
project="debian-cloud", family="debian-11"
38+
)
39+
disk_type = f"zones/{zone}/diskTypes/pd-standard"
40+
disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)]
41+
instance = create_instance(project_id, zone, instance_name, disks, spot=True)
42+
return instance
43+
# </INGREDIENT>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# This is an ingredient file. It is not meant to be run directly. Check the samples/snippets
16+
# folder for complete code samples that are ready to be used.
17+
# Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check.
18+
# flake8: noqa
19+
from google.cloud import compute_v1
20+
21+
22+
# <INGREDIENT is_spot_vm>
23+
def is_spot_vm(project_id: str, zone: str, instance_name: str) -> bool:
24+
"""
25+
Check if a given instance is Spot VM or not.
26+
Args:
27+
project_id: project ID or project number of the Cloud project you want to use.
28+
zone: name of the zone you want to use. For example: "us-west3-b"
29+
instance_name: name of the virtual machine to check.
30+
Returns:
31+
The Spot VM status of the instance.
32+
"""
33+
instance_client = compute_v1.InstancesClient()
34+
instance = instance_client.get(
35+
project=project_id, zone=zone, instance=instance_name
36+
)
37+
return instance.scheduling.provisioning_model == compute_v1.Scheduling.ProvisioningModel.SPOT.name
38+
# </INGREDIENT>
39+

compute/compute/recipes/instances/spot/__init__.py

Whitespace-only changes.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# flake8: noqa
15+
16+
# <REGION compute_spot_create>
17+
# <IMPORTS/>
18+
19+
# <INGREDIENT get_image_from_family />
20+
21+
22+
# <INGREDIENT disk_from_image />
23+
24+
# <INGREDIENT wait_for_extended_operation />
25+
26+
27+
# <INGREDIENT create_instance />
28+
29+
30+
# <INGREDIENT create_spot_instance />
31+
# </REGION compute_spot_create>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# flake8: noqa
15+
16+
# <REGION compute_spot_check>
17+
# <IMPORTS/>
18+
19+
# <INGREDIENT is_spot_vm />
20+
21+
# </REGION compute_spot_check>

compute/compute/snippets/instances/create.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import re
2424
import sys
2525
from typing import Any, List
26+
import warnings
2627

2728
from google.api_core.extended_operation import ExtendedOperation
2829
from google.cloud import compute_v1
@@ -143,6 +144,8 @@ def create_instance(
143144
external_ipv4: str = None,
144145
accelerators: List[compute_v1.AcceleratorConfig] = None,
145146
preemptible: bool = False,
147+
spot: bool = False,
148+
instance_termination_action: str = "STOP",
146149
custom_hostname: str = None,
147150
delete_protection: bool = False,
148151
) -> compute_v1.Instance:
@@ -175,7 +178,10 @@ def create_instance(
175178
accelerators: a list of AcceleratorConfig objects describing the accelerators that will
176179
be attached to the new instance.
177180
preemptible: boolean value indicating if the new instance should be preemptible
178-
or not.
181+
or not. Preemptible VMs have been deprecated and you should now use Spot VMs.
182+
spot: boolean value indicating if the new instance should be a Spot VM or not.
183+
instance_termination_action: What action should be taken once a Spot VM is terminated.
184+
Possible values: "STOP", "DELETE"
179185
custom_hostname: Custom hostname of the new VM instance.
180186
Custom hostnames must conform to RFC 1035 requirements for valid hostnames.
181187
delete_protection: boolean value indicating if the new virtual machine should be
@@ -205,6 +211,7 @@ def create_instance(
205211

206212
# Collect information into the Instance object.
207213
instance = compute_v1.Instance()
214+
instance.network_interfaces = [network_interface]
208215
instance.name = instance_name
209216
instance.disks = disks
210217
if re.match(r"^zones/[a-z\d\-]+/machineTypes/[a-z\d\-]+$", machine_type):
@@ -215,13 +222,22 @@ def create_instance(
215222
if accelerators:
216223
instance.guest_accelerators = accelerators
217224

218-
instance.network_interfaces = [network_interface]
219-
220225
if preemptible:
221226
# Set the preemptible setting
227+
warnings.warn(
228+
"Preemptible VMs are being replaced by Spot VMs.", DeprecationWarning
229+
)
222230
instance.scheduling = compute_v1.Scheduling()
223231
instance.scheduling.preemptible = True
224232

233+
if spot:
234+
# Set the Spot VM setting
235+
instance.scheduling = compute_v1.Scheduling()
236+
instance.scheduling.provisioning_model = (
237+
compute_v1.Scheduling.ProvisioningModel.SPOT.name
238+
)
239+
instance.scheduling.instance_termination_action = instance_termination_action
240+
225241
if custom_hostname is not None:
226242
# Set the custom hostname for the instance
227243
instance.hostname = custom_hostname

compute/compute/snippets/instances/create_start_instance/create_from_custom_image.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import re
2424
import sys
2525
from typing import Any, List
26+
import warnings
2627

2728
from google.api_core.extended_operation import ExtendedOperation
2829
from google.cloud import compute_v1
@@ -143,6 +144,8 @@ def create_instance(
143144
external_ipv4: str = None,
144145
accelerators: List[compute_v1.AcceleratorConfig] = None,
145146
preemptible: bool = False,
147+
spot: bool = False,
148+
instance_termination_action: str = "STOP",
146149
custom_hostname: str = None,
147150
delete_protection: bool = False,
148151
) -> compute_v1.Instance:
@@ -175,7 +178,10 @@ def create_instance(
175178
accelerators: a list of AcceleratorConfig objects describing the accelerators that will
176179
be attached to the new instance.
177180
preemptible: boolean value indicating if the new instance should be preemptible
178-
or not.
181+
or not. Preemptible VMs have been deprecated and you should now use Spot VMs.
182+
spot: boolean value indicating if the new instance should be a Spot VM or not.
183+
instance_termination_action: What action should be taken once a Spot VM is terminated.
184+
Possible values: "STOP", "DELETE"
179185
custom_hostname: Custom hostname of the new VM instance.
180186
Custom hostnames must conform to RFC 1035 requirements for valid hostnames.
181187
delete_protection: boolean value indicating if the new virtual machine should be
@@ -205,6 +211,7 @@ def create_instance(
205211

206212
# Collect information into the Instance object.
207213
instance = compute_v1.Instance()
214+
instance.network_interfaces = [network_interface]
208215
instance.name = instance_name
209216
instance.disks = disks
210217
if re.match(r"^zones/[a-z\d\-]+/machineTypes/[a-z\d\-]+$", machine_type):
@@ -215,13 +222,22 @@ def create_instance(
215222
if accelerators:
216223
instance.guest_accelerators = accelerators
217224

218-
instance.network_interfaces = [network_interface]
219-
220225
if preemptible:
221226
# Set the preemptible setting
227+
warnings.warn(
228+
"Preemptible VMs are being replaced by Spot VMs.", DeprecationWarning
229+
)
222230
instance.scheduling = compute_v1.Scheduling()
223231
instance.scheduling.preemptible = True
224232

233+
if spot:
234+
# Set the Spot VM setting
235+
instance.scheduling = compute_v1.Scheduling()
236+
instance.scheduling.provisioning_model = (
237+
compute_v1.Scheduling.ProvisioningModel.SPOT.name
238+
)
239+
instance.scheduling.instance_termination_action = instance_termination_action
240+
225241
if custom_hostname is not None:
226242
# Set the custom hostname for the instance
227243
instance.hostname = custom_hostname

0 commit comments

Comments
 (0)