diff --git a/.changelog/12715.txt b/.changelog/12715.txt new file mode 100644 index 00000000000..0af818a7824 --- /dev/null +++ b/.changelog/12715.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_colab_runtime` +``` \ No newline at end of file diff --git a/google/provider/provider_mmv1_resources.go b/google/provider/provider_mmv1_resources.go index 8970379ea9b..aefc5730d00 100644 --- a/google/provider/provider_mmv1_resources.go +++ b/google/provider/provider_mmv1_resources.go @@ -465,9 +465,9 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{ } // Resources -// Generated resources: 507 +// Generated resources: 508 // Generated IAM resources: 261 -// Total generated resources: 768 +// Total generated resources: 769 var generatedResources = map[string]*schema.Resource{ "google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(), "google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(), @@ -635,6 +635,7 @@ var generatedResources = map[string]*schema.Resource{ "google_cloud_tasks_queue_iam_binding": tpgiamresource.ResourceIamBinding(cloudtasks.CloudTasksQueueIamSchema, cloudtasks.CloudTasksQueueIamUpdaterProducer, cloudtasks.CloudTasksQueueIdParseFunc), "google_cloud_tasks_queue_iam_member": tpgiamresource.ResourceIamMember(cloudtasks.CloudTasksQueueIamSchema, cloudtasks.CloudTasksQueueIamUpdaterProducer, cloudtasks.CloudTasksQueueIdParseFunc), "google_cloud_tasks_queue_iam_policy": tpgiamresource.ResourceIamPolicy(cloudtasks.CloudTasksQueueIamSchema, cloudtasks.CloudTasksQueueIamUpdaterProducer, cloudtasks.CloudTasksQueueIdParseFunc), + "google_colab_runtime": colab.ResourceColabRuntime(), "google_colab_runtime_template": colab.ResourceColabRuntimeTemplate(), "google_composer_user_workloads_config_map": composer.ResourceComposerUserWorkloadsConfigMap(), "google_compute_address": compute.ResourceComputeAddress(), diff --git a/google/services/colab/colab_operation.go b/google/services/colab/colab_operation.go index 010cb282ae2..4c3f6aad07c 100644 --- a/google/services/colab/colab_operation.go +++ b/google/services/colab/colab_operation.go @@ -1,20 +1,5 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 - -// ---------------------------------------------------------------------------- -// -// *** AUTO GENERATED CODE *** Type: MMv1 *** -// -// ---------------------------------------------------------------------------- -// -// This file is automatically generated by Magic Modules and manual -// changes will be clobbered when the file is regenerated. -// -// Please read more about how to change this file in -// .github/CONTRIBUTING.md. -// -// ---------------------------------------------------------------------------- - package colab import ( @@ -38,8 +23,11 @@ func (w *ColabOperationWaiter) QueryOp() (interface{}, error) { if w == nil { return nil, fmt.Errorf("Cannot query operation, it's unset or nil.") } + + region := tpgresource.GetRegionFromRegionalSelfLink(w.CommonOperationWaiter.Op.Name) + // Returns the proper get. - url := fmt.Sprintf("%s%s", w.Config.ColabBasePath, w.CommonOperationWaiter.Op.Name) + url := fmt.Sprintf("https://%s-aiplatform.googleapis.com/v1/%s", region, w.CommonOperationWaiter.Op.Name) return transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ Config: w.Config, diff --git a/google/services/colab/resource_colab_runtime.go b/google/services/colab/resource_colab_runtime.go new file mode 100644 index 00000000000..8fa01ac1af7 --- /dev/null +++ b/google/services/colab/resource_colab_runtime.go @@ -0,0 +1,495 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package colab + +import ( + "fmt" + "log" + "net/http" + "reflect" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func ResourceColabRuntime() *schema.Resource { + return &schema.Resource{ + Create: resourceColabRuntimeCreate, + Read: resourceColabRuntimeRead, + Update: resourceColabRuntimeUpdate, + Delete: resourceColabRuntimeDelete, + + Importer: &schema.ResourceImporter{ + State: resourceColabRuntimeImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "display_name": { + Type: schema.TypeString, + Required: true, + Description: `Required. The display name of the Runtime.`, + }, + "location": { + Type: schema.TypeString, + Required: true, + Description: `The location for the resource: https://cloud.google.com/colab/docs/locations`, + }, + "runtime_user": { + Type: schema.TypeString, + Required: true, + Description: `The user email of the NotebookRuntime.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `The description of the Runtime.`, + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: `The resource name of the Runtime`, + }, + "notebook_runtime_template_ref": { + Type: schema.TypeList, + Optional: true, + Description: `'Runtime specific information used for NotebookRuntime creation.'`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "notebook_runtime_template": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: tpgresource.ProjectNumberDiffSuppress, + Description: `The resource name of the NotebookRuntimeTemplate based on which a NotebookRuntime will be created.`, + }, + }, + }, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceColabRuntimeCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + notebookRuntimeTemplateRefProp, err := expandColabRuntimeNotebookRuntimeTemplateRef(d.Get("notebook_runtime_template_ref"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("notebook_runtime_template_ref"); !tpgresource.IsEmptyValue(reflect.ValueOf(notebookRuntimeTemplateRefProp)) && (ok || !reflect.DeepEqual(v, notebookRuntimeTemplateRefProp)) { + obj["notebookRuntimeTemplateRef"] = notebookRuntimeTemplateRefProp + } + runtimeUserProp, err := expandColabRuntimeRuntimeUser(d.Get("runtime_user"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("runtime_user"); !tpgresource.IsEmptyValue(reflect.ValueOf(runtimeUserProp)) && (ok || !reflect.DeepEqual(v, runtimeUserProp)) { + obj["runtimeUser"] = runtimeUserProp + } + displayNameProp, err := expandColabRuntimeDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + descriptionProp, err := expandColabRuntimeDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + + obj, err = resourceColabRuntimeEncoder(d, meta, obj) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{ColabBasePath}}projects/{{project}}/locations/{{location}}/notebookRuntimes:assign?notebook_runtime_id={{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Runtime: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Runtime: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + Headers: headers, + }) + if err != nil { + return fmt.Errorf("Error creating Runtime: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = ColabOperationWaitTime( + config, res, project, "Creating Runtime", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create Runtime: %s", err) + } + + log.Printf("[DEBUG] Finished creating Runtime %q: %#v", d.Id(), res) + + return resourceColabRuntimeRead(d, meta) +} + +func resourceColabRuntimeRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{ColabBasePath}}projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Runtime: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("ColabRuntime %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Runtime: %s", err) + } + + if err := d.Set("notebook_runtime_template_ref", flattenColabRuntimeNotebookRuntimeTemplateRef(res["notebookRuntimeTemplateRef"], d, config)); err != nil { + return fmt.Errorf("Error reading Runtime: %s", err) + } + if err := d.Set("runtime_user", flattenColabRuntimeRuntimeUser(res["runtimeUser"], d, config)); err != nil { + return fmt.Errorf("Error reading Runtime: %s", err) + } + if err := d.Set("display_name", flattenColabRuntimeDisplayName(res["displayName"], d, config)); err != nil { + return fmt.Errorf("Error reading Runtime: %s", err) + } + if err := d.Set("description", flattenColabRuntimeDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading Runtime: %s", err) + } + + return nil +} + +func resourceColabRuntimeUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Runtime: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + notebookRuntimeTemplateRefProp, err := expandColabRuntimeNotebookRuntimeTemplateRef(d.Get("notebook_runtime_template_ref"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("notebook_runtime_template_ref"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, notebookRuntimeTemplateRefProp)) { + obj["notebookRuntimeTemplateRef"] = notebookRuntimeTemplateRefProp + } + runtimeUserProp, err := expandColabRuntimeRuntimeUser(d.Get("runtime_user"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("runtime_user"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, runtimeUserProp)) { + obj["runtimeUser"] = runtimeUserProp + } + displayNameProp, err := expandColabRuntimeDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + descriptionProp, err := expandColabRuntimeDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + + obj, err = resourceColabRuntimeEncoder(d, meta, obj) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{ColabBasePath}}projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Runtime %q: %#v", d.Id(), obj) + headers := make(http.Header) + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PUT", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + Headers: headers, + }) + + if err != nil { + return fmt.Errorf("Error updating Runtime %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating Runtime %q: %#v", d.Id(), res) + } + + err = ColabOperationWaitTime( + config, res, project, "Updating Runtime", userAgent, + d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return err + } + + return resourceColabRuntimeRead(d, meta) +} + +func resourceColabRuntimeDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Runtime: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{ColabBasePath}}projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + + log.Printf("[DEBUG] Deleting Runtime %q", d.Id()) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "Runtime") + } + + err = ColabOperationWaitTime( + config, res, project, "Deleting Runtime", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting Runtime %q: %#v", d.Id(), res) + return nil +} + +func resourceColabRuntimeImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/locations/(?P[^/]+)/notebookRuntimes/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)$", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenColabRuntimeNotebookRuntimeTemplateRef(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["notebook_runtime_template"] = + flattenColabRuntimeNotebookRuntimeTemplateRefNotebookRuntimeTemplate(original["notebookRuntimeTemplate"], d, config) + return []interface{}{transformed} +} +func flattenColabRuntimeNotebookRuntimeTemplateRefNotebookRuntimeTemplate(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenColabRuntimeRuntimeUser(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenColabRuntimeDisplayName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenColabRuntimeDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandColabRuntimeNotebookRuntimeTemplateRef(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedNotebookRuntimeTemplate, err := expandColabRuntimeNotebookRuntimeTemplateRefNotebookRuntimeTemplate(original["notebook_runtime_template"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNotebookRuntimeTemplate); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["notebookRuntimeTemplate"] = transformedNotebookRuntimeTemplate + } + + return transformed, nil +} + +func expandColabRuntimeNotebookRuntimeTemplateRefNotebookRuntimeTemplate(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandColabRuntimeRuntimeUser(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandColabRuntimeDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandColabRuntimeDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func resourceColabRuntimeEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { + newObj := make(map[string]interface{}) + newObj["notebookRuntimeTemplate"], _ = d.GetOk("notebook_runtime_template_ref.0.notebook_runtime_template") + + delete(obj, "notebookRuntimeTemplateRef") + + newObj["notebookRuntime"] = obj + return newObj, nil +} diff --git a/google/services/colab/resource_colab_runtime_generated_meta.yaml b/google/services/colab/resource_colab_runtime_generated_meta.yaml new file mode 100644 index 00000000000..f65e23fdb4a --- /dev/null +++ b/google/services/colab/resource_colab_runtime_generated_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_colab_runtime' +generation_type: 'mmv1' +api_service_name: 'aiplatform.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Runtime' diff --git a/google/services/colab/resource_colab_runtime_generated_test.go b/google/services/colab/resource_colab_runtime_generated_test.go new file mode 100644 index 00000000000..1cf69675843 --- /dev/null +++ b/google/services/colab/resource_colab_runtime_generated_test.go @@ -0,0 +1,219 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package colab_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func TestAccColabRuntime_colabRuntimeBasicExample(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), + CheckDestroy: testAccCheckColabRuntimeDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccColabRuntime_colabRuntimeBasicExample(context), + }, + { + ResourceName: "google_colab_runtime.runtime", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name"}, + }, + }, + }) +} + +func testAccColabRuntime_colabRuntimeBasicExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_colab_runtime_template" "my_template" { + name = "tf-test-colab-runtime%{random_suffix}" + display_name = "Runtime template basic" + location = "us-central1" + + machine_spec { + machine_type = "e2-standard-4" + } + + network_spec { + enable_internet_access = true + } +} + +resource "google_colab_runtime" "runtime" { + name = "tf-test-colab-runtime%{random_suffix}" + location = "us-central1" + + notebook_runtime_template_ref { + notebook_runtime_template = google_colab_runtime_template.my_template.id + } + + display_name = "Runtime basic" + runtime_user = "gterraformtestuser@gmail.com" + + depends_on = [ + google_colab_runtime_template.my_template, + ] +} +`, context) +} + +func TestAccColabRuntime_colabRuntimeFullExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "key_name": acctest.BootstrapKMSKeyInLocation(t, "us-central1").CryptoKey.Name, + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckColabRuntimeDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccColabRuntime_colabRuntimeFullExample(context), + }, + { + ResourceName: "google_colab_runtime.runtime", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name"}, + }, + }, + }) +} + +func testAccColabRuntime_colabRuntimeFullExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_colab_runtime_template" "my_template" { + name = "tf-test-colab-runtime%{random_suffix}" + display_name = "Runtime template full" + location = "us-central1" + description = "Full runtime template" + machine_spec { + machine_type = "n1-standard-2" + accelerator_type = "NVIDIA_TESLA_T4" + accelerator_count = "1" + } + + data_persistent_disk_spec { + disk_type = "pd-standard" + disk_size_gb = 200 + } + + network_spec { + enable_internet_access = true + } + + labels = { + k = "val" + } + + idle_shutdown_config { + idle_timeout = "3600s" + } + + euc_config { + euc_disabled = true + } + + shielded_vm_config { + enable_secure_boot = true + } + + network_tags = ["abc", "def"] + + encryption_spec { + kms_key_name = "%{key_name}" + } +} + +resource "google_colab_runtime" "runtime" { + name = "tf-test-colab-runtime%{random_suffix}" + location = "us-central1" + + notebook_runtime_template_ref { + notebook_runtime_template = google_colab_runtime_template.my_template.id + } + + display_name = "Runtime full" + runtime_user = "gterraformtestuser@gmail.com" + description = "Full runtime" + + depends_on = [ + google_colab_runtime_template.my_template + ] +} +`, context) +} + +func testAccCheckColabRuntimeDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_colab_runtime" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{ColabBasePath}}projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("ColabRuntime still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/services/colab/resource_colab_runtime_sweeper.go b/google/services/colab/resource_colab_runtime_sweeper.go new file mode 100644 index 00000000000..a5de548ae82 --- /dev/null +++ b/google/services/colab/resource_colab_runtime_sweeper.go @@ -0,0 +1,139 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package colab + +import ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/sweeper" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func init() { + sweeper.AddTestSweepers("ColabRuntime", testSweepColabRuntime) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepColabRuntime(region string) error { + resourceName := "ColabRuntime" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sweeper.SharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := envvar.GetTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &tpgresource.ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://{{region}}-aiplatform.googleapis.com/v1/projects/{{project}}/locations/{{location}}/notebookRuntimes", "?")[0] + listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: listUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["runtimes"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + if obj["name"] == nil { + log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) + return nil + } + + name := tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) + // Skip resources that shouldn't be sweeped + if !sweeper.IsSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://{{region}}-aiplatform.googleapis.com/v1/projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}" + deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: config.Project, + RawURL: deleteUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/website/docs/r/colab_runtime.html.markdown b/website/docs/r/colab_runtime.html.markdown new file mode 100644 index 00000000000..e0e17107837 --- /dev/null +++ b/website/docs/r/colab_runtime.html.markdown @@ -0,0 +1,229 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Colab Enterprise" +description: |- + 'A runtime is a Google-provisioned virtual machine (VM) that can run the code in your notebook (IPYNB file). +--- + +# google_colab_runtime + +'A runtime is a Google-provisioned virtual machine (VM) that can run the code in your notebook (IPYNB file).' + + +To get more information about Runtime, see: + +* [API documentation](https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.notebookRuntimes) +* How-to Guides + * [Create a runtime](https://cloud.google.com/colab/docs/create-runtime) + + +## Example Usage - Colab Runtime Basic + + +```hcl +resource "google_colab_runtime_template" "my_template" { + name = "colab-runtime" + display_name = "Runtime template basic" + location = "us-central1" + + machine_spec { + machine_type = "e2-standard-4" + } + + network_spec { + enable_internet_access = true + } +} + +resource "google_colab_runtime" "runtime" { + name = "colab-runtime" + location = "us-central1" + + notebook_runtime_template_ref { + notebook_runtime_template = google_colab_runtime_template.my_template.id + } + + display_name = "Runtime basic" + runtime_user = "gterraformtestuser@gmail.com" + + depends_on = [ + google_colab_runtime_template.my_template, + ] +} +``` + +## Example Usage - Colab Runtime Full + + +```hcl +resource "google_colab_runtime_template" "my_template" { + name = "colab-runtime" + display_name = "Runtime template full" + location = "us-central1" + description = "Full runtime template" + machine_spec { + machine_type = "n1-standard-2" + accelerator_type = "NVIDIA_TESLA_T4" + accelerator_count = "1" + } + + data_persistent_disk_spec { + disk_type = "pd-standard" + disk_size_gb = 200 + } + + network_spec { + enable_internet_access = true + } + + labels = { + k = "val" + } + + idle_shutdown_config { + idle_timeout = "3600s" + } + + euc_config { + euc_disabled = true + } + + shielded_vm_config { + enable_secure_boot = true + } + + network_tags = ["abc", "def"] + + encryption_spec { + kms_key_name = "my-crypto-key" + } +} + +resource "google_colab_runtime" "runtime" { + name = "colab-runtime" + location = "us-central1" + + notebook_runtime_template_ref { + notebook_runtime_template = google_colab_runtime_template.my_template.id + } + + display_name = "Runtime full" + runtime_user = "gterraformtestuser@gmail.com" + description = "Full runtime" + + depends_on = [ + google_colab_runtime_template.my_template + ] +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `runtime_user` - + (Required) + The user email of the NotebookRuntime. + +* `display_name` - + (Required) + Required. The display name of the Runtime. + +* `location` - + (Required) + The location for the resource: https://cloud.google.com/colab/docs/locations + + +- - - + + +* `notebook_runtime_template_ref` - + (Optional) + 'Runtime specific information used for NotebookRuntime creation.' + Structure is [documented below](#nested_notebook_runtime_template_ref). + +* `description` - + (Optional) + The description of the Runtime. + +* `name` - + (Optional) + The resource name of the Runtime + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `notebook_runtime_template_ref` block supports: + +* `notebook_runtime_template` - + (Required) + The resource name of the NotebookRuntimeTemplate based on which a NotebookRuntime will be created. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}` + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. +- `delete` - Default is 20 minutes. + +## Import + + +Runtime can be imported using any of these accepted formats: + +* `projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}` +* `{{project}}/{{location}}/{{name}}` +* `{{location}}/{{name}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Runtime using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}}" + to = google_colab_runtime.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), Runtime can be imported using one of the formats above. For example: + +``` +$ terraform import google_colab_runtime.default projects/{{project}}/locations/{{location}}/notebookRuntimes/{{name}} +$ terraform import google_colab_runtime.default {{project}}/{{location}}/{{name}} +$ terraform import google_colab_runtime.default {{location}}/{{name}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).