Skip to content

Commit

Permalink
Add desired state to workbench instances. (#9945) (#17270)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
modular-magician authored Feb 13, 2024
1 parent 6015012 commit cfe4774
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 71 deletions.
3 changes: 3 additions & 0 deletions .changelog/9945.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
workbench: added `desired_state` field to `google_workbench_instance` resource
```
150 changes: 91 additions & 59 deletions google/services/workbench/resource_workbench_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,43 @@ func waitForWorkbenchInstanceActive(d *schema.ResourceData, config *transport_tp
})
}

func modifyWorkbenchInstanceState(config *transport_tpg.Config, d *schema.ResourceData, project string, billingProject string, userAgent string, state string) (map[string]interface{}, error) {
url, err := tpgresource.ReplaceVars(d, config, "{{WorkbenchBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:"+state)
if err != nil {
return nil, err
}

res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "POST",
Project: billingProject,
RawURL: url,
UserAgent: userAgent,
})
if err != nil {
return nil, fmt.Errorf("Unable to %q google_workbench_instance %q: %s", state, d.Id(), err)
}
return res, nil
}

func WorkbenchInstanceKmsDiffSuppress(_, old, new string, _ *schema.ResourceData) bool {
if strings.HasPrefix(old, new) {
return true
}
return false
}

func waitForWorkbenchOperation(config *transport_tpg.Config, d *schema.ResourceData, project string, billingProject string, userAgent string, response map[string]interface{}) error {
var opRes map[string]interface{}
err := WorkbenchOperationWaitTimeWithResponse(
config, response, &opRes, project, "Modifying Workbench Instance state", userAgent,
d.Timeout(schema.TimeoutUpdate))
if err != nil {
return err
}
return nil
}

func ResourceWorkbenchInstance() *schema.Resource {
return &schema.Resource{
Create: resourceWorkbenchInstanceCreate,
Expand Down Expand Up @@ -280,10 +317,11 @@ recommended value of 150GB.`,
Description: `Optional. Indicates the type of the disk. Possible values: ["PD_STANDARD", "PD_SSD", "PD_BALANCED", "PD_EXTREME"]`,
},
"kms_key": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: `'Optional. Input only. The KMS key used to encrypt the disks, only
Type: schema.TypeString,
Optional: true,
ForceNew: true,
DiffSuppressFunc: WorkbenchInstanceKmsDiffSuppress,
Description: `'Optional. The KMS key used to encrypt the disks, only
applicable if disk_encryption is CMEK. Format: 'projects/{project_id}/locations/{location}/keyRings/{key_ring_id}/cryptoKeys/{key_id}'
Learn more about using your own encryption keys.'`,
},
Expand Down Expand Up @@ -325,10 +363,11 @@ up to a maximum of 64000 GB (64 TB). If not specified, this defaults to
Description: `Optional. Input only. Indicates the type of the disk. Possible values: ["PD_STANDARD", "PD_SSD", "PD_BALANCED", "PD_EXTREME"]`,
},
"kms_key": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: `'Optional. Input only. The KMS key used to encrypt the disks,
Type: schema.TypeString,
Optional: true,
ForceNew: true,
DiffSuppressFunc: WorkbenchInstanceKmsDiffSuppress,
Description: `'Optional. The KMS key used to encrypt the disks,
only applicable if disk_encryption is CMEK. Format: 'projects/{project_id}/locations/{location}/keyRings/{key_ring_id}/cryptoKeys/{key_id}'
Learn more about using your own encryption keys.'`,
},
Expand Down Expand Up @@ -615,6 +654,12 @@ The milliseconds portion (".SSS") is optional.`,
},
},
},
"desired_state": {
Type: schema.TypeString,
Optional: true,
Default: "ACTIVE",
Description: `Desired state of the Workbench Instance. Set this field to 'ACTIVE' to start the Instance, and 'STOPPED' to stop the Instance.`,
},
"project": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -722,6 +767,16 @@ func resourceWorkbenchInstanceCreate(d *schema.ResourceData, meta interface{}) e
return fmt.Errorf("Workbench instance %q did not reach ACTIVE state: %q", d.Get("name").(string), err)
}

if p, ok := d.GetOk("desired_state"); ok && p.(string) == "STOPPED" {
dRes, err := modifyWorkbenchInstanceState(config, d, project, billingProject, userAgent, "stop")
if err != nil {
return err
}
if err := waitForWorkbenchOperation(config, d, project, billingProject, userAgent, dRes); err != nil {
return fmt.Errorf("Error stopping Workbench Instance: %s", err)
}
}

log.Printf("[DEBUG] Finished creating Instance %q: %#v", d.Id(), res)

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

// Explicitly set virtual fields to default values if unset
if _, ok := d.GetOkExists("desired_state"); !ok {
if err := d.Set("desired_state", "ACTIVE"); err != nil {
return fmt.Errorf("Error setting desired_state: %s", err)
}
}
if err := d.Set("project", project); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
Expand Down Expand Up @@ -863,34 +924,15 @@ func resourceWorkbenchInstanceUpdate(d *schema.ResourceData, meta interface{}) e
name := d.Get("name").(string)
if d.HasChange("gce_setup.0.machine_type") || d.HasChange("gce_setup.0.accelerator_configs") {
state := d.Get("state").(string)

if state != "STOPPED" {
stopURL, err := tpgresource.ReplaceVars(d, config, "{{WorkbenchBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:stop")
dRes, err := modifyWorkbenchInstanceState(config, d, project, billingProject, userAgent, "stop")
if err != nil {
return err
}

log.Printf("[DEBUG] Stopping Workbench Instance: %q", name)

emptyReqBody := make(map[string]interface{})

dRes, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "POST",
Project: billingProject,
RawURL: stopURL,
UserAgent: userAgent,
Body: emptyReqBody,
})
if err != nil {
return fmt.Errorf("Error Stopping Workbench Instance: %s", err)
}

var opRes map[string]interface{}
err = WorkbenchOperationWaitTimeWithResponse(
config, dRes, &opRes, project, "Stopping Workbench Instance", userAgent,
d.Timeout(schema.TimeoutUpdate))
if err != nil {
return fmt.Errorf("Error waiting to stop Workbench Instance: %s", err)
if err := waitForWorkbenchOperation(config, d, project, billingProject, userAgent, dRes); err != nil {
return fmt.Errorf("Error stopping Workbench Instance: %s", err)
}

} else {
Expand Down Expand Up @@ -955,35 +997,20 @@ func resourceWorkbenchInstanceUpdate(d *schema.ResourceData, meta interface{}) e
}

state := d.Get("state").(string)
desired_state := d.Get("desired_state").(string)

if state != "ACTIVE" {
startURL, err := tpgresource.ReplaceVars(d, config, "{{WorkbenchBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:start")
if err != nil {
return err
if state != desired_state {
verb := "start"
if desired_state == "STOPPED" {
verb = "stop"
}

log.Printf("[DEBUG] Starting Workbench Instance: %q", name)

emptyReqBody := make(map[string]interface{})

pRes, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "POST",
Project: billingProject,
RawURL: startURL,
UserAgent: userAgent,
Body: emptyReqBody,
})
pRes, err := modifyWorkbenchInstanceState(config, d, project, billingProject, userAgent, verb)
if err != nil {
return fmt.Errorf("Error Starting Workbench Instance: %s", err)
return err
}

var opResp map[string]interface{}
err = WorkbenchOperationWaitTimeWithResponse(
config, pRes, &opResp, project, "Starting Workbench Instance", userAgent,
d.Timeout(schema.TimeoutUpdate))
if err != nil {
return fmt.Errorf("Error waiting to start Workbench Instance: %s", err)
if err := waitForWorkbenchOperation(config, d, project, billingProject, userAgent, pRes); err != nil {
return fmt.Errorf("Error waiting to modify Workbench Instance state: %s", err)
}

} else {
Expand Down Expand Up @@ -1062,6 +1089,11 @@ func resourceWorkbenchInstanceImport(d *schema.ResourceData, meta interface{}) (
}
d.SetId(id)

// Explicitly set virtual fields to default values on import
if err := d.Set("desired_state", "ACTIVE"); err != nil {
return nil, fmt.Errorf("Error setting desired_state: %s", err)
}

return []*schema.ResourceData{d}, nil
}

Expand Down Expand Up @@ -1191,11 +1223,11 @@ func flattenWorkbenchInstanceGceSetupBootDiskDiskType(v interface{}, d *schema.R
}

func flattenWorkbenchInstanceGceSetupBootDiskDiskEncryption(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return d.Get("gce_setup.0.boot_disk.0.disk_encryption")
return v
}

func flattenWorkbenchInstanceGceSetupBootDiskKmsKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return d.Get("gce_setup.0.boot_disk.0.kms_key")
return v
}

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

func flattenWorkbenchInstanceGceSetupDataDisksDiskEncryption(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return d.Get("gce_setup.0.data_disks.0.disk_encryption")
return v
}

func flattenWorkbenchInstanceGceSetupDataDisksKmsKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return d.Get("gce_setup.0.data_disks.0.kms_key")
return v
}

func flattenWorkbenchInstanceGceSetupNetworkInterfaces(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ resource "google_workbench_instance" "instance" {
`, context)
}

