Skip to content

Commit cfe4774

Browse files
Add desired state to workbench instances. (#9945) (#17270)
* add labels to runtime update test * Add desired_state for workbench instances * fix(tgc): Fixing the if block for existingConverterAsset and add test case (#9914) * Add sweepers for vertex_dataset, vertex_tensorboard and vertex_metadataStore (#9911) * Make acctest use bootstrapped KMS key, instead of making new key that resembles a shared key (#9926) * Refactor the TeamCity config to define all projects, across GA, Beta, and VCR testing (#9837) * Replace contents of .teamcity/ with new refactored config files * Remove remaining automation for generating service lists automatically * Remove copyright headers, as they're added during generation process * Update header comments on .teamcity files * Make VCR testing compatible with TeamCity agent * Update GA + Beta service lists to match the currrent provider * Fix whitespace * Update default TEST ENV value for VCR builds * Add chmod commands to handling of creds file * Update pre- and post-VCR steps to echo out more information about their actions * Rename `generated` folder to `inputs` * Update header comments on .teamcity files * Refactor how VCR recording buid configurations are made * Fix comment on MM VCR build * Update VCR post step to fail if no cassettes are produced by the tests before * Whitespace changes * Fix how teamcity files are copied to the downstreams * Change how VCR build configs are named * remove newlines * Fix defect in post VCR build steps * Refactor labelling that indicates automated vs ad hoc builds * Make VCR builds be triggered to indicate VCR_MODE * Add first version of TeamCity documentation! * Add contents section to PERFORMING_TASKS_IN_TEAMCITY.md * Move details about DSL into technical README, away from process doc * Make the .teamcity folder only propogate to the TPG repo, and no longer be in the TPGB repo * Ensure all TeamCity files are being copied to the downstream repo * Move echo command to after `BRANCH_NAME` ENV declared * Update VCR steps to look for fixtures files inside beta folder * Update mmv1/third_party/terraform/.teamcity/components/builds/vcr_build_steps.kt * Update mmv1/third_party/terraform/.teamcity/CONTRIBUTION_GUIDE.md --------- * [#15779] Add google_network_security_firewall_endpoint resource (#9813) * [#15779] Add google_network_security_firewall_endpoint resource * Fix yaml linting * Removing unused fields from yaml * Fixing tests * Fixes per comments --------- * enhancement: Allow overriding the Billing Project for google_cloud_asset_resources_search_all (#9935) * enhancement: Allow overriding the Billing Project for cloud_asset_resources_search_all * chore: Fixed indentation * Add firebaseappcheck to service package lists (#9937) * Enable CRONs in TeamCity (#9938) * Set CRONs for 4am UTC * Enable CRONs * Update enrolled_teams.yml (#9939) * add NickElliot to vacation reviewers (#9942) * Update membership.go * Update membership.go * fix lint issues * fix conversion compilation * Remove Runtime example * Add back kms flatten * change encryption to CMEK to test for KMS * Try using a global KMS key * kms key location to us-central1 * remove service account in full example * Adding back service account into full test --------- [upstream:1d3073d06c8e650a1afd7de552bbf457ea2a972f] Signed-off-by: Modular Magician <[email protected]>
1 parent 6015012 commit cfe4774

File tree

5 files changed

+170
-71
lines changed

5 files changed

+170
-71
lines changed

.changelog/9945.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
workbench: added `desired_state` field to `google_workbench_instance` resource
3+
```

google/services/workbench/resource_workbench_instance.go

+91-59
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,43 @@ func waitForWorkbenchInstanceActive(d *schema.ResourceData, config *transport_tp
173173
})
174174
}
175175

176+
func modifyWorkbenchInstanceState(config *transport_tpg.Config, d *schema.ResourceData, project string, billingProject string, userAgent string, state string) (map[string]interface{}, error) {
177+
url, err := tpgresource.ReplaceVars(d, config, "{{WorkbenchBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:"+state)
178+
if err != nil {
179+
return nil, err
180+
}
181+
182+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
183+
Config: config,
184+
Method: "POST",
185+
Project: billingProject,
186+
RawURL: url,
187+
UserAgent: userAgent,
188+
})
189+
if err != nil {
190+
return nil, fmt.Errorf("Unable to %q google_workbench_instance %q: %s", state, d.Id(), err)
191+
}
192+
return res, nil
193+
}
194+
195+
func WorkbenchInstanceKmsDiffSuppress(_, old, new string, _ *schema.ResourceData) bool {
196+
if strings.HasPrefix(old, new) {
197+
return true
198+
}
199+
return false
200+
}
201+
202+
func waitForWorkbenchOperation(config *transport_tpg.Config, d *schema.ResourceData, project string, billingProject string, userAgent string, response map[string]interface{}) error {
203+
var opRes map[string]interface{}
204+
err := WorkbenchOperationWaitTimeWithResponse(
205+
config, response, &opRes, project, "Modifying Workbench Instance state", userAgent,
206+
d.Timeout(schema.TimeoutUpdate))
207+
if err != nil {
208+
return err
209+
}
210+
return nil
211+
}
212+
176213
func ResourceWorkbenchInstance() *schema.Resource {
177214
return &schema.Resource{
178215
Create: resourceWorkbenchInstanceCreate,
@@ -280,10 +317,11 @@ recommended value of 150GB.`,
280317
Description: `Optional. Indicates the type of the disk. Possible values: ["PD_STANDARD", "PD_SSD", "PD_BALANCED", "PD_EXTREME"]`,
281318
},
282319
"kms_key": {
283-
Type: schema.TypeString,
284-
Optional: true,
285-
ForceNew: true,
286-
Description: `'Optional. Input only. The KMS key used to encrypt the disks, only
320+
Type: schema.TypeString,
321+
Optional: true,
322+
ForceNew: true,
323+
DiffSuppressFunc: WorkbenchInstanceKmsDiffSuppress,
324+
Description: `'Optional. The KMS key used to encrypt the disks, only
287325
applicable if disk_encryption is CMEK. Format: 'projects/{project_id}/locations/{location}/keyRings/{key_ring_id}/cryptoKeys/{key_id}'
288326
Learn more about using your own encryption keys.'`,
289327
},
@@ -325,10 +363,11 @@ up to a maximum of 64000 GB (64 TB). If not specified, this defaults to
325363
Description: `Optional. Input only. Indicates the type of the disk. Possible values: ["PD_STANDARD", "PD_SSD", "PD_BALANCED", "PD_EXTREME"]`,
326364
},
327365
"kms_key": {
328-
Type: schema.TypeString,
329-
Optional: true,
330-
ForceNew: true,
331-
Description: `'Optional. Input only. The KMS key used to encrypt the disks,
366+
Type: schema.TypeString,
367+
Optional: true,
368+
ForceNew: true,
369+
DiffSuppressFunc: WorkbenchInstanceKmsDiffSuppress,
370+
Description: `'Optional. The KMS key used to encrypt the disks,
332371
only applicable if disk_encryption is CMEK. Format: 'projects/{project_id}/locations/{location}/keyRings/{key_ring_id}/cryptoKeys/{key_id}'
333372
Learn more about using your own encryption keys.'`,
334373
},
@@ -615,6 +654,12 @@ The milliseconds portion (".SSS") is optional.`,
615654
},
616655
},
617656
},
657+
"desired_state": {
658+
Type: schema.TypeString,
659+
Optional: true,
660+
Default: "ACTIVE",
661+
Description: `Desired state of the Workbench Instance. Set this field to 'ACTIVE' to start the Instance, and 'STOPPED' to stop the Instance.`,
662+
},
618663
"project": {
619664
Type: schema.TypeString,
620665
Optional: true,
@@ -722,6 +767,16 @@ func resourceWorkbenchInstanceCreate(d *schema.ResourceData, meta interface{}) e
722767
return fmt.Errorf("Workbench instance %q did not reach ACTIVE state: %q", d.Get("name").(string), err)
723768
}
724769

770+
if p, ok := d.GetOk("desired_state"); ok && p.(string) == "STOPPED" {
771+
dRes, err := modifyWorkbenchInstanceState(config, d, project, billingProject, userAgent, "stop")
772+
if err != nil {
773+
return err
774+
}
775+
if err := waitForWorkbenchOperation(config, d, project, billingProject, userAgent, dRes); err != nil {
776+
return fmt.Errorf("Error stopping Workbench Instance: %s", err)
777+
}
778+
}
779+
725780
log.Printf("[DEBUG] Finished creating Instance %q: %#v", d.Id(), res)
726781

727782
return resourceWorkbenchInstanceRead(d, meta)
@@ -763,6 +818,12 @@ func resourceWorkbenchInstanceRead(d *schema.ResourceData, meta interface{}) err
763818
return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("WorkbenchInstance %q", d.Id()))
764819
}
765820

821+
// Explicitly set virtual fields to default values if unset
822+
if _, ok := d.GetOkExists("desired_state"); !ok {
823+
if err := d.Set("desired_state", "ACTIVE"); err != nil {
824+
return fmt.Errorf("Error setting desired_state: %s", err)
825+
}
826+
}
766827
if err := d.Set("project", project); err != nil {
767828
return fmt.Errorf("Error reading Instance: %s", err)
768829
}
@@ -863,34 +924,15 @@ func resourceWorkbenchInstanceUpdate(d *schema.ResourceData, meta interface{}) e
863924
name := d.Get("name").(string)
864925
if d.HasChange("gce_setup.0.machine_type") || d.HasChange("gce_setup.0.accelerator_configs") {
865926
state := d.Get("state").(string)
927+
866928
if state != "STOPPED" {
867-
stopURL, err := tpgresource.ReplaceVars(d, config, "{{WorkbenchBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:stop")
929+
dRes, err := modifyWorkbenchInstanceState(config, d, project, billingProject, userAgent, "stop")
868930
if err != nil {
869931
return err
870932
}
871933

872-
log.Printf("[DEBUG] Stopping Workbench Instance: %q", name)
873-
874-
emptyReqBody := make(map[string]interface{})
875-
876-
dRes, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
877-
Config: config,
878-
Method: "POST",
879-
Project: billingProject,
880-
RawURL: stopURL,
881-
UserAgent: userAgent,
882-
Body: emptyReqBody,
883-
})
884-
if err != nil {
885-
return fmt.Errorf("Error Stopping Workbench Instance: %s", err)
886-
}
887-
888-
var opRes map[string]interface{}
889-
err = WorkbenchOperationWaitTimeWithResponse(
890-
config, dRes, &opRes, project, "Stopping Workbench Instance", userAgent,
891-
d.Timeout(schema.TimeoutUpdate))
892-
if err != nil {
893-
return fmt.Errorf("Error waiting to stop Workbench Instance: %s", err)
934+
if err := waitForWorkbenchOperation(config, d, project, billingProject, userAgent, dRes); err != nil {
935+
return fmt.Errorf("Error stopping Workbench Instance: %s", err)
894936
}
895937

896938
} else {
@@ -955,35 +997,20 @@ func resourceWorkbenchInstanceUpdate(d *schema.ResourceData, meta interface{}) e
955997
}
956998

957999
state := d.Get("state").(string)
1000+
desired_state := d.Get("desired_state").(string)
9581001

959-
if state != "ACTIVE" {
960-
startURL, err := tpgresource.ReplaceVars(d, config, "{{WorkbenchBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:start")
961-
if err != nil {
962-
return err
1002+
if state != desired_state {
1003+
verb := "start"
1004+
if desired_state == "STOPPED" {
1005+
verb = "stop"
9631006
}
964-
965-
log.Printf("[DEBUG] Starting Workbench Instance: %q", name)
966-
967-
emptyReqBody := make(map[string]interface{})
968-
969-
pRes, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
970-
Config: config,
971-
Method: "POST",
972-
Project: billingProject,
973-
RawURL: startURL,
974-
UserAgent: userAgent,
975-
Body: emptyReqBody,
976-
})
1007+
pRes, err := modifyWorkbenchInstanceState(config, d, project, billingProject, userAgent, verb)
9771008
if err != nil {
978-
return fmt.Errorf("Error Starting Workbench Instance: %s", err)
1009+
return err
9791010
}
9801011

981-
var opResp map[string]interface{}
982-
err = WorkbenchOperationWaitTimeWithResponse(
983-
config, pRes, &opResp, project, "Starting Workbench Instance", userAgent,
984-
d.Timeout(schema.TimeoutUpdate))
985-
if err != nil {
986-
return fmt.Errorf("Error waiting to start Workbench Instance: %s", err)
1012+
if err := waitForWorkbenchOperation(config, d, project, billingProject, userAgent, pRes); err != nil {
1013+
return fmt.Errorf("Error waiting to modify Workbench Instance state: %s", err)
9871014
}
9881015

9891016
} else {
@@ -1062,6 +1089,11 @@ func resourceWorkbenchInstanceImport(d *schema.ResourceData, meta interface{}) (
10621089
}
10631090
d.SetId(id)
10641091

1092+
// Explicitly set virtual fields to default values on import
1093+
if err := d.Set("desired_state", "ACTIVE"); err != nil {
1094+
return nil, fmt.Errorf("Error setting desired_state: %s", err)
1095+
}
1096+
10651097
return []*schema.ResourceData{d}, nil
10661098
}
10671099

@@ -1191,11 +1223,11 @@ func flattenWorkbenchInstanceGceSetupBootDiskDiskType(v interface{}, d *schema.R
11911223
}
11921224

11931225
func flattenWorkbenchInstanceGceSetupBootDiskDiskEncryption(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1194-
return d.Get("gce_setup.0.boot_disk.0.disk_encryption")
1226+
return v
11951227
}
11961228

11971229
func flattenWorkbenchInstanceGceSetupBootDiskKmsKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1198-
return d.Get("gce_setup.0.boot_disk.0.kms_key")
1230+
return v
11991231
}
12001232

12011233
func flattenWorkbenchInstanceGceSetupDataDisks(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
@@ -1228,11 +1260,11 @@ func flattenWorkbenchInstanceGceSetupDataDisksDiskType(v interface{}, d *schema.
12281260
}
12291261

12301262
func flattenWorkbenchInstanceGceSetupDataDisksDiskEncryption(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1231-
return d.Get("gce_setup.0.data_disks.0.disk_encryption")
1263+
return v
12321264
}
12331265

12341266
func flattenWorkbenchInstanceGceSetupDataDisksKmsKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1235-
return d.Get("gce_setup.0.data_disks.0.kms_key")
1267+
return v
12361268
}
12371269

12381270
func flattenWorkbenchInstanceGceSetupNetworkInterfaces(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {

google/services/workbench/resource_workbench_instance_generated_test.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ resource "google_workbench_instance" "instance" {
110110
`, context)
111111
}
112112

