Skip to content

Commit

Permalink
Make notebooks wait for active state and enable stopping/starting ins… (
Browse files Browse the repository at this point in the history
GoogleCloudPlatform#9971)

* Make notebooks wait for active state and enable stopping/starting instances using the desired_state field

* ignore update_time
  • Loading branch information
bcreddy-gcp authored and pengq-google committed May 21, 2024
1 parent 10bd7ea commit 78238b9
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 0 deletions.
22 changes: 22 additions & 0 deletions mmv1/products/notebooks/Instance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ examples:
region_override: 'us-west1-a'
vars:
instance_name: 'notebooks-instance'
- !ruby/object:Provider::Terraform::Examples
name: 'notebook_instance_basic_stopped'
primary_resource_id: 'instance'
primary_resource_name: "fmt.Sprintf(\"tf-test-notebooks-instance%s\",
context[\"\
random_suffix\"])"
region_override: 'us-west1-a'
vars:
instance_name: 'notebooks-instance'
ignore_read_extra:
- 'desired_state'
- !ruby/object:Provider::Terraform::Examples
name: 'notebook_instance_basic_container'
primary_resource_id: 'instance'
Expand Down Expand Up @@ -87,9 +98,20 @@ examples:
key_name: 'acctest.BootstrapKMSKeyInLocation(t, "global").CryptoKey.Name'
test_env_vars:
service_account: :SERVICE_ACCT
virtual_fields:
- !ruby/object:Api::Type::Enum
name: desired_state
description: |
Desired state of the Notebook Instance. Set this field to `ACTIVE` to start the Instance, and `STOPPED` to stop the Instance.
values:
- :ACTIVE
- :STOPPED
default_value: :ACTIVE
custom_code: !ruby/object:Provider::Terraform::CustomCode
constants: templates/terraform/constants/notebooks_instance.go
update_encoder: templates/terraform/update_encoder/notebooks_instance.go
post_create: templates/terraform/post_create/notebooks_instance.go.erb
post_update: templates/terraform/post_update/notebooks_instance.go.erb
state_upgraders: true
schema_version: 1
parameters:
Expand Down
53 changes: 53 additions & 0 deletions mmv1/templates/terraform/constants/notebooks_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,56 @@ func NotebooksInstanceKmsDiffSuppress(_, old, new string, _ *schema.ResourceData
}
return false
}

<% unless compiler == "terraformgoogleconversion-codegen" -%>
// waitForNotebooksInstanceActive waits for an Notebook instance to become "ACTIVE"
func waitForNotebooksInstanceActive(d *schema.ResourceData, config *transport_tpg.Config, timeout time.Duration) error {
return resource.Retry(timeout, func() *resource.RetryError {
if err := resourceNotebooksInstanceRead(d, config); err != nil {
return resource.NonRetryableError(err)
}

name := d.Get("name").(string)
state := d.Get("state").(string)
if state == "ACTIVE" {
log.Printf("[DEBUG] Notebook Instance %q has state %q.", name, state)
return nil
} else {
return resource.RetryableError(fmt.Errorf("Notebook Instance %q has state %q. Waiting for ACTIVE state", name, state))
}

})
}
<% end -%>

func modifyNotebooksInstanceState(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, "{{NotebooksBasePath}}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_notebooks_instance %q: %s", state, d.Id(), err)
}
return res, nil
}

<% unless compiler == "terraformgoogleconversion-codegen" -%>
func waitForNotebooksOperation(config *transport_tpg.Config, d *schema.ResourceData, project string, billingProject string, userAgent string, response map[string]interface{}) error {
var opRes map[string]interface{}
err := NotebooksOperationWaitTimeWithResponse(
config, response, &opRes, project, "Modifying Notebook Instance state", userAgent,
d.Timeout(schema.TimeoutUpdate))
if err != nil {
return err
}
return nil
}
<% end -%>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
resource "google_notebooks_instance" "<%= ctx[:primary_resource_id] %>" {
name = "<%= ctx[:vars]["instance_name"] %>"
location = "us-west1-a"
machine_type = "e2-medium"
vm_image {
project = "deeplearning-platform-release"
image_family = "tf-latest-cpu"
}
desired_state = "STOPPED"
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ resource "google_notebooks_instance" "<%= ctx[:primary_resource_id] %>" {
]
disk_encryption = "CMEK"
kms_key = "<%= ctx[:vars]['key_name'] %>"
desired_state = "ACTIVE"
}

