Skip to content

Commit 0b5436e

Browse files
A new datasource for fetching the list of alloydb supported database flags in a location. (#7377) (#14197)
* Added validation for "type" in cloud_sql_user_resource for preventing user from setting "password" or "host" for CLOUD_IAM_USER and CLOUD_IAM_SERVICE_ACCOUNT user types. * Removed validation and added documentation to prevent setting of host or password field for CLOUD_IAM_USER and CLOUD_IAM_SERVICE_ACCOUNT * added new datasource for fetching all the alloydb supported database flags in a location. * added new datasource for fetching all the alloydb supported database flags in a location. * Using go client for api calls * using v1 and v1beta go clients for GA and beta providers respectively Signed-off-by: Modular Magician <[email protected]>
1 parent 8a6f9a3 commit 0b5436e

9 files changed

+364
-1
lines changed

.changelog/7377.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-datasource
2+
A new datasource for fetching the list of alloydb supported database flags in a location.
3+
```

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module github.com/hashicorp/terraform-provider-google
22
go 1.18
33

44
require (
5+
cloud.google.com/go/alloydb v0.2.0
56
cloud.google.com/go/bigtable v1.17.0
67
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.34.0
78
github.com/apparentlymart/go-cidr v1.1.0

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
6161
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
6262
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.34.0 h1:o7t+hPFv+Ax5O2vxzIH7dEtvlWA7JJOlOd7mWFvMa6s=
6363
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.34.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k=
64+
cloud.google.com/go/alloydb v0.2.0 h1:bAFRzwC4q/+eiz5FpckFbT0IZozJMTjVcrDdRCpIdJI=
65+
cloud.google.com/go/alloydb v0.2.0/go.mod h1:wZv2QDg2+hJ/V4lXsUdnSm8ygdMKBVWeioAsERSBLbE=
6466
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
6567
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
6668
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=

google/config.go

+12
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/sirupsen/logrus"
2020
"google.golang.org/api/option"
2121

22+
alloydb "cloud.google.com/go/alloydb/apiv1"
2223
"golang.org/x/oauth2"
2324
googleoauth "golang.org/x/oauth2/google"
2425
appengine "google.golang.org/api/appengine/v1"
@@ -1346,6 +1347,17 @@ func (c *Config) NewSqlAdminClient(userAgent string) *sqladmin.Service {
13461347
return clientSqlAdmin
13471348
}
13481349

1350+
func (c *Config) NewAlloydbClient(userAgent string) *alloydb.AlloyDBAdminClient {
1351+
alloydbBasePath := RemoveBasePathVersion(RemoveBasePathVersion(c.AlloydbBasePath))
1352+
log.Printf("[INFO] Instantiating Alloydb client for path %s", alloydbBasePath)
1353+
clientAlloydb, err := alloydb.NewAlloyDBAdminRESTClient(c.context, option.WithHTTPClient(c.Client), option.WithUserAgent(userAgent), option.WithEndpoint(alloydbBasePath))
1354+
if err != nil {
1355+
log.Printf("[WARN] Error creating client storage: %s", err)
1356+
return nil
1357+
}
1358+
return clientAlloydb
1359+
}
1360+
13491361
func (c *Config) NewPubsubClient(userAgent string) *pubsub.Service {
13501362
pubsubClientBasePath := RemoveBasePathVersion(c.PubsubBasePath)
13511363
log.Printf("[INFO] Instantiating Google Pubsub client for path %s", pubsubClientBasePath)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
package google
2+
3+
import (
4+
alloydb "cloud.google.com/go/alloydb/apiv1"
5+
alloydbpb "cloud.google.com/go/alloydb/apiv1/alloydbpb"
6+
"fmt"
7+
gax "github.com/googleapis/gax-go/v2"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
"google.golang.org/api/iterator"
10+
)
11+
12+
func DataSourceAlloydbSupportedDatabaseFlags() *schema.Resource {
13+
14+
return &schema.Resource{
15+
Read: dataSourceAlloydbSupportedDatabaseFlagsRead,
16+
17+
Schema: map[string]*schema.Schema{
18+
"project": {
19+
Type: schema.TypeString,
20+
Optional: true,
21+
Description: `Project ID of the project.`,
22+
},
23+
"location": {
24+
Type: schema.TypeString,
25+
Required: true,
26+
Description: `The canonical id for the location. For example: "us-east1".`,
27+
},
28+
"supported_database_flags": {
29+
Type: schema.TypeList,
30+
Computed: true,
31+
Elem: &schema.Resource{
32+
Schema: map[string]*schema.Schema{
33+
"name": {
34+
Type: schema.TypeString,
35+
Computed: true,
36+
Optional: true,
37+
Description: `The name of the flag resource, following Google Cloud conventions, e.g.: * projects/{project}/locations/{location}/flags/{flag} This field currently has no semantic meaning.`,
38+
},
39+
"flag_name": {
40+
Type: schema.TypeString,
41+
Computed: true,
42+
Optional: true,
43+
Description: `The name of the database flag, e.g. "max_allowed_packets". The is a possibly key for the Instance.database_flags map field.`,
44+
},
45+
"value_type": {
46+
Type: schema.TypeString,
47+
Computed: true,
48+
Optional: true,
49+
Description: `ValueType describes the semantic type of the value that the flag accepts. The supported values are:- 'VALUE_TYPE_UNSPECIFIED', 'STRING', 'INTEGER', 'FLOAT', 'NONE'.`,
50+
},
51+
"accepts_multiple_values": {
52+
Type: schema.TypeBool,
53+
Computed: true,
54+
Optional: true,
55+
Description: `Whether the database flag accepts multiple values. If true, a comma-separated list of stringified values may be specified.`,
56+
},
57+
"supported_db_versions": {
58+
Type: schema.TypeList,
59+
Computed: true,
60+
Optional: true,
61+
Description: `Major database engine versions for which this flag is supported. Supported values are:- 'DATABASE_VERSION_UNSPECIFIED', and 'POSTGRES_14'.`,
62+
Elem: &schema.Schema{Type: schema.TypeString},
63+
},
64+
"requires_db_restart": {
65+
Type: schema.TypeBool,
66+
Computed: true,
67+
Optional: true,
68+
Description: `Whether setting or updating this flag on an Instance requires a database restart. If a flag that requires database restart is set, the backend will automatically restart the database (making sure to satisfy any availability SLO's).`,
69+
},
70+
"string_restrictions": {
71+
Type: schema.TypeList,
72+
Computed: true,
73+
Optional: true,
74+
Description: `Restriction on STRING type value.`,
75+
MaxItems: 1,
76+
Elem: &schema.Resource{
77+
Schema: map[string]*schema.Schema{
78+
"allowed_values": {
79+
Type: schema.TypeList,
80+
Computed: true,
81+
Optional: true,
82+
Description: `The list of allowed values, if bounded. This field will be empty if there is a unbounded number of allowed values.`,
83+
Elem: &schema.Schema{Type: schema.TypeString},
84+
},
85+
},
86+
},
87+
},
88+
"integer_restrictions": {
89+
Type: schema.TypeList,
90+
Computed: true,
91+
Optional: true,
92+
Description: `Restriction on INTEGER type value.`,
93+
MaxItems: 1,
94+
Elem: &schema.Resource{
95+
Schema: map[string]*schema.Schema{
96+
"min_value": {
97+
Type: schema.TypeInt,
98+
Computed: true,
99+
Optional: true,
100+
Description: `The minimum value that can be specified, if applicable.`,
101+
},
102+
"max_value": {
103+
Type: schema.TypeInt,
104+
Computed: true,
105+
Optional: true,
106+
Description: `The maximum value that can be specified, if applicable.`,
107+
},
108+
},
109+
},
110+
},
111+
},
112+
},
113+
},
114+
},
115+
}
116+
}
117+
118+
func dataSourceAlloydbSupportedDatabaseFlagsRead(d *schema.ResourceData, meta interface{}) error {
119+
config := meta.(*Config)
120+
userAgent, err := generateUserAgentString(d, config.UserAgent)
121+
if err != nil {
122+
return err
123+
}
124+
project, err := getProject(d, config)
125+
if err != nil {
126+
return fmt.Errorf("Error fetching project: %s", err)
127+
}
128+
billingProject := project
129+
if bp, err := getBillingProject(d, config); err == nil {
130+
billingProject = bp
131+
}
132+
location := ""
133+
if v, ok := d.GetOk("location"); ok {
134+
location = v.(string)
135+
}
136+
if location == "" {
137+
return fmt.Errorf("Location cannot be empty")
138+
}
139+
var supportedDatabaseFlagIterator *alloydb.SupportedDatabaseFlagIterator
140+
dbFlagsReq := new(alloydbpb.ListSupportedDatabaseFlagsRequest)
141+
alloydbClient := config.NewAlloydbClient(userAgent)
142+
if alloydbClient == nil {
143+
return fmt.Errorf("Failed to call the API to fetch the supported database flags")
144+
}
145+
err = nil
146+
err = retryTime(func() error {
147+
url := fmt.Sprintf("v1/projects/%s/locations/%s/supportedDatabaseFlags", billingProject, location)
148+
supportedDatabaseFlagIterator = alloydbClient.ListSupportedDatabaseFlags(config.context, dbFlagsReq, gax.WithPath(url))
149+
return nil
150+
}, 5)
151+
if err != nil {
152+
return handleNotFoundError(err, d, fmt.Sprintf("Supported Database flags %q", d.Id()))
153+
}
154+
155+
var supportedDatabaseFlags []map[string]interface{}
156+
for {
157+
supportedDatabaseFlag := make(map[string]interface{})
158+
flag, err := supportedDatabaseFlagIterator.Next()
159+
if err == iterator.Done {
160+
break
161+
}
162+
if err != nil {
163+
return fmt.Errorf(fmt.Sprintf("Failed to fetch the supported database flags for the provided location: %s", location))
164+
}
165+
if flag.Name != "" {
166+
supportedDatabaseFlag["name"] = flag.Name
167+
}
168+
if flag.FlagName != "" {
169+
supportedDatabaseFlag["flag_name"] = flag.FlagName
170+
}
171+
supportedDatabaseFlag["value_type"] = flag.ValueType.String()
172+
supportedDatabaseFlag["accepts_multiple_values"] = flag.AcceptsMultipleValues
173+
supportedDatabaseFlag["requires_db_restart"] = flag.RequiresDbRestart
174+
if flag.SupportedDbVersions != nil {
175+
dbVersions := make([]string, 0, len(flag.SupportedDbVersions))
176+
for _, supDbVer := range flag.SupportedDbVersions {
177+
dbVersions = append(dbVersions, supDbVer.String())
178+
}
179+
supportedDatabaseFlag["supported_db_versions"] = dbVersions
180+
}
181+
182+
if flag.Restrictions != nil {
183+
if stringRes, ok := flag.Restrictions.(*alloydbpb.SupportedDatabaseFlag_StringRestrictions_); ok {
184+
restrictions := make([]map[string][]string, 0, 1)
185+
fetchedAllowedValues := stringRes.StringRestrictions.AllowedValues
186+
if fetchedAllowedValues != nil {
187+
allowedValues := make([]string, 0, len(fetchedAllowedValues))
188+
for _, val := range fetchedAllowedValues {
189+
allowedValues = append(allowedValues, val)
190+
}
191+
stringRestrictions := map[string][]string{
192+
"allowed_values": allowedValues,
193+
}
194+
restrictions = append(restrictions, stringRestrictions)
195+
supportedDatabaseFlag["string_restrictions"] = restrictions
196+
}
197+
}
198+
if integerRes, ok := flag.Restrictions.(*alloydbpb.SupportedDatabaseFlag_IntegerRestrictions_); ok {
199+
restrictions := make([]map[string]int64, 0, 1)
200+
minValue := integerRes.IntegerRestrictions.MinValue
201+
maxValue := integerRes.IntegerRestrictions.MaxValue
202+
integerRestrictions := map[string]int64{
203+
"min_value": minValue.GetValue(),
204+
"max_value": maxValue.GetValue(),
205+
}
206+
restrictions = append(restrictions, integerRestrictions)
207+
supportedDatabaseFlag["integer_restrictions"] = restrictions
208+
}
209+
}
210+
supportedDatabaseFlags = append(supportedDatabaseFlags, supportedDatabaseFlag)
211+
}
212+
if err := d.Set("supported_database_flags", supportedDatabaseFlags); err != nil {
213+
return fmt.Errorf("Error setting supported_database_flags: %s", err)
214+
}
215+
d.SetId(fmt.Sprintf("projects/%s/locations/%s/supportedDbFlags", project, location))
216+
return nil
217+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package google
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"strconv"
7+
"testing"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
11+
)
12+
13+
func TestAccDataSourceAlloydbSupportedDatabaseFlags_basic(t *testing.T) {
14+
t.Parallel()
15+
16+
context := map[string]interface{}{
17+
"random_suffix": RandString(t, 10),
18+
}
19+
20+
VcrTest(t, resource.TestCase{
21+
PreCheck: func() { testAccPreCheck(t) },
22+
Providers: TestAccProviders,
23+
CheckDestroy: testAccSqlDatabaseDestroyProducer(t),
24+
Steps: []resource.TestStep{
25+
{
26+
Config: testAccDataSourceAlloydbSupportedDatabaseFlags_basic(context),
27+
Check: resource.ComposeTestCheckFunc(
28+
validateAlloydbSupportedDatabaseFlagsResult(
29+
"data.google_alloydb_supported_database_flags.qa",
30+
),
31+
),
32+
},
33+
},
34+
})
35+
}
36+
37+
func testAccDataSourceAlloydbSupportedDatabaseFlags_basic(context map[string]interface{}) string {
38+
return Nprintf(`
39+
data "google_alloydb_supported_database_flags" "qa"{
40+
location = "us-central1"
41+
}
42+
`, context)
43+
}
44+
45+
func validateAlloydbSupportedDatabaseFlagsResult(dataSourceName string) func(*terraform.State) error {
46+
return func(s *terraform.State) error {
47+
ds, ok := s.RootModule().Resources[dataSourceName]
48+
if !ok {
49+
return fmt.Errorf("can't find %s in state", dataSourceName)
50+
}
51+
52+
var dsAttr map[string]string
53+
dsAttr = ds.Primary.Attributes
54+
55+
totalFlags, err := strconv.Atoi(dsAttr["supported_database_flags.#"])
56+
if err != nil {
57+
return errors.New("Couldn't convert length of flags list to integer")
58+
}
59+
if totalFlags == 0 {
60+
return errors.New("No supported database flags are fetched from location 'us-central1'")
61+
}
62+
for i := 0; i < totalFlags; i++ {
63+
if dsAttr["supported_database_flags."+strconv.Itoa(i)+".name"] == "" {
64+
return errors.New("name parameter is not set for the flag")
65+
}
66+
if dsAttr["supported_database_flags."+strconv.Itoa(i)+".flag_name"] == "" {
67+
return errors.New("flag_name parameter is not set for the flag")
68+
}
69+
if len(dsAttr["supported_database_flags."+strconv.Itoa(i)+".string_restrictions"]) > 0 && len(dsAttr["supported_database_flags."+strconv.Itoa(i)+".integer_restrictions"]) > 0 {
70+
return errors.New("Both string restriction and integer restriction cannot be set for a union restriction field")
71+
}
72+
}
73+
return nil
74+
}
75+
}

google/data_source_sql_databases_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func checkDatabaseFieldsMatchForDataSourceStateAndResourceState(dsAttr, rsAttr m
120120
}
121121

122122
if index == "-1" {
123-
return errors.New("The newly created intance is not found in the data source")
123+
return errors.New("The newly created instance is not found in the data source")
124124
}
125125

126126
errMsg := ""

google/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ func Provider() *schema.Provider {
579579
"google_access_approval_organization_service_account": DataSourceAccessApprovalOrganizationServiceAccount(),
580580
"google_access_approval_project_service_account": DataSourceAccessApprovalProjectServiceAccount(),
581581
"google_active_folder": DataSourceGoogleActiveFolder(),
582+
"google_alloydb_supported_database_flags": DataSourceAlloydbSupportedDatabaseFlags(),
582583
"google_artifact_registry_repository": DataSourceArtifactRegistryRepository(),
583584
"google_app_engine_default_service_account": DataSourceGoogleAppEngineDefaultServiceAccount(),
584585
"google_beyondcorp_app_connection": DataSourceGoogleBeyondcorpAppConnection(),

0 commit comments

Comments
 (0)