Skip to content

Commit c7aa539

Browse files
authored
Rewrite tgc provider and resource converter template (#11706)
1 parent e709ea5 commit c7aa539

12 files changed

+389
-49
lines changed

mmv1/api/resource.go

+67
Original file line numberDiff line numberDiff line change
@@ -1601,3 +1601,70 @@ func (r Resource) StateUpgradersCount() []int {
16011601
}
16021602
return nums
16031603
}
1604+
1605+
func (r Resource) CaiProductBaseUrl() string {
1606+
version := r.ProductMetadata.VersionObjOrClosest(r.TargetVersionName)
1607+
baseUrl := version.CaiBaseUrl
1608+
if baseUrl == "" {
1609+
baseUrl = version.BaseUrl
1610+
}
1611+
return baseUrl
1612+
}
1613+
1614+
// Returns the Cai product backend name from the version base url
1615+
// base_url: https://accessapproval.googleapis.com/v1/ -> accessapproval
1616+
func (r Resource) CaiProductBackendName(caiProductBaseUrl string) string {
1617+
backendUrl := strings.Split(strings.Split(caiProductBaseUrl, "://")[1], ".googleapis.com")[0]
1618+
return strings.ToLower(backendUrl)
1619+
}
1620+
1621+
// Gets the Cai asset name template, which could include version
1622+
// For example: //monitoring.googleapis.com/v3/projects/{{project}}/services/{{service_id}}
1623+
func (r Resource) rawCaiAssetNameTemplate(productBackendName string) string {
1624+
caiBaseUrl := ""
1625+
if r.CaiBaseUrl != "" {
1626+
caiBaseUrl = fmt.Sprintf("%s/{{name}}", r.CaiBaseUrl)
1627+
}
1628+
if caiBaseUrl == "" {
1629+
caiBaseUrl = r.SelfLink
1630+
}
1631+
if caiBaseUrl == "" {
1632+
caiBaseUrl = fmt.Sprintf("%s/{{name}}", r.BaseUrl)
1633+
}
1634+
return fmt.Sprintf("//%s.googleapis.com/%s", productBackendName, caiBaseUrl)
1635+
}
1636+
1637+
// Gets the Cai asset name template, which doesn't include version
1638+
// For example: //monitoring.googleapis.com/projects/{{project}}/services/{{service_id}}
1639+
func (r Resource) CaiAssetNameTemplate(productBackendName string) string {
1640+
template := r.rawCaiAssetNameTemplate(productBackendName)
1641+
versionRegex, err := regexp.Compile(`\/(v\d[^\/]*)\/`)
1642+
if err != nil {
1643+
log.Fatalf("Cannot compile the regular expression: %v", err)
1644+
}
1645+
1646+
return versionRegex.ReplaceAllString(template, "/")
1647+
}
1648+
1649+
// Gets the Cai API version
1650+
func (r Resource) CaiApiVersion(productBackendName, caiProductBaseUrl string) string {
1651+
template := r.rawCaiAssetNameTemplate(productBackendName)
1652+
1653+
versionRegex, err := regexp.Compile(`\/(v\d[^\/]*)\/`)
1654+
if err != nil {
1655+
log.Fatalf("Cannot compile the regular expression: %v", err)
1656+
}
1657+
1658+
apiVersion := strings.ReplaceAll(versionRegex.FindString(template), "/", "")
1659+
if apiVersion != "" {
1660+
return apiVersion
1661+
}
1662+
1663+
splits := strings.Split(caiProductBaseUrl, "/")
1664+
for i := 0; i < len(splits); i++ {
1665+
if splits[len(splits)-1-i] != "" {
1666+
return splits[len(splits)-1-i]
1667+
}
1668+
}
1669+
return ""
1670+
}

