Skip to content

Commit 88a3b9b

Browse files
Lakshman single datasource generation (#14598)
1 parent b17bac0 commit 88a3b9b

7 files changed

Lines changed: 158 additions & 40 deletions

File tree

mmv1/api/resource.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ type Resource struct {
226226
// If true, resource is not importable
227227
ExcludeImport bool `yaml:"exclude_import,omitempty"`
228228

229+
// If true, resource should be autogenerated as a data source
230+
GenerateDatasource bool `yaml:"generate_datasource,omitempty"`
231+
229232
// If true, skip sweeper generation for this resource
230233
ExcludeSweeper bool `yaml:"exclude_sweeper,omitempty"`
231234

@@ -1993,6 +1996,44 @@ func urlContainsOnlyAllowedKeys(templateURL string, allowedKeys []string) bool {
19931996
return true
19941997
}
19951998

1999+
func (r Resource) ShouldGenerateSingularDataSource() bool {
2000+
return r.GenerateDatasource
2001+
}
2002+
2003+
// DatasourceOptionalFields returns a list of fields from the resource's URI
2004+
// that should be marked as "Required".
2005+
func (r Resource) DatasourceRequiredFields() []string {
2006+
requiredFields := []string{}
2007+
uriParts := strings.Split(r.SelfLink, "/")
2008+
2009+
for _, part := range uriParts {
2010+
if strings.HasPrefix(part, "{{") && strings.HasSuffix(part, "}}") {
2011+
field := strings.TrimSuffix(strings.TrimPrefix(part, "{{"), "}}")
2012+
if field != "region" && field != "project" && field != "zone" {
2013+
requiredFields = append(requiredFields, field)
2014+
}
2015+
}
2016+
}
2017+
return requiredFields
2018+
}
2019+
2020+
// DatasourceOptionalFields returns a list of fields from the resource's URI
2021+
// that should be marked as "Optional".
2022+
func (r Resource) DatasourceOptionalFields() []string {
2023+
optionalFields := []string{}
2024+
uriParts := strings.Split(r.SelfLink, "/")
2025+
2026+
for _, part := range uriParts {
2027+
if strings.HasPrefix(part, "{{") && strings.HasSuffix(part, "}}") {
2028+
field := strings.TrimSuffix(strings.TrimPrefix(part, "{{"), "}}")
2029+
if field == "region" || field == "project" || field == "zone" {
2030+
optionalFields = append(optionalFields, field)
2031+
}
2032+
}
2033+
}
2034+
return optionalFields
2035+
}
2036+
19962037
func (r Resource) ShouldGenerateSweepers() bool {
19972038
if !r.ExcludeSweeper && !utils.IsEmpty(r.Sweeper) {
19982039
return true

mmv1/products/iap/Client.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ self_link: '{{brand}}/identityAwareProxyClients/{{client_id}}'
3333
immutable: true
3434
import_format:
3535
- '{{brand}}/identityAwareProxyClients/{{client_id}}'
36+
generate_datasource: true
3637
timeouts:
3738
insert_minutes: 20
3839
update_minutes: 20

mmv1/provider/template_data.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ func (td *TemplateData) GenerateMetadataFile(filePath string, resource api.Resou
9393
td.GenerateFile(filePath, templatePath, resource, false, templates...)
9494
}
9595

96+
func (td *TemplateData) GenerateDataSourceFile(filePath string, resource api.Resource) {
97+
templatePath := "templates/terraform/datasource.go.tmpl"
98+
templates := []string{
99+
templatePath,
100+
}
101+
td.GenerateFile(filePath, templatePath, resource, true, templates...)
102+
}
103+
96104
func (td *TemplateData) GenerateProductFile(filePath string, product api.Product) {
97105
templatePath := "templates/terraform/product.go.tmpl"
98106
templates := []string{

mmv1/provider/terraform.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ func (t *Terraform) GenerateObject(object api.Resource, outputFolder, productPat
107107
// log.Printf("Generating %s tests", object.Name)
108108
t.GenerateResourceTests(object, *templateData, outputFolder)
109109
t.GenerateResourceSweeper(object, *templateData, outputFolder)
110+
t.GenerateSingularDataSource(object, *templateData, outputFolder)
110111
// log.Printf("Generating %s metadata", object.Name)
111112
t.GenerateResourceMetadata(object, *templateData, outputFolder)
112113
}
@@ -188,6 +189,20 @@ func (t *Terraform) GenerateResourceSweeper(object api.Resource, templateData Te
188189
templateData.GenerateSweeperFile(targetFilePath, object)
189190
}
190191

192+
func (t *Terraform) GenerateSingularDataSource(object api.Resource, templateData TemplateData, outputFolder string) {
193+
if !object.ShouldGenerateSingularDataSource() {
194+
return
195+
}
196+
197+
productName := t.Product.ApiName
198+
targetFolder := path.Join(outputFolder, t.FolderName(), "services", productName)
199+
if err := os.MkdirAll(targetFolder, os.ModePerm); err != nil {
200+
log.Println(fmt.Errorf("error creating parent directory %v: %v", targetFolder, err))
201+
}
202+
targetFilePath := path.Join(targetFolder, fmt.Sprintf("data_source_%s.go", t.ResourceGoFilename(object)))
203+
templateData.GenerateDataSourceFile(targetFilePath, object)
204+
}
205+
191206
// GenerateProduct creates the product.go file for a given service directory.
192207
// This will be used to seed the directory and add a package-level comment
193208
// specific to the product.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{{/* The license inside this block applies to this file
2+
Copyright 2024 Google LLC. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License. */ -}}
15+
// Copyright (c) HashiCorp, Inc.
16+
// SPDX-License-Identifier: MPL-2.0
17+
18+
{{$.CodeHeader TemplatePath}}
19+
package {{ lower $.ProductMetadata.Name }}
20+
21+
import (
22+
23+
"fmt"
24+
"log"
25+
"net/http"
26+
"reflect"
27+
{{- if $.SupportsIndirectUserProjectOverride }}
28+
"regexp"
29+
{{- end }}
30+
{{- if or (and (not $.Immutable) ($.UpdateMask)) $.LegacyLongFormProject }}
31+
"strings"
32+
{{- end }}
33+
"time"
34+
35+
{{/* # We list all the v2 imports here, because we run 'goimports' to guess the correct */}}
36+
{{/* # set of imports, which will never guess the major version correctly. */}}
37+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
38+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
39+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
40+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
41+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
42+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
43+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
44+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
45+
"github.com/hashicorp/go-cty/cty"
46+
47+
"{{ $.ImportPath }}/tpgresource"
48+
transport_tpg "{{ $.ImportPath }}/transport"
49+
"{{ $.ImportPath }}/verify"
50+
51+
{{ if $.FlattenedProperties }}
52+
"google.golang.org/api/googleapi"
53+
{{- end}}
54+
)
55+
56+
func DataSource{{ .ResourceName -}}() *schema.Resource {
57+
rs := Resource{{ .ResourceName -}}().Schema
58+
59+
dsSchema := tpgresource.DatasourceSchemaFromResourceSchema(rs)
60+
61+
// Set 'Required' schema elements
62+
tpgresource.AddRequiredFieldsToSchema(dsSchema, {{range $index, $field := .DatasourceRequiredFields}}{{if gt $index 0}}, {{end}}{{printf "%q" $field}}{{end}})
63+
64+
// Set 'Optional' schema elements
65+
tpgresource.AddOptionalFieldsToSchema(dsSchema, {{range $index, $field := .DatasourceOptionalFields}}{{if gt $index 0}}, {{end}}{{printf "%q" $field}}{{end}})
66+
67+
return &schema.Resource{
68+
Read: dataSource{{ $.ResourceName -}}Read,
69+
Schema: dsSchema,
70+
}
71+
}
72+
73+
func dataSource{{ $.ResourceName -}}Read(d *schema.ResourceData, meta interface{}) error {
74+
config := meta.(*transport_tpg.Config)
75+
76+
id, err := tpgresource.ReplaceVars{{if $.LegacyLongFormProject -}}ForId{{ end -}}(d, config, "{{$.SelfLinkUri}}{{$.ReadQueryParams}}")
77+
if err != nil {
78+
return err
79+
}
80+
d.SetId(id)
81+
82+
err = resource{{ $.ResourceName -}}Read(d, meta)
83+
if err != nil {
84+
return err
85+
}
86+
87+
if d.Id() == "" {
88+
return fmt.Errorf("%s not found", id)
89+
}
90+
91+
return nil
92+
}

mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
151151
"google_iam_testable_permissions": resourcemanager.DataSourceGoogleIamTestablePermissions(),
152152
"google_iam_workload_identity_pool": iambeta.DataSourceIAMBetaWorkloadIdentityPool(),
153153
"google_iam_workload_identity_pool_provider": iambeta.DataSourceIAMBetaWorkloadIdentityPoolProvider(),
154-
"google_iap_client": iap.DataSourceGoogleIapClient(),
154+
"google_iap_client": iap.DataSourceIapClient(),
155155
"google_kms_crypto_key": kms.DataSourceGoogleKmsCryptoKey(),
156156
"google_kms_crypto_keys": kms.DataSourceGoogleKmsCryptoKeys(),
157157
"google_kms_crypto_key_version": kms.DataSourceGoogleKmsCryptoKeyVersion(),

mmv1/third_party/terraform/services/iap/data_source_iap_client.go

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)