diff --git a/mmv1/go.mod b/mmv1/go.mod index 6ba2aa672c36..79316b0a09ea 100644 --- a/mmv1/go.mod +++ b/mmv1/go.mod @@ -8,3 +8,7 @@ require ( ) require github.com/golang/glog v1.2.0 + +require github.com/otiai10/copy v1.9.0 + +require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect diff --git a/mmv1/go.sum b/mmv1/go.sum index 02e4ed2c5647..14b659976106 100644 --- a/mmv1/go.sum +++ b/mmv1/go.sum @@ -2,8 +2,16 @@ github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/otiai10/copy v1.9.0 h1:7KFNiCgZ91Ru4qW4CWPf/7jqtxLagGRmIxWldPP9VY4= +github.com/otiai10/copy v1.9.0/go.mod h1:hsfX19wcn0UWIHUQ3/4fHuehhk2UyArQ9dVFAn3FczI= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.4.0/go.mod h1:gifjb2MYOoULtKLqUAEILUG/9KONW6f7YsJ6vQLTlFI= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/mmv1/main.go b/mmv1/main.go index b9d1bf429a35..eeb4de618c80 100644 --- a/mmv1/main.go +++ b/mmv1/main.go @@ -149,7 +149,6 @@ func main() { providerToGenerate = setProvider(*forceProvider, *version, productsForVersion[0], startTime) providerToGenerate.CopyCommonFiles(*outputPath, generateCode, generateDocs) - log.Printf("Compiling common files for terraform") if generateCode { providerToGenerate.CompileCommonFiles(*outputPath, productsForVersion, "") @@ -236,6 +235,8 @@ func setProvider(forceProvider, version string, productApi *api.Product, startTi switch forceProvider { case "tgc": return provider.NewTerraformGoogleConversion(productApi, version, startTime) + case "tgc_cai2hcl": + return provider.NewCaiToTerraformConversion(productApi, version, startTime) default: return provider.NewTerraform(productApi, version, startTime) } diff --git a/mmv1/provider/provider.go b/mmv1/provider/provider.go index 947c79c80d42..fab8e0a52161 100644 --- a/mmv1/provider/provider.go +++ b/mmv1/provider/provider.go @@ -28,7 +28,7 @@ func ProviderName(t Provider) string { return reflect.TypeOf(t).Name() } -func ImportPathFromVersion(t Provider, v string) string { +func ImportPathFromVersion(v string) string { var tpg, dir string switch v { case "ga": diff --git a/mmv1/provider/terraform.go b/mmv1/provider/terraform.go index 75bd3697920f..9d333dabf9dc 100644 --- a/mmv1/provider/terraform.go +++ b/mmv1/provider/terraform.go @@ -63,7 +63,7 @@ func NewTerraform(product *api.Product, versionName string, startTime time.Time) t.Product.SetPropertiesBasedOnVersion(&t.Version) for _, r := range t.Product.Objects { r.SetCompiler(ProviderName(t)) - r.ImportPath = ImportPathFromVersion(t, versionName) + r.ImportPath = ImportPathFromVersion(versionName) } return t @@ -557,8 +557,8 @@ func (t Terraform) replaceImportPath(outputFolder, target string) { data := string(sourceByte) - gaImportPath := ImportPathFromVersion(t, "ga") - betaImportPath := ImportPathFromVersion(t, "beta") + gaImportPath := ImportPathFromVersion("ga") + betaImportPath := ImportPathFromVersion("beta") if strings.Contains(data, betaImportPath) { log.Fatalf("Importing a package from module %s is not allowed in file %s. Please import a package from module %s.", betaImportPath, filepath.Base(target), gaImportPath) diff --git a/mmv1/provider/terraform_tgc.go b/mmv1/provider/terraform_tgc.go index 007c20c05595..7a993ddd8fb1 100644 --- a/mmv1/provider/terraform_tgc.go +++ b/mmv1/provider/terraform_tgc.go @@ -16,6 +16,8 @@ package provider import ( + "bytes" + "errors" "fmt" "io/ioutil" "log" @@ -60,7 +62,7 @@ func NewTerraformGoogleConversion(product *api.Product, versionName string, star t.Product.SetPropertiesBasedOnVersion(&t.Version) for _, r := range t.Product.Objects { r.SetCompiler(ProviderName(t)) - r.ImportPath = ImportPathFromVersion(t, versionName) + r.ImportPath = ImportPathFromVersion(versionName) } return t @@ -155,7 +157,7 @@ func (tgc TerraformGoogleConversion) GenerateIamPolicy(object api.Resource, temp } // Generates the list of resources -func (tgc TerraformGoogleConversion) generateCaiIamResources(products []*api.Product) { +func (tgc *TerraformGoogleConversion) generateCaiIamResources(products []*api.Product) { for _, productDefinition := range products { service := strings.ToLower(productDefinition.Name) for _, object := range productDefinition.Objects { @@ -179,7 +181,7 @@ func (tgc TerraformGoogleConversion) generateCaiIamResources(products []*api.Pro } func (tgc TerraformGoogleConversion) CompileCommonFiles(outputFolder string, products []*api.Product, overridePath string) { - log.Printf("Compiling common files.") + log.Printf("Compiling common files for tgc.") tgc.generateCaiIamResources(products) tgc.NonDefinedTests = retrieveFullManifestOfNonDefinedTests() @@ -199,24 +201,15 @@ func (tgc TerraformGoogleConversion) CompileCommonFiles(outputFolder string, pro templateData := NewTemplateData(outputFolder, tgc.TargetVersionName) tgc.CompileFileList(outputFolder, testSource, *templateData, products) - // compile_file_list( - // output_folder, - // [ - // ['converters/google/resources/services/compute/compute_instance_helpers.go', - // 'third_party/terraform/services/compute/compute_instance_helpers.go.erb'], - // ['converters/google/resources/resource_converters.go', - // 'templates/tgc/resource_converters.go.erb'], - // ['converters/google/resources/services/kms/iam_kms_key_ring.go', - // 'third_party/terraform/services/kms/iam_kms_key_ring.go.erb'], - // ['converters/google/resources/services/kms/iam_kms_crypto_key.go', - // 'third_party/terraform/services/kms/iam_kms_crypto_key.go.erb'], - // ['converters/google/resources/services/compute/metadata.go', - // 'third_party/terraform/services/compute/metadata.go.erb'], - // ['converters/google/resources/services/compute/compute_instance.go', - // 'third_party/tgc/compute_instance.go.erb'] - // ], - // file_template - // ) + resourceConverters := map[string]string{ + "converters/google/resources/services/compute/compute_instance_helpers.go": "third_party/terraform/services/compute/go/compute_instance_helpers.go.tmpl", + "converters/google/resources/resource_converters.go": "third_party/tgc/resource_converters.go.tmpl", + "converters/google/resources/services/kms/iam_kms_key_ring.go": "third_party/terraform/services/kms/go/iam_kms_key_ring.go.tmpl", + "converters/google/resources/services/kms/iam_kms_crypto_key.go": "third_party/terraform/services/kms/go/iam_kms_crypto_key.go.tmpl", + "converters/google/resources/services/compute/metadata.go": "third_party/terraform/services/compute/go/metadata.go.tmpl", + "converters/google/resources/services/compute/compute_instance.go": "third_party/tgc/services/compute/compute_instance.go.tmpl", + } + tgc.CompileFileList(outputFolder, resourceConverters, *templateData, products) } func (tgc TerraformGoogleConversion) CompileFileList(outputFolder string, files map[string]string, fileTemplate TemplateData, products []*api.Product) { @@ -238,7 +231,7 @@ func (tgc TerraformGoogleConversion) CompileFileList(outputFolder string, files formatFile := filepath.Ext(targetFile) == ".go" fileTemplate.GenerateFile(targetFile, source, tgc, formatFile, templates...) - // tgc.replaceImportPath(outputFolder, target) + tgc.replaceImportPath(outputFolder, target) } } @@ -289,16 +282,32 @@ func retrieveFullListOfTestFiles() []string { return testFiles } +// Gets all of files in the folder third_party/tgc/tests/data +func retrieveFullListOfTestTilesWithLocation() map[string]string { + testFiles := make(map[string]string) + files := retrieveFullListOfTestFiles() + for _, file := range files { + target := fmt.Sprintf("testdata/templates/%s", file) + source := fmt.Sprintf("third_party/tgc/tests/data/%s", file) + testFiles[target] = source + } + return testFiles +} + func retrieveTestSourceCodeWithLocation(suffix string) map[string]string { var fileNames []string - path := "third_party/tgc/tests/source/go" + var path string + if suffix == ".tmpl" { + path = "third_party/tgc/tests/source/go" + } else { + path = "third_party/tgc/tests/source" + } files, err := ioutil.ReadDir(path) if err != nil { log.Fatal(err) } for _, file := range files { - log.Printf("ext %s", filepath.Ext(file.Name())) if filepath.Ext(file.Name()) == suffix { fileNames = append(fileNames, file.Name()) } @@ -338,5 +347,139 @@ func retrieveListOfManuallyDefinedTestsFromFile(file string) []string { } func (tgc TerraformGoogleConversion) CopyCommonFiles(outputFolder string, generateCode, generateDocs bool) { + log.Printf("Copying common files.") + + if !generateCode { + return + } + + tgc.CopyFileList(outputFolder, retrieveFullListOfTestTilesWithLocation()) + tgc.CopyFileList(outputFolder, retrieveTestSourceCodeWithLocation(".go")) + + resourceConverters := map[string]string{ + "converters/google/resources/cai/constants.go": "third_party/tgc/cai/constants.go", + "converters/google/resources/constants.go": "third_party/tgc/constants.go", + "converters/google/resources/cai.go": "third_party/tgc/cai.go", + "converters/google/resources/cai/cai.go": "third_party/tgc/cai/cai.go", + "converters/google/resources/cai/cai_test.go": "third_party/tgc/cai/cai_test.go", + "converters/google/resources/org_policy_policy.go": "third_party/tgc/org_policy_policy.go", + "converters/google/resources/getconfig.go": "third_party/tgc/getconfig.go", + "converters/google/resources/folder.go": "third_party/tgc/folder.go", + "converters/google/resources/getconfig_test.go": "third_party/tgc/getconfig_test.go", + "converters/google/resources/cai/json_map.go": "third_party/tgc/cai/json_map.go", + "converters/google/resources/project.go": "third_party/tgc/project.go", + "converters/google/resources/sql_database_instance.go": "third_party/tgc/sql_database_instance.go", + "converters/google/resources/storage_bucket.go": "third_party/tgc/storage_bucket.go", + "converters/google/resources/cloudfunctions_function.go": "third_party/tgc/cloudfunctions_function.go", + "converters/google/resources/cloudfunctions_cloud_function.go": "third_party/tgc/cloudfunctions_cloud_function.go", + "converters/google/resources/bigquery_table.go": "third_party/tgc/bigquery_table.go", + "converters/google/resources/bigtable_cluster.go": "third_party/tgc/bigtable_cluster.go", + "converters/google/resources/bigtable_instance.go": "third_party/tgc/bigtable_instance.go", + "converters/google/resources/cai/iam_helpers.go": "third_party/tgc/cai/iam_helpers.go", + "converters/google/resources/cai/iam_helpers_test.go": "third_party/tgc/cai/iam_helpers_test.go", + "converters/google/resources/services/resourcemanager/organization_iam.go": "third_party/tgc/organization_iam.go", + "converters/google/resources/services/resourcemanager/project_iam.go": "third_party/tgc/project_iam.go", + "converters/google/resources/project_organization_policy.go": "third_party/tgc/project_organization_policy.go", + "converters/google/resources/folder_organization_policy.go": "third_party/tgc/folder_organization_policy.go", + "converters/google/resources/services/resourcemanager/folder_iam.go": "third_party/tgc/folder_iam.go", + "converters/google/resources/container.go": "third_party/tgc/container.go", + "converters/google/resources/project_service.go": "third_party/tgc/project_service.go", + "converters/google/resources/services/monitoring/monitoring_slo_helper.go": "third_party/tgc/monitoring_slo_helper.go", + "converters/google/resources/service_account.go": "third_party/tgc/service_account.go", + "converters/google/resources/services/compute/image.go": "third_party/terraform/services/compute/image.go", + "converters/google/resources/services/compute/disk_type.go": "third_party/terraform/services/compute/disk_type.go", + "converters/google/resources/services/kms/kms_utils.go": "third_party/terraform/services/kms/kms_utils.go", + "converters/google/resources/services/sourcerepo/source_repo_utils.go": "third_party/terraform/services/sourcerepo/source_repo_utils.go", + "converters/google/resources/services/pubsub/pubsub_utils.go": "third_party/terraform/services/pubsub/pubsub_utils.go", + "converters/google/resources/services/resourcemanager/iam_organization.go": "third_party/terraform/services/resourcemanager/iam_organization.go", + "converters/google/resources/services/resourcemanager/iam_folder.go": "third_party/terraform/services/resourcemanager/iam_folder.go", + "converters/google/resources/services/resourcemanager/iam_project.go": "third_party/terraform/services/resourcemanager/iam_project.go", + "converters/google/resources/services/privateca/privateca_utils.go": "third_party/terraform/services/privateca/privateca_utils.go", + "converters/google/resources/services/bigquery/iam_bigquery_dataset.go": "third_party/terraform/services/bigquery/iam_bigquery_dataset.go", + "converters/google/resources/services/bigquery/bigquery_dataset_iam.go": "third_party/tgc/bigquery_dataset_iam.go", + "converters/google/resources/compute_security_policy.go": "third_party/tgc/compute_security_policy.go", + "converters/google/resources/kms_key_ring_iam.go": "third_party/tgc/kms_key_ring_iam.go", + "converters/google/resources/kms_crypto_key_iam.go": "third_party/tgc/kms_crypto_key_iam.go", + "converters/google/resources/project_iam_custom_role.go": "third_party/tgc/project_iam_custom_role.go", + "converters/google/resources/organization_iam_custom_role.go": "third_party/tgc/organization_iam_custom_role.go", + "converters/google/resources/services/pubsub/iam_pubsub_subscription.go": "third_party/terraform/services/pubsub/iam_pubsub_subscription.go", + "converters/google/resources/services/pubsub/pubsub_subscription_iam.go": "third_party/tgc/pubsub_subscription_iam.go", + "converters/google/resources/services/spanner/iam_spanner_database.go": "third_party/terraform/services/spanner/iam_spanner_database.go", + "converters/google/resources/services/spanner/spanner_database_iam.go": "third_party/tgc/spanner_database_iam.go", + "converters/google/resources/services/spanner/iam_spanner_instance.go": "third_party/terraform/services/spanner/iam_spanner_instance.go", + "converters/google/resources/services/spanner/spanner_instance_iam.go": "third_party/tgc/spanner_instance_iam.go", + "converters/google/resources/storage_bucket_iam.go": "third_party/tgc/storage_bucket_iam.go", + "converters/google/resources/organization_policy.go": "third_party/tgc/organization_policy.go", + "converters/google/resources/iam_storage_bucket.go": "third_party/tgc/iam_storage_bucket.go", + "ancestrymanager/ancestrymanager.go": "third_party/tgc/ancestrymanager/ancestrymanager.go", + "ancestrymanager/ancestrymanager_test.go": "third_party/tgc/ancestrymanager/ancestrymanager_test.go", + "ancestrymanager/ancestryutil.go": "third_party/tgc/ancestrymanager/ancestryutil.go", + "ancestrymanager/ancestryutil_test.go": "third_party/tgc/ancestrymanager/ancestryutil_test.go", + "converters/google/convert.go": "third_party/tgc/convert.go", + "converters/google/convert_test.go": "third_party/tgc/convert_test.go", + "converters/google/resources/compute_instance_group.go": "third_party/tgc/compute_instance_group.go", + "converters/google/resources/job.go": "third_party/tgc/job.go", + "converters/google/resources/service_account_key.go": "third_party/tgc/service_account_key.go", + "converters/google/resources/compute_target_pool.go": "third_party/tgc/compute_target_pool.go", + "converters/google/resources/dataproc_cluster.go": "third_party/tgc/dataproc_cluster.go", + "converters/google/resources/composer_environment.go": "third_party/tgc/composer_environment.go", + "converters/google/resources/commitment.go": "third_party/tgc/commitment.go", + "converters/google/resources/firebase_project.go": "third_party/tgc/firebase_project.go", + "converters/google/resources/appengine_application.go": "third_party/tgc/appengine_application.go", + "converters/google/resources/apikeys_key.go": "third_party/tgc/apikeys_key.go", + "converters/google/resources/logging_folder_bucket_config.go": "third_party/tgc/logging_folder_bucket_config.go", + "converters/google/resources/logging_organization_bucket_config.go": "third_party/tgc/logging_organization_bucket_config.go", + "converters/google/resources/logging_project_bucket_config.go": "third_party/tgc/logging_project_bucket_config.go", + "converters/google/resources/logging_billing_account_bucket_config.go": "third_party/tgc/logging_billing_account_bucket_config.go", + "converters/google/resources/appengine_standard_version.go": "third_party/tgc/appengine_standard_version.go", + } + tgc.CopyFileList(outputFolder, resourceConverters) +} + +func (tgc TerraformGoogleConversion) CopyFileList(outputFolder string, files map[string]string) { + for target, source := range files { + targetFile := filepath.Join(outputFolder, target) + targetDir := filepath.Dir(targetFile) + if err := os.MkdirAll(targetDir, os.ModePerm); err != nil { + log.Println(fmt.Errorf("error creating output directory %v: %v", targetDir, err)) + } + // If we've modified a file since starting an MM run, it's a reasonable + // assumption that it was this run that modified it. + if info, err := os.Stat(targetFile); !errors.Is(err, os.ErrNotExist) && tgc.StartTime.Before(info.ModTime()) { + log.Fatalf("%s was already modified during this run at %s", targetFile, info.ModTime().String()) + } + + sourceByte, err := os.ReadFile(source) + if err != nil { + log.Fatalf("Cannot read source file %s while copying: %s", source, err) + } + + err = os.WriteFile(targetFile, sourceByte, 0644) + if err != nil { + log.Fatalf("Cannot write target file %s while copying: %s", target, err) + } + + // Replace import path based on version (beta/alpha) + if filepath.Ext(target) == ".go" || filepath.Ext(target) == ".mod" { + tgc.replaceImportPath(outputFolder, target) + } + } +} + +func (tgc TerraformGoogleConversion) replaceImportPath(outputFolder, target string) { + // Replace import paths to reference the resources dir instead of the google provider + targetFile := filepath.Join(outputFolder, target) + sourceByte, err := os.ReadFile(targetFile) + if err != nil { + log.Fatalf("Cannot read file %s to replace import path: %s", targetFile, err) + } + + // replace google to google-beta + gaImportPath := ImportPathFromVersion("ga") + sourceByte = bytes.Replace(sourceByte, []byte(gaImportPath), []byte(TERRAFORM_PROVIDER_BETA+"/"+RESOURCE_DIRECTORY_BETA), -1) + err = os.WriteFile(targetFile, sourceByte, 0644) + if err != nil { + log.Fatalf("Cannot write file %s to replace import path: %s", target, err) + } } diff --git a/mmv1/provider/terraform_tgc_cai2hcl.go b/mmv1/provider/terraform_tgc_cai2hcl.go new file mode 100644 index 000000000000..8e8ef16f4de1 --- /dev/null +++ b/mmv1/provider/terraform_tgc_cai2hcl.go @@ -0,0 +1,74 @@ +// Copyright 2024 Google Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package provider + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/GoogleCloudPlatform/magic-modules/mmv1/api" + "github.com/GoogleCloudPlatform/magic-modules/mmv1/api/product" + "github.com/otiai10/copy" +) + +// Code generator for a library converting GCP CAI objects to Terraform state. +type CaiToTerraformConversion struct { + TargetVersionName string + + Version product.Version + + Product *api.Product + + StartTime time.Time +} + +func NewCaiToTerraformConversion(product *api.Product, versionName string, startTime time.Time) CaiToTerraformConversion { + t := CaiToTerraformConversion{ + Product: product, + TargetVersionName: versionName, + Version: *product.VersionObjOrClosest(versionName), + StartTime: startTime, + } + + t.Product.SetPropertiesBasedOnVersion(&t.Version) + for _, r := range t.Product.Objects { + r.SetCompiler(ProviderName(t)) + r.ImportPath = ImportPathFromVersion(t, versionName) + } + + return t +} + +func (cai2hcl CaiToTerraformConversion) Generate(outputFolder, productPath, resourceToGenerate string, generateCode, generateDocs bool) { +} + +func (cai2hcl CaiToTerraformConversion) CompileCommonFiles(outputFolder string, products []*api.Product, overridePath string) { +} + +func (cai2hcl CaiToTerraformConversion) CopyCommonFiles(outputFolder string, generateCode, generateDocs bool) { + if !generateCode { + return + } + log.Printf("Coping cai2hcl common files") + + if err := os.MkdirAll(outputFolder, os.ModePerm); err != nil { + log.Println(fmt.Errorf("error creating output directory %v: %v", outputFolder, err)) + } + + if err := copy.Copy("third_party/cai2hcl", outputFolder); err != nil { + log.Println(fmt.Errorf("error copying directory %v: %v", outputFolder, err)) + } +} diff --git a/mmv1/third_party/tgc/resource_converters.go.tmpl b/mmv1/third_party/tgc/resource_converters.go.tmpl new file mode 100644 index 000000000000..1acd324f3d8a --- /dev/null +++ b/mmv1/third_party/tgc/resource_converters.go.tmpl @@ -0,0 +1,193 @@ +{{/* The license inside this block applies to this file + Copyright 2024 Google LLC. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ -}} +// ---------------------------------------------------------------------------- +// +// *** 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 google + +import ( + "sort" + "github.com/GoogleCloudPlatform/terraform-google-conversion/v5/tfplan2cai/converters/google/resources/services/compute" + "github.com/GoogleCloudPlatform/terraform-google-conversion/v5/tfplan2cai/converters/google/resources/services/kms" + "github.com/GoogleCloudPlatform/terraform-google-conversion/v5/tfplan2cai/converters/google/resources/services/resourcemanager" + "github.com/GoogleCloudPlatform/terraform-google-conversion/v5/tfplan2cai/converters/google/resources/services/spanner" + "github.com/GoogleCloudPlatform/terraform-google-conversion/v5/tfplan2cai/converters/google/resources/services/secretmanagerregional" + "github.com/GoogleCloudPlatform/terraform-google-conversion/v5/tfplan2cai/converters/google/resources/services/securesourcemanager" + "github.com/GoogleCloudPlatform/terraform-google-conversion/v5/tfplan2cai/converters/google/resources/services/securitycenterv2" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" +) + + +// ResourceConverter returns a map of terraform resource types (i.e. `google_project`) +// to a slice of ResourceConverters. +// +// Modelling of relationships: +// terraform resources to CAI assets as []cai.ResourceConverter: +// 1:1 = [ResourceConverter{Convert: convertAbc}] (len=1) +// 1:N = [ResourceConverter{Convert: convertAbc}, ...] (len=N) +// N:1 = [ResourceConverter{Convert: convertAbc, merge: mergeAbc}] (len=1) +func ResourceConverters() map[string][]cai.ResourceConverter { + return map[string][]cai.ResourceConverter{ + "google_artifact_registry_repository": {artifactregistry.ResourceConverterArtifactRegistryRepository()}, + "google_app_engine_application": {resourceConverterAppEngineApplication()}, + "google_alloydb_cluster": {alloydb.ResourceConverterAlloydbCluster()}, + "google_alloydb_instance": {alloydb.ResourceConverterAlloydbInstance()}, + "google_apikeys_key": {resourceConverterApikeysKey()}, + "google_compute_address": {compute.ResourceConverterComputeAddress()}, + "google_compute_autoscaler": {compute.ResourceConverterComputeAutoscaler()}, + "google_compute_firewall": {compute.ResourceConverterComputeFirewall()}, + "google_compute_disk": {compute.ResourceConverterComputeDisk()}, + "google_compute_forwarding_rule": {compute.ResourceConverterComputeForwardingRule()}, + "google_gke_hub_membership": {gkehub.ResourceConverterGKEHubMembership()}, + "google_compute_global_address": {compute.ResourceConverterComputeGlobalAddress()}, + "google_compute_global_forwarding_rule": {compute.ResourceConverterComputeGlobalForwardingRule()}, + "google_compute_health_check": {compute.ResourceConverterComputeHealthCheck()}, + "google_compute_instance": {compute.ResourceConverterComputeInstance()}, + "google_compute_instance_group": {resourceConverterComputeInstanceGroup()}, + "google_compute_network": {compute.ResourceConverterComputeNetwork()}, + "google_compute_node_template": {compute.ResourceConverterComputeNodeTemplate()}, + "google_compute_route": {compute.ResourceConverterComputeRoute()}, + "google_compute_router": {compute.ResourceConverterComputeRouter()}, + "google_compute_vpn_tunnel": {compute.ResourceConverterComputeVpnTunnel()}, + "google_compute_resource_policy": {compute.ResourceConverterComputeResourcePolicy()}, + "google_compute_security_policy": {resourceConverterComputeSecurityPolicy()}, + "google_compute_snapshot": {compute.ResourceConverterComputeSnapshot()}, + "google_compute_subnetwork": {compute.ResourceConverterComputeSubnetwork()}, + "google_compute_ssl_policy": {compute.ResourceConverterComputeSslPolicy()}, + "google_compute_ssl_certificate": {compute.ResourceConverterComputeSslCertificate()}, + "google_compute_url_map": {compute.ResourceConverterComputeUrlMap()}, + "google_compute_target_http_proxy": {compute.ResourceConverterComputeTargetHttpProxy()}, + "google_compute_target_https_proxy": {compute.ResourceConverterComputeTargetHttpsProxy()}, + "google_compute_target_ssl_proxy": {compute.ResourceConverterComputeTargetSslProxy()}, + "google_compute_target_pool": {resourceConverterComputeTargetPool()}, + "google_composer_environment": {resourceConverterComposerEnvironment()}, + "google_compute_region_commitment": {resourceConverterCommitment()}, + "google_dataflow_job": {resourceDataflowJob()}, + "google_dataproc_autoscaling_policy": {dataproc.ResourceConverterDataprocAutoscalingPolicy()}, + "google_dataproc_cluster": {resourceConverterDataprocCluster()}, + "google_dns_managed_zone": {dns.ResourceConverterDNSManagedZone()}, + "google_dns_policy": {dns.ResourceConverterDNSPolicy()}, + "google_kms_key_ring_import_job": {kms.ResourceConverterKMSKeyRingImportJob()}, + "google_gke_hub_feature": {gkehub2.ResourceConverterGKEHub2Feature()}, + "google_storage_bucket": {resourceConverterStorageBucket()}, + "google_sql_database_instance": {resourceConverterSQLDatabaseInstance()}, + "google_sql_database": {sql.ResourceConverterSQLDatabase()}, + "google_container_cluster": {resourceConverterContainerCluster()}, + "google_container_node_pool": {resourceConverterContainerNodePool()}, + "google_bigquery_dataset": {bigquery.ResourceConverterBigQueryDataset()}, + "google_bigquery_dataset_iam_policy": {bigquery.ResourceConverterBigqueryDatasetIamPolicy()}, + "google_bigquery_dataset_iam_binding": {bigquery.ResourceConverterBigqueryDatasetIamBinding()}, + "google_bigquery_dataset_iam_member": {bigquery.ResourceConverterBigqueryDatasetIamMember()}, + "google_bigquery_table": {resourceConverterBigQueryTable()}, + "google_datastream_connection_profile": {datastream.ResourceConverterDatastreamConnectionProfile()}, + "google_datastream_private_connection": {datastream.ResourceConverterDatastreamPrivateConnection()}, + "google_datastream_stream": {datastream.ResourceConverterDatastreamStream()}, + "google_firebase_project": {resourceConverterFirebaseProject()}, + "google_org_policy_policy": {resourceConverterOrgPolicyPolicy()}, + "google_redis_instance": {redis.ResourceConverterRedisInstance()}, + "google_spanner_database": {spanner.ResourceConverterSpannerDatabase()}, + "google_spanner_database_iam_policy": {spanner.ResourceConverterSpannerDatabaseIamPolicy()}, + "google_spanner_database_iam_binding": {spanner.ResourceConverterSpannerDatabaseIamBinding()}, + "google_spanner_database_iam_member": {spanner.ResourceConverterSpannerDatabaseIamMember()}, + "google_spanner_instance": {spanner.ResourceConverterSpannerInstance()}, + "google_spanner_instance_iam_policy": {spanner.ResourceConverterSpannerInstanceIamPolicy()}, + "google_spanner_instance_iam_binding": {spanner.ResourceConverterSpannerInstanceIamBinding()}, + "google_spanner_instance_iam_member": {spanner.ResourceConverterSpannerInstanceIamMember()}, + "google_project_service": {resourceConverterServiceUsage()}, + "google_secret_manager_secret_version": {secretmanager.ResourceConverterSecretManagerSecretVersion()}, + "google_pubsub_lite_reservation": {pubsublite.ResourceConverterPubsubLiteReservation()}, + "google_pubsub_lite_subscription": {pubsublite.ResourceConverterPubsubLiteSubscription()}, + "google_pubsub_lite_topic": {pubsublite.ResourceConverterPubsubLiteTopic()}, + "google_pubsub_schema": {pubsub.ResourceConverterPubsubSchema()}, + "google_pubsub_subscription": {pubsub.ResourceConverterPubsubSubscription()}, + "google_pubsub_subscription_iam_policy": {pubsub.ResourceConverterPubsubSubscriptionIamPolicy()}, + "google_pubsub_subscription_iam_binding": {pubsub.ResourceConverterPubsubSubscriptionIamBinding()}, + "google_pubsub_subscription_iam_member": {pubsub.ResourceConverterPubsubSubscriptionIamMember()}, + "google_storage_bucket_iam_policy": {resourceConverterStorageBucketIamPolicy()}, + "google_storage_bucket_iam_binding": {resourceConverterStorageBucketIamBinding()}, + "google_storage_bucket_iam_member": {resourceConverterStorageBucketIamMember()}, + "google_compute_node_group": {compute.ResourceConverterComputeNodeGroup()}, + "google_logging_folder_bucket_config": {resourceConverterLogFolderBucket()}, + "google_app_engine_standard_app_version": {resourceAppEngineStandardAppVersion()}, + "google_logging_organization_bucket_config": {resourceConverterLogOrganizationBucket()}, + "google_logging_project_bucket_config": {resourceConverterLogProjectBucket()}, + "google_logging_billing_account_bucket_config": {resourceConverterLogBillingAccountBucket()}, + "google_cloud_tasks_queue": {cloudtasks.ResourceConverterCloudTasksQueue()}, + "google_pubsub_topic": {pubsub.ResourceConverterPubsubTopic()}, + "google_kms_crypto_key": {kms.ResourceConverterKMSCryptoKey()}, + "google_kms_key_ring": {kms.ResourceConverterKMSKeyRing()}, + "google_filestore_instance": {filestore.ResourceConverterFilestoreInstance()}, + "google_access_context_manager_service_perimeter": {accesscontextmanager.ResourceConverterAccessContextManagerServicePerimeter()}, + "google_access_context_manager_access_policy": {accesscontextmanager.ResourceConverterAccessContextManagerAccessPolicy()}, + "google_cloud_run_service": {cloudrun.ResourceConverterCloudRunService()}, + "google_cloud_run_domain_mapping": {cloudrun.ResourceConverterCloudRunDomainMapping()}, + "google_cloud_run_v2_job": {cloudrunv2.ResourceConverterCloudRunV2Job()}, + "google_cloudfunctions_function": {resourceConverterCloudFunctionsCloudFunction()}, + "google_monitoring_notification_channel": {monitoring.ResourceConverterMonitoringNotificationChannel()}, + "google_monitoring_alert_policy": {monitoring.ResourceConverterMonitoringAlertPolicy()}, + "google_vertex_ai_dataset": {vertexai.ResourceConverterVertexAIDataset()}, + {{- range $object := $.IamResources }} + {{- if $object.IamClassName }} + "{{ $object.TerraformName }}_iam_policy": { {{- $object.IamClassName }}IamPolicy()}, + "{{ $object.TerraformName }}_iam_binding": { {{- $object.IamClassName }}IamBinding()}, + "{{ $object.TerraformName }}_iam_member": { {{- $object.IamClassName }}IamMember()}, + {{- end }} + {{- end }} + "google_project": { + resourceConverterProject(), + resourceConverterProjectBillingInfo(), + }, + "google_bigtable_instance": { + resourceConverterBigtableInstance(), + resourceConverterBigtableCluster(), + }, + "google_organization_iam_policy": {resourcemanager.ResourceConverterOrganizationIamPolicy()}, + "google_organization_iam_binding": {resourcemanager.ResourceConverterOrganizationIamBinding()}, + "google_organization_iam_member": {resourcemanager.ResourceConverterOrganizationIamMember()}, + "google_organization_policy": {resourceConverterOrganizationPolicy()}, + "google_project_organization_policy": {resourceConverterProjectOrgPolicy()}, + "google_folder": {resourceConverterFolder()}, + "google_folder_iam_policy": {resourcemanager.ResourceConverterFolderIamPolicy()}, + "google_folder_iam_binding": {resourcemanager.ResourceConverterFolderIamBinding()}, + "google_folder_iam_member": {resourcemanager.ResourceConverterFolderIamMember()}, + "google_folder_organization_policy": {resourceConverterFolderOrgPolicy()}, + "google_kms_crypto_key_iam_policy": {resourceConverterKmsCryptoKeyIamPolicy()}, + "google_kms_crypto_key_iam_binding": {resourceConverterKmsCryptoKeyIamBinding()}, + "google_kms_crypto_key_iam_member": {resourceConverterKmsCryptoKeyIamMember()}, + "google_kms_key_ring_iam_policy": {resourceConverterKmsKeyRingIamPolicy()}, + "google_kms_key_ring_iam_binding": {resourceConverterKmsKeyRingIamBinding()}, + "google_kms_key_ring_iam_member": {resourceConverterKmsKeyRingIamMember()}, + "google_project_iam_policy": {resourcemanager.ResourceConverterProjectIamPolicy()}, + "google_project_iam_binding": {resourcemanager.ResourceConverterProjectIamBinding()}, + "google_project_iam_member": {resourcemanager.ResourceConverterProjectIamMember()}, + "google_project_iam_custom_role": {resourceConverterProjectIAMCustomRole()}, + "google_organization_iam_custom_role": {resourceConverterOrganizationIAMCustomRole()}, + "google_vpc_access_connector": {vpcaccess.ResourceConverterVPCAccessConnector()}, + "google_logging_metric": {logging.ResourceConverterLoggingMetric()}, + "google_service_account": {resourceConverterServiceAccount()}, + "google_service_account_key": {resourceConverterServiceAccountKey()}, + + } +} diff --git a/mmv1/third_party/tgc/services/compute/compute_instance.go.tmpl b/mmv1/third_party/tgc/services/compute/compute_instance.go.tmpl new file mode 100644 index 000000000000..b5293a31d9b3 --- /dev/null +++ b/mmv1/third_party/tgc/services/compute/compute_instance.go.tmpl @@ -0,0 +1,350 @@ +// ---------------------------------------------------------------------------- +// +// This file is copied here by Magic Modules. The code for building up a +// compute instance object is copied from the manually implemented +// provider file: +// third_party/terraform/resources/resource_compute_instance.go +// +// ---------------------------------------------------------------------------- +package compute + +import ( + "errors" + "fmt" + "strings" + + "google.golang.org/api/googleapi" + + compute "google.golang.org/api/compute/v0.beta" + + "github.com/GoogleCloudPlatform/terraform-google-conversion/v5/tfplan2cai/converters/google/resources/cai" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" +) + +const ComputeInstanceAssetType string = "compute.googleapis.com/Instance" + +func ResourceConverterComputeInstance() cai.ResourceConverter { + return cai.ResourceConverter{ + AssetType: ComputeInstanceAssetType, + Convert: GetComputeInstanceCaiObject, + } +} + +func GetComputeInstanceCaiObject(d tpgresource.TerraformResourceData, config *transport_tpg.Config) ([]cai.Asset, error) { + name, err := cai.AssetName(d, config, "//compute.googleapis.com/projects/{{"{{"}}project{{"}}"}}/zones/{{"{{"}}zone{{"}}"}}/instances/{{"{{"}}name{{"}}"}}") + if err != nil { + return []cai.Asset{}, err + } + if obj, err := GetComputeInstanceApiObject(d, config); err == nil { + return []cai.Asset{{"{{"}} + Name: name, + Type: ComputeInstanceAssetType, + Resource: &cai.AssetResource{ + Version: "v1", + DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest", + DiscoveryName: "Instance", + Data: obj, + }, + {{"}}"}}, nil + } else { + return []cai.Asset{}, err + } +} + +func GetComputeInstanceApiObject(d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]interface{}, error) { + project, err := tpgresource.GetProject(d, config) + if err != nil { + return nil, err + } + + instance, err := expandComputeInstance(project, d, config) + if err != nil { + return nil, err + } + + return cai.JsonMap(instance) +} + +func expandComputeInstance(project string, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (*compute.Instance, error) { + // Get the machine type + var machineTypeUrl string + if mt, ok := d.GetOk("machine_type"); ok { + machineType, err := tpgresource.ParseMachineTypesFieldValue(mt.(string), d, config) + if err != nil { + return nil, fmt.Errorf( + "Error loading machine type: %s", + err) + } + machineTypeUrl = machineType.RelativeLink() + } + + // Build up the list of disks + + disks := []*compute.AttachedDisk{} + if _, hasBootDisk := d.GetOk("boot_disk"); hasBootDisk { + bootDisk, err := expandBootDisk(d, config, project) + if err != nil { + return nil, err + } + disks = append(disks, bootDisk) + } + + if _, hasScratchDisk := d.GetOk("scratch_disk"); hasScratchDisk { + scratchDisks, err := expandScratchDisks(d, config, project) + if err != nil { + return nil, err + } + disks = append(disks, scratchDisks...) + } + + attachedDisksCount := d.Get("attached_disk.#").(int) + + for i := 0; i < attachedDisksCount; i++ { + diskConfig := d.Get(fmt.Sprintf("attached_disk.%d", i)).(map[string]interface{}) + disk, err := expandAttachedDisk(diskConfig, d, config) + if err != nil { + return nil, err + } + + disks = append(disks, disk) + } + + sch := d.Get("scheduling").([]interface{}) + var scheduling *compute.Scheduling + if len(sch) == 0 { + // TF doesn't do anything about defaults inside of nested objects, so if + // scheduling hasn't been set, then send it with its default values. + scheduling = &compute.Scheduling{ + AutomaticRestart: googleapi.Bool(true), + } + } else { + prefix := "scheduling.0" + scheduling = &compute.Scheduling{ + AutomaticRestart: googleapi.Bool(d.Get(prefix + ".automatic_restart").(bool)), + Preemptible: d.Get(prefix + ".preemptible").(bool), + OnHostMaintenance: d.Get(prefix + ".on_host_maintenance").(string), + ProvisioningModel: d.Get(prefix + ".provisioning_model").(string), + ForceSendFields: []string{"AutomaticRestart", "Preemptible"}, + } + } + + metadata, err := resourceInstanceMetadata(d) + if err != nil { + return nil, fmt.Errorf("Error creating metadata: %s", err) + } + + networkInterfaces, err := expandNetworkInterfaces(d, config) + if err != nil { + return nil, fmt.Errorf("Error creating network interfaces: %s", err) + } + + accels, err := expandInstanceGuestAccelerators(d, config) + if err != nil { + return nil, fmt.Errorf("Error creating guest accelerators: %s", err) + } + + // Create the instance information + return &compute.Instance{ + CanIpForward: d.Get("can_ip_forward").(bool), + Description: d.Get("description").(string), + Disks: disks, + MachineType: machineTypeUrl, + Metadata: metadata, + Name: d.Get("name").(string), + Zone: d.Get("zone").(string), + NetworkInterfaces: networkInterfaces, + Tags: resourceInstanceTags(d), + Labels: tpgresource.ExpandLabels(d), + ServiceAccounts: expandServiceAccounts(d.Get("service_account").([]interface{})), + GuestAccelerators: accels, + MinCpuPlatform: d.Get("min_cpu_platform").(string), + Scheduling: scheduling, + DeletionProtection: d.Get("deletion_protection").(bool), + Hostname: d.Get("hostname").(string), + ForceSendFields: []string{"CanIpForward", "DeletionProtection"}, + ShieldedInstanceConfig: expandShieldedVmConfigs(d), + DisplayDevice: expandDisplayDevice(d), + AdvancedMachineFeatures: expandAdvancedMachineFeatures(d), + }, nil +} + +func expandAttachedDisk(diskConfig map[string]interface{}, d tpgresource.TerraformResourceData, meta interface{}) (*compute.AttachedDisk, error) { + config := meta.(*transport_tpg.Config) + + s := diskConfig["source"].(string) + var sourceLink string + if strings.Contains(s, "regions/") { + source, err := tpgresource.ParseRegionDiskFieldValue(s, d, config) + if err != nil { + return nil, err + } + sourceLink = source.RelativeLink() + } else { + source, err := tpgresource.ParseDiskFieldValue(s, d, config) + if err != nil { + return nil, err + } + sourceLink = source.RelativeLink() + } + + disk := &compute.AttachedDisk{ + Source: sourceLink, + } + + if v, ok := diskConfig["mode"]; ok { + disk.Mode = v.(string) + } + + if v, ok := diskConfig["device_name"]; ok { + disk.DeviceName = v.(string) + } + + keyValue, keyOk := diskConfig["disk_encryption_key_raw"] + if keyOk { + if keyValue != "" { + disk.DiskEncryptionKey = &compute.CustomerEncryptionKey{ + RawKey: keyValue.(string), + } + } + } + + kmsValue, kmsOk := diskConfig["kms_key_self_link"] + if kmsOk { + if keyOk && keyValue != "" && kmsValue != "" { + return nil, errors.New("Only one of kms_key_self_link and disk_encryption_key_raw can be set") + } + if kmsValue != "" { + disk.DiskEncryptionKey = &compute.CustomerEncryptionKey{ + KmsKeyName: kmsValue.(string), + } + } + } + return disk, nil +} + +// See comment on expandInstanceTemplateGuestAccelerators regarding why this +// code is duplicated. +func expandInstanceGuestAccelerators(d tpgresource.TerraformResourceData, config *transport_tpg.Config) ([]*compute.AcceleratorConfig, error) { + configs, ok := d.GetOk("guest_accelerator") + if !ok { + return nil, nil + } + accels := configs.([]interface{}) + guestAccelerators := make([]*compute.AcceleratorConfig, 0, len(accels)) + for _, raw := range accels { + data := raw.(map[string]interface{}) + if data["count"].(int) == 0 { + continue + } + at, err := tpgresource.ParseAcceleratorFieldValue(data["type"].(string), d, config) + if err != nil { + return nil, fmt.Errorf("cannot parse accelerator type: %v", err) + } + guestAccelerators = append(guestAccelerators, &compute.AcceleratorConfig{ + AcceleratorCount: int64(data["count"].(int)), + AcceleratorType: at.RelativeLink(), + }) + } + + return guestAccelerators, nil +} + +func expandBootDisk(d tpgresource.TerraformResourceData, config *transport_tpg.Config, project string) (*compute.AttachedDisk, error) { + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return nil, err + } + + disk := &compute.AttachedDisk{ + AutoDelete: d.Get("boot_disk.0.auto_delete").(bool), + Boot: true, + } + + if v, ok := d.GetOk("boot_disk.0.device_name"); ok { + disk.DeviceName = v.(string) + } + + if v, ok := d.GetOk("boot_disk.0.disk_encryption_key_raw"); ok { + if v != "" { + disk.DiskEncryptionKey = &compute.CustomerEncryptionKey{ + RawKey: v.(string), + } + } + } + + if v, ok := d.GetOk("boot_disk.0.kms_key_self_link"); ok { + if v != "" { + disk.DiskEncryptionKey = &compute.CustomerEncryptionKey{ + KmsKeyName: v.(string), + } + } + } + + if v, ok := d.GetOk("boot_disk.0.source"); ok { + source, err := tpgresource.ParseDiskFieldValue(v.(string), d, config) + if err != nil { + return nil, err + } + disk.Source = source.RelativeLink() + } + + if _, ok := d.GetOk("boot_disk.0.initialize_params"); ok { + disk.InitializeParams = &compute.AttachedDiskInitializeParams{} + + if v, ok := d.GetOk("boot_disk.0.initialize_params.0.size"); ok { + disk.InitializeParams.DiskSizeGb = int64(v.(int)) + } + + if v, ok := d.GetOk("boot_disk.0.initialize_params.0.type"); ok { + diskTypeName := v.(string) + diskType, err := readDiskType(config, d, diskTypeName) + if err != nil { + return nil, fmt.Errorf("Error loading disk type '%s': %s", diskTypeName, err) + } + disk.InitializeParams.DiskType = diskType.RelativeLink() + } + + if v, ok := d.GetOk("boot_disk.0.initialize_params.0.image"); ok { + imageName := v.(string) + imageUrl, err := ResolveImage(config, project, imageName, userAgent) + if err != nil { + return nil, fmt.Errorf("Error resolving image name '%s': %s", imageName, err) + } + + disk.InitializeParams.SourceImage = imageUrl + } + + if _, ok := d.GetOk("boot_disk.0.initialize_params.0.labels"); ok { + disk.InitializeParams.Labels = tpgresource.ExpandStringMap(d, "boot_disk.0.initialize_params.0.labels") + } + } + + if v, ok := d.GetOk("boot_disk.0.mode"); ok { + disk.Mode = v.(string) + } + + return disk, nil +} + +func expandScratchDisks(d tpgresource.TerraformResourceData, config *transport_tpg.Config, project string) ([]*compute.AttachedDisk, error) { + diskType, err := readDiskType(config, d, "local-ssd") + if err != nil { + return nil, fmt.Errorf("Error loading disk type 'local-ssd': %s", err) + } + + n := d.Get("scratch_disk.#").(int) + scratchDisks := make([]*compute.AttachedDisk, 0, n) + for i := 0; i < n; i++ { + scratchDisks = append(scratchDisks, &compute.AttachedDisk{ + AutoDelete: true, + Type: "SCRATCH", + Interface: d.Get(fmt.Sprintf("scratch_disk.%d.interface", i)).(string), + InitializeParams: &compute.AttachedDiskInitializeParams{ + DiskType: diskType.RelativeLink(), + }, + }) + } + + return scratchDisks, nil +}