Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for string --> object map for DCL resources #10039

Merged
merged 8 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mmv1/third_party/terraform/go.mod.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.20

require (
cloud.google.com/go/bigtable v1.19.0
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0
github.com/apparentlymart/go-cidr v1.1.0
github.com/davecgh/go-spew v1.1.1
github.com/dnaeon/go-vcr v1.0.1
Expand Down
2 changes: 2 additions & 0 deletions mmv1/third_party/terraform/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,5 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0 h1:eSOBYPZVnU2fZul9sAJFGLVCgv6stNVKkmsogKF7UeY=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k=
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,17 @@ func TestAccGKEHubFeatureMembership_gkehubFeaturePolicyController(t *testing.T)
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccGKEHubFeatureMembership_policycontrollerUpdateMaps(context),
Check: resource.ComposeTestCheckFunc(
testAccCheckGkeHubFeatureMembershipPresent(t, fmt.Sprintf("tf-test-gkehub%s", context["random_suffix"]), "global", "policycontroller", fmt.Sprintf("tf-test1%s", context["random_suffix"])),
),
},
{
ResourceName: "google_gke_hub_feature_membership.feature_member",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
Expand Down Expand Up @@ -1064,9 +1075,92 @@ resource "google_gke_hub_feature_membership" "feature_member" {
"PROMETHEUS"
]
}
deployment_configs {
component_name = "admission"
replica_count = 3
pod_affinity = "ANTI_AFFINITY"
container_resources {
limits {
memory = "1Gi"
cpu = "1.5"
}
requests {
memory = "500Mi"
cpu = "150m"
}
}
pod_tolerations {
key = "key1"
operator = "Equal"
value = "value1"
effect = "NoSchedule"
}
}
deployment_configs {
component_name = "mutation"
replica_count = 3
pod_affinity = "ANTI_AFFINITY"
}
policy_content {
template_library {
installation = "NOT_INSTALLED"
installation = "ALL"
}
bundles {
bundle_name = "pci-dss-v3.2.1"
exempted_namespaces = ["sample-namespace"]
}
bundles {
bundle_name = "nist-sp-800-190"
}
}
}
version = "1.17.0"
}
}
`, context)
}

func testAccGKEHubFeatureMembership_policycontrollerUpdateMaps(context map[string]interface{}) string {
return gkeHubFeatureProjectSetup(context) + gkeHubClusterMembershipSetup(context) + acctest.Nprintf(`
resource "google_gke_hub_feature" "feature" {
project = google_project.project.project_id
name = "policycontroller"
location = "global"
depends_on = [google_project_service.container, google_project_service.gkehub, google_project_service.poco]
}