mmv1/api/type.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,8 @@ func (t *Type) GetPrefix() string {
422422
if t.Prefix == "" {
423423
if t.ParentMetadata == nil {
424424
nestedPrefix := ""
425-
if t.ResourceMetadata.NestedQuery != nil {
425+
// TODO: Use the nestedPrefix for tgc provider to be consistent with terraform provider
426+
if t.ResourceMetadata.NestedQuery != nil && t.ResourceMetadata.Compiler != "terraformgoogleconversion-codegen" {
426427
nestedPrefix = "Nested"
427428
}
428429

mmv1/main.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ var doNotGenerateCode = flag.Bool("no-code", false, "do not generate code")
3636

3737
var doNotGenerateDocs = flag.Bool("no-docs", false, "do not generate docs")
3838

39+
var forceProvider = flag.String("provider", "", "optional provider name. If specified, a non-default provider will be used.")
40+
3941
// Example usage: --yaml
4042
var yamlMode = flag.Bool("yaml", false, "copy text over from ruby yaml to go yaml")
4143

@@ -110,6 +112,7 @@ func main() {
110112
startTime := time.Now()
111113
log.Printf("Generating MM output to '%s'", *outputPath)
112114
log.Printf("Using %s version", *version)
115+
log.Printf("Using %s provider", *forceProvider)
113116

114117
// Building compute takes a long time and can't be parallelized within the product
115118
// so lets build it first
@@ -120,7 +123,7 @@ func main() {
120123
return false
121124
})
122125

123-
var providerToGenerate *provider.Terraform
126+
var providerToGenerate provider.Provider
124127
var productsForVersion []*api.Product
125128

126129
ch := make(chan string, len(allProductFiles))
@@ -143,8 +146,7 @@ func main() {
143146
// In order to only copy/compile files once per provider this must be called outside
144147
// of the products loop. This will get called with the provider from the final iteration
145148
// of the loop
146-
providerToGenerate = provider.NewTerraform(productsForVersion[0], *version, startTime)
147-
149+
providerToGenerate = setProvider(*forceProvider, *version, productsForVersion[0], startTime)
148150
providerToGenerate.CopyCommonFiles(*outputPath, generateCode, generateDocs)
149151

150152
log.Printf("Compiling common files for terraform")
@@ -155,7 +157,7 @@ func main() {
155157
}
156158
}
157159

158-
func GenerateProduct(productChannel chan string, providerToGenerate *provider.Terraform, productsForVersion *[]*api.Product, startTime time.Time, productsToGenerate []string, resourceToGenerate string, generateCode, generateDocs bool) {
160+
func GenerateProduct(productChannel chan string, providerToGenerate provider.Provider, productsForVersion *[]*api.Product, startTime time.Time, productsToGenerate []string, resourceToGenerate string, generateCode, generateDocs bool) {
159161

160162
defer wg.Done()
161163
productName := <-productChannel
@@ -215,8 +217,7 @@ func GenerateProduct(productChannel chan string, providerToGenerate *provider.Te
215217
productApi.Objects = resources
216218
productApi.Validate()
217219

218-
// TODO rewrite: set other providers via flag
219-
providerToGenerate = provider.NewTerraform(productApi, *version, startTime)
220+
providerToGenerate = setProvider(*forceProvider, *version, productApi, startTime)
220221

221222
*productsForVersion = append(*productsForVersion, productApi)
222223

@@ -229,3 +230,13 @@ func GenerateProduct(productChannel chan string, providerToGenerate *provider.Te
229230
providerToGenerate.Generate(*outputPath, productName, resourceToGenerate, generateCode, generateDocs)
230231
}
231232
}
233+
234+
// Sets provider via flag
235+
func setProvider(forceProvider, version string, productApi *api.Product, startTime time.Time) provider.Provider {
236+
switch forceProvider {
237+
case "tgc":
238+
return provider.NewTerraformGoogleConversion(productApi, version, startTime)
239+
default:
240+
return provider.NewTerraform(productApi, version, startTime)
241+
}
242+
}

mmv1/provider/provider.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package provider
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
7+
"github.com/GoogleCloudPlatform/magic-modules/mmv1/api"
8+
)
9+
10+
type Provider interface {
11+
Generate(string, string, string, bool, bool)
12+
CopyCommonFiles(outputFolder string, generateCode, generateDocs bool)
13+
CompileCommonFiles(outputFolder string, products []*api.Product, overridePath string)
14+
}
15+
16+
// Shared constants and functions among the providers
17+
18+
const TERRAFORM_PROVIDER_GA = "github.com/hashicorp/terraform-provider-google"
19+
const TERRAFORM_PROVIDER_BETA = "github.com/hashicorp/terraform-provider-google-beta"
20+
const TERRAFORM_PROVIDER_PRIVATE = "internal/terraform-next"
21+
const RESOURCE_DIRECTORY_GA = "google"
22+
const RESOURCE_DIRECTORY_BETA = "google-beta"
23+
const RESOURCE_DIRECTORY_PRIVATE = "google-private"
24+
25+
// # TODO(nelsonjr): Review all object interfaces and move to private methods
26+
// # that should not be exposed outside the object hierarchy.
27+
func ProviderName(t Provider) string {
28+
return reflect.TypeOf(t).Name()
29+
}
30+
31+
func ImportPathFromVersion(t Provider, v string) string {
32+
var tpg, dir string
33+
switch v {
34+
case "ga":
35+
tpg = TERRAFORM_PROVIDER_GA
36+
dir = RESOURCE_DIRECTORY_GA
37+
case "beta":
38+
tpg = TERRAFORM_PROVIDER_BETA
39+
dir = RESOURCE_DIRECTORY_BETA
40+
default:
41+
tpg = TERRAFORM_PROVIDER_PRIVATE
42+
dir = RESOURCE_DIRECTORY_PRIVATE
43+
}
44+
return fmt.Sprintf("%s/%s", tpg, dir)
45+
}

mmv1/provider/template_data.go

+9
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@ func (td *TemplateData) GenerateSweeperFile(filePath string, resource api.Resour
168168
td.GenerateFile(filePath, templatePath, resource, false, templates...)
169169
}
170170

171+
func (td *TemplateData) GenerateTGCResourceFile(filePath string, resource api.Resource) {
172+
templatePath := "templates/tgc/resource_converter.go.tmpl"
173+
templates := []string{
174+
templatePath,
175+
"templates/terraform/expand_property_method.go.tmpl",
176+
}
177+
td.GenerateFile(filePath, templatePath, resource, true, templates...)
178+
}
179+
171180
func (td *TemplateData) GenerateFile(filePath, templatePath string, input any, goFormat bool, templates ...string) {
172181
// log.Printf("Generating %s", filePath)
173182

mmv1/provider/terraform.go

+8-38
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"os"
2525
"path"
2626
"path/filepath"
27-
"reflect"
2827
"slices"
2928
"strings"
3029
"time"
@@ -35,13 +34,6 @@ import (
3534
"github.com/GoogleCloudPlatform/magic-modules/mmv1/google"
3635
)
3736

38-
const TERRAFORM_PROVIDER_GA = "github.com/hashicorp/terraform-provider-google"
39-
const TERRAFORM_PROVIDER_BETA = "github.com/hashicorp/terraform-provider-google-beta"
40-
const TERRAFORM_PROVIDER_PRIVATE = "internal/terraform-next"
41-
const RESOURCE_DIRECTORY_GA = "google"
42-
const RESOURCE_DIRECTORY_BETA = "google-beta"
43-
const RESOURCE_DIRECTORY_PRIVATE = "google-private"
44-
4537
type Terraform struct {
4638
ResourceCount int
4739

@@ -58,7 +50,7 @@ type Terraform struct {
5850
StartTime time.Time
5951
}
6052

61-
func NewTerraform(product *api.Product, versionName string, startTime time.Time) *Terraform {
53+
func NewTerraform(product *api.Product, versionName string, startTime time.Time) Terraform {
6254
t := Terraform{
6355
ResourceCount: 0,
6456
IAMResourceCount: 0,
@@ -70,14 +62,14 @@ func NewTerraform(product *api.Product, versionName string, startTime time.Time)
7062

7163
t.Product.SetPropertiesBasedOnVersion(&t.Version)
7264
for _, r := range t.Product.Objects {
73-
r.SetCompiler(t.providerName())
74-
r.ImportPath = t.ImportPathFromVersion(versionName)
65+
r.SetCompiler(ProviderName(t))
66+
r.ImportPath = ImportPathFromVersion(t, versionName)
7567
}
7668

77-
return &t
69+
return t
7870
}
7971

80-
func (t *Terraform) Generate(outputFolder, productPath, resourceToGenerate string, generateCode, generateDocs bool) {
72+
func (t Terraform) Generate(outputFolder, productPath, resourceToGenerate string, generateCode, generateDocs bool) {
8173
if err := os.MkdirAll(outputFolder, os.ModePerm); err != nil {
8274
log.Println(fmt.Errorf("error creating output directory %v: %v", outputFolder, err))
8375
}
@@ -273,7 +265,7 @@ func (t *Terraform) FullResourceName(object api.Resource) string {
273265
}
274266

275267
func (t Terraform) CopyCommonFiles(outputFolder string, generateCode, generateDocs bool) {
276-
log.Printf("Copying common files for %s", t.providerName())
268+
log.Printf("Copying common files for %s", ProviderName(t))
277269

278270
files := t.getCommonCopyFiles(t.TargetVersionName, generateCode, generateDocs)
279271
t.CopyFileList(outputFolder, files)
@@ -565,8 +557,8 @@ func (t Terraform) replaceImportPath(outputFolder, target string) {
565557

566558
data := string(sourceByte)
567559

568-
gaImportPath := t.ImportPathFromVersion("ga")
569-
betaImportPath := t.ImportPathFromVersion("beta")
560+
gaImportPath := ImportPathFromVersion(t, "ga")
561+
betaImportPath := ImportPathFromVersion(t, "beta")
570562

571563
if strings.Contains(data, betaImportPath) {
572564
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)
@@ -607,22 +599,6 @@ func (t Terraform) replaceImportPath(outputFolder, target string) {
607599
}
608600
}
609601

610-
func (t Terraform) ImportPathFromVersion(v string) string {
611-
var tpg, dir string
612-
switch v {
613-
case "ga":
614-
tpg = TERRAFORM_PROVIDER_GA
615-
dir = RESOURCE_DIRECTORY_GA
616-
case "beta":
617-
tpg = TERRAFORM_PROVIDER_BETA
618-
dir = RESOURCE_DIRECTORY_BETA
619-
default:
620-
tpg = TERRAFORM_PROVIDER_PRIVATE
621-
dir = RESOURCE_DIRECTORY_PRIVATE
622-
}
623-
return fmt.Sprintf("%s/%s", tpg, dir)
624-
}
625-
626602
func (t Terraform) ProviderFromVersion() string {
627603
var dir string
628604
switch t.TargetVersionName {
@@ -708,12 +684,6 @@ func (t *Terraform) generateResourcesForVersion(products []*api.Product) {
708684
}
709685
}
710686

711-
// # TODO(nelsonjr): Review all object interfaces and move to private methods
712-
// # that should not be exposed outside the object hierarchy.
713-
func (t Terraform) providerName() string {
714-
return reflect.TypeOf(t).Name()
715-
}
716-
717687
// # Adapted from the method used in templating
718688
// # See: mmv1/compile/core.rb
719689
func commentBlock(text []string, lang string) string {

0 commit comments

Comments
 (0)