113-
func TestAccWorkbenchInstance_workbenchInstanceLabelsExample(t *testing.T) {
113+
func TestAccWorkbenchInstance_workbenchInstanceLabelsStoppedExample(t *testing.T) {
114114
t.Parallel()
115115

116116
context := map[string]interface{}{
@@ -124,19 +124,19 @@ func TestAccWorkbenchInstance_workbenchInstanceLabelsExample(t *testing.T) {
124124
CheckDestroy: testAccCheckWorkbenchInstanceDestroyProducer(t),
125125
Steps: []resource.TestStep{
126126
{
127-
Config: testAccWorkbenchInstance_workbenchInstanceLabelsExample(context),
127+
Config: testAccWorkbenchInstance_workbenchInstanceLabelsStoppedExample(context),
128128
},
129129
{
130130
ResourceName: "google_workbench_instance.instance",
131131
ImportState: true,
132132
ImportStateVerify: true,
133-
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "labels", "terraform_labels"},
133+
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "desired_state", "labels", "terraform_labels"},
134134
},
135135
},
136136
})
137137
}
138138

139-
func testAccWorkbenchInstance_workbenchInstanceLabelsExample(context map[string]interface{}) string {
139+
func testAccWorkbenchInstance_workbenchInstanceLabelsStoppedExample(context map[string]interface{}) string {
140140
return acctest.Nprintf(`
141141
resource "google_workbench_instance" "instance" {
142142
name = "tf-test-workbench-instance%{random_suffix}"
@@ -161,6 +161,8 @@ resource "google_workbench_instance" "instance" {
161161
k = "val"
162162
}
163163
164+
desired_state = "STOPPED"
165+
164166
}
165167
`, context)
166168
}
@@ -186,7 +188,7 @@ func TestAccWorkbenchInstance_workbenchInstanceFullExample(t *testing.T) {
186188
ResourceName: "google_workbench_instance.instance",
187189
ImportState: true,
188190
ImportStateVerify: true,
189-
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "gce_setup.0.vm_image", "gce_setup.0.boot_disk.0.disk_encryption", "gce_setup.0.boot_disk.0.disk_type", "gce_setup.0.boot_disk.0.kms_key", "gce_setup.0.data_disks.0.disk_encryption", "gce_setup.0.data_disks.0.disk_type", "gce_setup.0.data_disks.0.kms_key", "labels", "terraform_labels"},
191+
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "gce_setup.0.vm_image", "gce_setup.0.boot_disk.0.disk_type", "gce_setup.0.data_disks.0.disk_type", "labels", "terraform_labels"},
190192
},
191193
},
192194
})
@@ -226,14 +228,14 @@ resource "google_workbench_instance" "instance" {
226228
boot_disk {
227229
disk_size_gb = 310
228230
disk_type = "PD_SSD"
229-
disk_encryption = "GMEK"
231+
disk_encryption = "CMEK"
230232
kms_key = "%{key_name}"
231233
}
232234
233235
data_disks {
234236
disk_size_gb = 330
235237
disk_type = "PD_SSD"
236-
disk_encryption = "GMEK"
238+
disk_encryption = "CMEK"
237239
kms_key = "%{key_name}"
238240
}
239241
@@ -261,6 +263,8 @@ resource "google_workbench_instance" "instance" {
261263
k = "val"
262264
}
263265
266+
desired_state = "ACTIVE"
267+
264268
}
265269
`, context)
266270
}

google/services/workbench/resource_workbench_instance_gpu_test.go renamed to google/services/workbench/resource_workbench_instance_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,57 @@ resource "google_workbench_instance" "instance" {
271271
}
272272
`, context)
273273
}
274+
275+
func TestAccWorkbenchInstance_updateState(t *testing.T) {
276+
t.Parallel()
277+
278+
context := map[string]interface{}{
279+
"random_suffix": acctest.RandString(t, 10),
280+
}
281+
282+
acctest.VcrTest(t, resource.TestCase{
283+
PreCheck: func() { acctest.AccTestPreCheck(t) },
284+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
285+
Steps: []resource.TestStep{
286+
{
287+
Config: testAccWorkbenchInstance_basic(context),
288+
},
289+
{
290+
ResourceName: "google_workbench_instance.instance",
291+
ImportState: true,
292+
ImportStateVerify: true,
293+
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels", "desired_state"},
294+
},
295+
{
296+
Config: testAccWorkbenchInstance_updateState(context),
297+
},
298+
{
299+
ResourceName: "google_workbench_instance.instance",
300+
ImportState: true,
301+
ImportStateVerify: true,
302+
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels", "desired_state"},
303+
},
304+
{
305+
Config: testAccWorkbenchInstance_basic(context),
306+
},
307+
{
308+
ResourceName: "google_workbench_instance.instance",
309+
ImportState: true,
310+
ImportStateVerify: true,
311+
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels", "desired_state"},
312+
},
313+
},
314+
})
315+
}
316+
317+
func testAccWorkbenchInstance_updateState(context map[string]interface{}) string {
318+
return acctest.Nprintf(`
319+
resource "google_workbench_instance" "instance" {
320+
name = "tf-test-workbench-instance%{random_suffix}"
321+
location = "us-central1-a"
322+
323+
desired_state = "STOPPED"
324+
325+
}
326+
`, context)
327+
}

0 commit comments

Comments
 (0)