data "google_compute_network" "my_network" {
Expand Down
13 changes: 13 additions & 0 deletions mmv1/templates/terraform/post_create/notebooks_instance.go.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
if err := waitForNotebooksInstanceActive(d, config, d.Timeout(schema.TimeoutCreate) - time.Minute); err != nil {
return fmt.Errorf("Notebook 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 := modifyNotebooksInstanceState(config, d, project, billingProject, userAgent, "stop")
if err != nil {
return err
}
if err := waitForNotebooksOperation(config, d, project, billingProject, userAgent, dRes); err != nil {
return fmt.Errorf("Error stopping Notebook Instance: %s", err)
}
}
21 changes: 21 additions & 0 deletions mmv1/templates/terraform/post_update/notebooks_instance.go.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name := d.Get("name").(string)
state := d.Get("state").(string)
desired_state := d.Get("desired_state").(string)

if state != desired_state {
verb := "start"
if desired_state == "STOPPED" {
verb = "stop"
}
pRes, err := modifyNotebooksInstanceState(config, d, project, billingProject, userAgent, verb)
if err != nil {
return err
}

if err := waitForNotebooksOperation(config, d, project, billingProject, userAgent, pRes); err != nil {
return fmt.Errorf("Error waiting to modify Notebook Instance state: %s", err)
}

} else {
log.Printf("[DEBUG] Notebook Instance %q has state %q.", name, state)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<% autogen_exception -%>
package notebooks_test

<% unless version == 'ga' %>
import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-provider-google/google/acctest"
)

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

prefix := fmt.Sprintf("%d", acctest.RandInt(t))
name := fmt.Sprintf("tf-%s", prefix)

acctest.VcrTest(t, resource.TestCase{
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testAccNotebooksInstance_basic_active(name),
},
{
ResourceName: "google_notebooks_instance.test",
ImportState: true,
ImportStateVerify: true,
ExpectNonEmptyPlan: true,
ImportStateVerifyIgnore: []string{"container_image", "metadata", "vm_image","desired_state", "update_time"},
},
{
Config: testAccNotebooksInstance_basic_stopped(name),
},
{
ResourceName: "google_notebooks_instance.test",
ImportState: true,
ImportStateVerify: true,
ExpectNonEmptyPlan: true,
ImportStateVerifyIgnore: []string{"container_image", "metadata", "vm_image","desired_state", "update_time"},
},
{
Config: testAccNotebooksInstance_basic_active(name),
},
{
ResourceName: "google_notebooks_instance.test",
ImportState: true,
ImportStateVerify: true,
ExpectNonEmptyPlan: true,
ImportStateVerifyIgnore: []string{"container_image", "metadata", "vm_image","desired_state", "update_time"},
},
},
})
}

func testAccNotebooksInstance_basic_active(name string) string {
return fmt.Sprintf(`
resource "google_notebooks_instance" "test" {
name = "%s"
location = "us-west1-a"
machine_type = "e2-medium"
vm_image {
project = "deeplearning-platform-release"
image_family = "tf-latest-cpu"
}
desired_state = "ACTIVE"
}
`, name)
}

func testAccNotebooksInstance_basic_stopped(name string) string {
return fmt.Sprintf(`
resource "google_notebooks_instance" "test" {
name = "%s"
location = "us-west1-a"
machine_type = "e2-medium"
vm_image {
project = "deeplearning-platform-release"
image_family = "tf-latest-cpu"
}
desired_state = "STOPPED"
}
`, name)
}
<% end -%>

0 comments on commit 78238b9

Please sign in to comment.