resource "google_gke_hub_feature_membership" "feature_member" {
project = google_project.project.project_id
location = "global"
feature = google_gke_hub_feature.feature.name
membership = google_gke_hub_membership.membership.membership_id
policycontroller {
policy_controller_hub_config {
install_spec = "INSTALL_SPEC_SUSPENDED"
constraint_violation_limit = 50
referential_rules_enabled = true
log_denies_enabled = true
mutation_enabled = true
monitoring {
backends = [
"PROMETHEUS"
]
}
deployment_configs {
component_name = "admission"
pod_affinity = "NO_AFFINITY"
}
deployment_configs {
component_name = "audit"
container_resources {
limits {
memory = "1Gi"
cpu = "1.5"
}
requests {
memory = "500Mi"
cpu = "150m"
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tpgtools/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.20

require (
bitbucket.org/creachadair/stringset v0.0.11
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0
github.com/golang/glog v1.1.2
github.com/hashicorp/hcl v1.0.0
github.com/kylelemons/godebug v1.1.0
Expand Down
8 changes: 2 additions & 6 deletions tpgtools/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdi
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.60.0 h1:RFZs9I3tXewC7cJf8RKbUMpQZO6jWZ9SHSnNd+auxsQ=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.60.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.61.0 h1:IAr9UlYbxURIYABRMagXXo8pDlkFNFFXWz5J2+srrnc=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.61.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0 h1:s4Y6r6RrYLBnqosGXLwR0h1Gqr0VT3wgd6rqvHsD9OE=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0 h1:eSOBYPZVnU2fZul9sAJFGLVCgv6stNVKkmsogKF7UeY=
github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
Expand Down
1 change: 1 addition & 0 deletions tpgtools/override.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ const (
CustomListSize = "CUSTOM_LIST_SIZE_CONSTRAINT"
CustomDefault = "CUSTOM_DEFAULT"
CustomSchemaValues = "CUSTOM_SCHEMA_VALUES"
ComplexMapKey = "COMPLEX_MAP_KEY_NAME"
)

// Overrides represents the type a resource's override file can be marshalled
Expand Down
5 changes: 5 additions & 0 deletions tpgtools/override_details.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,8 @@ type StateUpgradeDetails struct {
// The current schema version
SchemaVersion int
}

type ComplexMapKeyDetails struct {
// The name of the key as exposed by Terraform
KeyName string
}
8 changes: 8 additions & 0 deletions tpgtools/overrides/gkehub/beta/feature_membership.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,11 @@
details:
functions:
- tpgresource.DefaultProviderProject
- type: COMPLEX_MAP_KEY_NAME
field: policycontroller.policy_controller_hub_config.policy_content.bundles
details:
keyname: bundle_name
- type: COMPLEX_MAP_KEY_NAME
field: policycontroller.policy_controller_hub_config.deployment_configs
details:
keyname: component_name
10 changes: 9 additions & 1 deletion tpgtools/overrides/gkehub/feature_membership.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@
field: mesh.control_plane
details:
message: >-
Deprecated in favor of the `management` field
Deprecated in favor of the `management` field
- type: COMPLEX_MAP_KEY_NAME
field: policycontroller.policy_controller_hub_config.policy_content.bundles
details:
keyname: bundle_name
- type: COMPLEX_MAP_KEY_NAME
field: policycontroller.policy_controller_hub_config.deployment_configs
details:
keyname: component_name
60 changes: 57 additions & 3 deletions tpgtools/property.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ type Property struct {
// Sub-properties of nested objects or arrays with nested objects
Properties []Property

// If this is a complex map type, this string represents the name of the
// field that the key to the map can be set with
ComplexMapKeyName string

// Reference to the parent resource.
// note: "Properties" will not be available.
resource *Resource
Expand Down Expand Up @@ -198,13 +202,23 @@ func (p Property) ObjectType() string {
}

func (p Property) IsArray() bool {
return (p.Type.String() == SchemaTypeList || p.Type.String() == SchemaTypeSet) && !p.Type.IsObject()
return (p.Type.String() == SchemaTypeList || p.Type.String() == SchemaTypeSet) && !p.Type.IsObject() && !p.IsComplexMap()
}

func (t Type) IsSet() bool {
return t.String() == SchemaTypeSet
}

// Complex map is for maps of string --> object that are supported in DCL but
// not in Terraform. We handle this by adding a `name` field in the Terraform
// schema for the key in the map
func (t Type) IsComplexMap() bool {
if t.typ.AdditionalProperties != nil {
return t.typ.AdditionalProperties.Type != "string"
}
return false
}

// ShouldGenerateNestedSchema returns true if an object's nested schema function should be generated.
func (p Property) ShouldGenerateNestedSchema() bool {
return len(p.Properties) > 0 && !p.Collapsed
Expand Down Expand Up @@ -278,6 +292,9 @@ func buildGetter(p Property, rawGetter string) string {
if p.Type.IsEnumArray() {
return fmt.Sprintf("expand%s%sArray(%s)", p.resource.PathType(), p.PackagePath(), rawGetter)
}
if p.Type.IsComplexMap() {
return fmt.Sprintf("expand%s%sMap(%s)", p.resource.PathType(), p.PackagePath(), rawGetter)
}
if p.Type.typ.Items != nil && p.Type.typ.Items.Type == "string" {
return fmt.Sprintf("tpgdclresource.ExpandStringArray(%s)", rawGetter)
}
Expand Down Expand Up @@ -317,6 +334,9 @@ func (p Property) DefaultStateSetter() string {

return fmt.Sprintf("d.Set(%q, res.%s)", p.Name(), p.PackageName)
case SchemaTypeList, SchemaTypeSet:
if p.IsComplexMap() {
return fmt.Sprintf("d.Set(%q, flatten%s%sMap(res.%s))", p.Name(), p.resource.PathType(), p.PackagePath(), p.PackageName)
}
if p.typ.Items != nil && ((p.typ.Items.Type == "string" && len(p.typ.Items.Enum) == 0) || p.typ.Items.Type == "integer") {
return fmt.Sprintf("d.Set(%q, res.%s)", p.Name(), p.PackageName)
}
Expand Down Expand Up @@ -365,6 +385,9 @@ func (p Property) flattenGetterWithParent(parent string) string {
if p.Type.IsEnumArray() {
return fmt.Sprintf("flatten%s%sArray(obj.%s)", p.resource.PathType(), p.PackagePath(), p.PackageName)
}
if p.Type.IsComplexMap() {
return fmt.Sprintf("flatten%s%sMap(%s.%s)", p.resource.PathType(), p.PackagePath(), parent, p.PackageName)
}
if p.Type.typ.Items != nil && p.Type.typ.Items.Type == "integer" {
return fmt.Sprintf("%s.%s", parent, p.PackageName)
}
Expand All @@ -376,7 +399,6 @@ func (p Property) flattenGetterWithParent(parent string) string {
return fmt.Sprintf("flatten%s%sArray(%s.%s)", p.resource.PathType(), p.PackagePath(), parent, p.PackageName)
}
}

if p.typ.Type == "object" {
return fmt.Sprintf("flatten%s%s(%s.%s)", p.resource.PathType(), p.PackagePath(), parent, p.PackageName)
}
Expand Down Expand Up @@ -651,6 +673,38 @@ func createPropertiesFromSchema(schema *openapi.Schema, typeFetcher *TypeFetcher
p.ElemIsBasicType = true
}
}
// Complex maps are represented as TypeSet but don't have v.Items set.
// Use AdditionalProperties instead, and add an additional `name` field
// that represents the key in the map
if p.Type.IsComplexMap() {
props, err := createPropertiesFromSchema(p.Type.typ.AdditionalProperties, typeFetcher, overrides, resource, &p, location)
if err != nil {
return nil, err
}
cm := ComplexMapKeyDetails{}
cmOk, err := overrides.PropertyOverrideWithDetails(ComplexMapKey, p, &cm, location)
if err != nil {
return nil, fmt.Errorf("failed to decode complex map key name details")
}
if !cmOk {
return nil, fmt.Errorf("failed to find complex map key name for map named: %s", p.Name())
}
keyProp := Property{
title: cm.KeyName,
Type: Type{&openapi.Schema{Type: "string"}},
resource: resource,
parent: &p,
Required: true,
Description: "The name for the key in the map for which this object is mapped to in the API",
}
props = append(props, keyProp)
slevenick marked this conversation as resolved.
Show resolved Hide resolved

p.Properties = props
e := fmt.Sprintf("%s%sSchema()", resource.PathType(), p.PackagePath())
p.Elem = &e
p.ElemIsBasicType = false
p.ComplexMapKeyName = cm.KeyName
}

if !p.Computed {
if stringInSlice(v.Title, schema.Required) {
Expand Down Expand Up @@ -779,7 +833,7 @@ func createPropertiesFromSchema(schema *openapi.Schema, typeFetcher *TypeFetcher
p.ValidateFunc = &vf.Function
}

if p.Type.String() == SchemaTypeSet {
if p.Type.IsSet() {
shf := SetHashFuncDetails{}
shfOk, err := overrides.PropertyOverrideWithDetails(SetHashFunc, p, &shf, location)
if err != nil {
Expand Down
Loading
Loading