mmv1/provider/template_data.go (256 lines of code) (raw):

// 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 ( "bytes" "errors" "fmt" "go/format" "log" "os" "os/exec" "path/filepath" "strings" "sync" "text/template" "github.com/GoogleCloudPlatform/magic-modules/mmv1/api" "github.com/GoogleCloudPlatform/magic-modules/mmv1/google" "github.com/golang/glog" ) type TemplateData struct { OutputFolder string VersionName string TerraformResourceDirectory string TerraformProviderModule string // TODO rewrite: is this needed? // # Information about the local environment // # (which formatters are enabled, start-time) // attr_accessor :env } var GA_VERSION = "ga" var BETA_VERSION = "beta" var ALPHA_VERSION = "alpha" var PRIVATE_VERSION = "private" var goimportFiles sync.Map func NewTemplateData(outputFolder string, versionName string) *TemplateData { td := TemplateData{OutputFolder: outputFolder, VersionName: versionName} if versionName == GA_VERSION { td.TerraformResourceDirectory = "google" td.TerraformProviderModule = "github.com/hashicorp/terraform-provider-google" } else if versionName == ALPHA_VERSION || versionName == PRIVATE_VERSION { td.TerraformResourceDirectory = "google-private" td.TerraformProviderModule = "internal/terraform-next" } else { td.TerraformResourceDirectory = "google-beta" td.TerraformProviderModule = "github.com/hashicorp/terraform-provider-google-beta" } return &td } func (td *TemplateData) GenerateResourceFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/resource.go.tmpl" templates := []string{ templatePath, "templates/terraform/schema_property.go.tmpl", "templates/terraform/schema_subresource.go.tmpl", "templates/terraform/expand_resource_ref.tmpl", "templates/terraform/custom_flatten/bigquery_table_ref.go.tmpl", "templates/terraform/flatten_property_method.go.tmpl", "templates/terraform/expand_property_method.go.tmpl", "templates/terraform/update_mask.go.tmpl", "templates/terraform/nested_query.go.tmpl", "templates/terraform/unordered_list_customize_diff.go.tmpl", } td.GenerateFile(filePath, templatePath, resource, true, templates...) } func (td *TemplateData) GenerateMetadataFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/metadata.yaml.tmpl" templates := []string{ templatePath, } td.GenerateFile(filePath, templatePath, resource, false, templates...) } func (td *TemplateData) GenerateOperationFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/operation.go.tmpl" templates := []string{ templatePath, } td.GenerateFile(filePath, templatePath, resource, true, templates...) } func (td *TemplateData) GenerateDocumentationFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/resource.html.markdown.tmpl" templates := []string{ templatePath, "templates/terraform/property_documentation.html.markdown.tmpl", "templates/terraform/nested_property_documentation.html.markdown.tmpl", } td.GenerateFile(filePath, templatePath, resource, false, templates...) } func (td *TemplateData) GenerateTestFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/examples/base_configs/test_file.go.tmpl" templates := []string{ "templates/terraform/env_var_context.go.tmpl", templatePath, } tmplInput := TestInput{ Res: resource, ImportPath: td.ImportPath(), PROJECT_NAME: "my-project-name", CREDENTIALS: "my/credentials/filename.json", REGION: "us-west1", ORG_ID: "123456789", ORG_DOMAIN: "example.com", ORG_TARGET: "123456789", PROJECT_NUMBER: "1111111111111", BILLING_ACCT: "000000-0000000-0000000-000000", MASTER_BILLING_ACCT: "000000-0000000-0000000-000000", SERVICE_ACCT: "my@service-account.com", CUST_ID: "A01b123xz", IDENTITY_USER: "cloud_identity_user", PAP_DESCRIPTION: "description", CHRONICLE_ID: "00000000-0000-0000-0000-000000000000", VMWAREENGINE_PROJECT: "my-vmwareengine-project", } td.GenerateFile(filePath, templatePath, tmplInput, true, templates...) } func (td *TemplateData) GenerateIamPolicyFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/iam_policy.go.tmpl" templates := []string{ templatePath, } td.GenerateFile(filePath, templatePath, resource, true, templates...) } func (td *TemplateData) GenerateIamResourceDocumentationFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/resource_iam.html.markdown.tmpl" templates := []string{ templatePath, } td.GenerateFile(filePath, templatePath, resource, false, templates...) } func (td *TemplateData) GenerateIamDatasourceDocumentationFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/datasource_iam.html.markdown.tmpl" templates := []string{ templatePath, } td.GenerateFile(filePath, templatePath, resource, false, templates...) } func (td *TemplateData) GenerateIamPolicyTestFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/examples/base_configs/iam_test_file.go.tmpl" templates := []string{ templatePath, "templates/terraform/env_var_context.go.tmpl", "templates/terraform/iam/iam_test_setup.go.tmpl", } td.GenerateFile(filePath, templatePath, resource, true, templates...) } func (td *TemplateData) GenerateSweeperFile(filePath string, resource api.Resource) { templatePath := "templates/terraform/sweeper_file.go.tmpl" templates := []string{ templatePath, } td.GenerateFile(filePath, templatePath, resource, false, templates...) } func (td *TemplateData) GenerateTGCResourceFile(filePath string, resource api.Resource) { templatePath := "templates/tgc/resource_converter.go.tmpl" templates := []string{ templatePath, "templates/terraform/expand_property_method.go.tmpl", } td.GenerateFile(filePath, templatePath, resource, true, templates...) } func (td *TemplateData) GenerateTGCIamResourceFile(filePath string, resource api.Resource) { templatePath := "templates/tgc/resource_converter_iam.go.tmpl" templates := []string{ templatePath, } td.GenerateFile(filePath, templatePath, resource, true, templates...) } func (td *TemplateData) GenerateFile(filePath, templatePath string, input any, goFormat bool, templates ...string) { templateFileName := filepath.Base(templatePath) funcMap := template.FuncMap{ "TemplatePath": func() string { return templatePath }, } for k, v := range google.TemplateFunctions { funcMap[k] = v } tmpl, err := template.New(templateFileName).Funcs(funcMap).ParseFiles(templates...) if err != nil { glog.Exit(fmt.Sprintf("error parsing %s for filepath %s ", templateFileName, filePath), err) } contents := bytes.Buffer{} if err = tmpl.ExecuteTemplate(&contents, templateFileName, input); err != nil { glog.Exit(fmt.Sprintf("error executing %s for filepath %s ", templateFileName, filePath), err) } sourceByte := contents.Bytes() if len(sourceByte) == 0 { return } if goFormat { formattedByte, err := format.Source(sourceByte) if err != nil { glog.Error(fmt.Errorf("error formatting %s: %s", filePath, err)) } else { sourceByte = formattedByte } if !strings.Contains(templatePath, "third_party/terraform") { goimportFiles.Store(filePath, struct{}{}) } } err = os.WriteFile(filePath, sourceByte, 0644) if err != nil { glog.Exit(err) } } func (td *TemplateData) ImportPath() string { if td.VersionName == GA_VERSION { return "github.com/hashicorp/terraform-provider-google/google" } else if td.VersionName == ALPHA_VERSION || td.VersionName == PRIVATE_VERSION { return "internal/terraform-next/google-private" } return "github.com/hashicorp/terraform-provider-google-beta/google-beta" } func FixImports(outputPath string, dumpDiffs bool) { log.Printf("Fixing go import paths") baseArgs := []string{"-w"} if dumpDiffs { baseArgs = []string{"-d", "-w"} } // -w and -d are mutually exclusive; if dumpDiffs is requested we need to run twice. for _, base := range baseArgs { hasFiles := false args := []string{base} goimportFiles.Range(func(filePath, _ any) bool { p, err := filepath.Rel(outputPath, filePath.(string)) if err != nil { log.Fatal(err) } args = append(args, p) hasFiles = true return true }) if hasFiles { cmd := exec.Command("goimports", args...) cmd.Dir = outputPath cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { var exitErr *exec.ExitError if errors.As(err, &exitErr) && len(exitErr.Stderr) > 0 { glog.Error(string(exitErr.Stderr)) } log.Fatal(err) } } } } type TestInput struct { Res api.Resource ImportPath string PROJECT_NAME string CREDENTIALS string REGION string ORG_ID string ORG_DOMAIN string ORG_TARGET string PROJECT_NUMBER string BILLING_ACCT string MASTER_BILLING_ACCT string SERVICE_ACCT string CUST_ID string IDENTITY_USER string PAP_DESCRIPTION string CHRONICLE_ID string VMWAREENGINE_PROJECT string }