func TestAccWorkbenchInstance_workbenchInstanceLabelsExample(t *testing.T) {
func TestAccWorkbenchInstance_workbenchInstanceLabelsStoppedExample(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
Expand All @@ -124,19 +124,19 @@ func TestAccWorkbenchInstance_workbenchInstanceLabelsExample(t *testing.T) {
CheckDestroy: testAccCheckWorkbenchInstanceDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccWorkbenchInstance_workbenchInstanceLabelsExample(context),
Config: testAccWorkbenchInstance_workbenchInstanceLabelsStoppedExample(context),
},
{
ResourceName: "google_workbench_instance.instance",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "labels", "terraform_labels"},
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "desired_state", "labels", "terraform_labels"},
},
},
})
}

func testAccWorkbenchInstance_workbenchInstanceLabelsExample(context map[string]interface{}) string {
func testAccWorkbenchInstance_workbenchInstanceLabelsStoppedExample(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_workbench_instance" "instance" {
name = "tf-test-workbench-instance%{random_suffix}"
Expand All @@ -161,6 +161,8 @@ resource "google_workbench_instance" "instance" {
k = "val"
}
desired_state = "STOPPED"
}
`, context)
}
Expand All @@ -186,7 +188,7 @@ func TestAccWorkbenchInstance_workbenchInstanceFullExample(t *testing.T) {
ResourceName: "google_workbench_instance.instance",
ImportState: true,
ImportStateVerify: true,
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"},
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"},
},
},
})
Expand Down Expand Up @@ -226,14 +228,14 @@ resource "google_workbench_instance" "instance" {
boot_disk {
disk_size_gb = 310
disk_type = "PD_SSD"
disk_encryption = "GMEK"
disk_encryption = "CMEK"
kms_key = "%{key_name}"
}
data_disks {
disk_size_gb = 330
disk_type = "PD_SSD"
disk_encryption = "GMEK"
disk_encryption = "CMEK"
kms_key = "%{key_name}"
}
Expand Down Expand Up @@ -261,6 +263,8 @@ resource "google_workbench_instance" "instance" {
k = "val"
}
desired_state = "ACTIVE"
}
`, context)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,57 @@ resource "google_workbench_instance" "instance" {
}
`, context)
}

func TestAccWorkbenchInstance_updateState(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"random_suffix": acctest.RandString(t, 10),
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testAccWorkbenchInstance_basic(context),
},
{
ResourceName: "google_workbench_instance.instance",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels", "desired_state"},
},
{
Config: testAccWorkbenchInstance_updateState(context),
},
{
ResourceName: "google_workbench_instance.instance",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels", "desired_state"},
},
{
Config: testAccWorkbenchInstance_basic(context),
},
{
ResourceName: "google_workbench_instance.instance",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels", "desired_state"},
},
},
})
}

func testAccWorkbenchInstance_updateState(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_workbench_instance" "instance" {
name = "tf-test-workbench-instance%{random_suffix}"
location = "us-central1-a"
desired_state = "STOPPED"
}
`, context)
}
Loading

0 comments on commit cfe4774

Please sign in to comment.