Skip to content

Commit afd774d

Browse files
authored
manifest: remove forced replacement with x-kubernetes-preserve-unknown-fields (#2437)
* Do not force replacement on type changes caused by CRD attributes with `x-kubernetes-preserve-unknown-fields` * Add warning for when type changes
1 parent 52bccce commit afd774d

File tree

9 files changed

+104
-27
lines changed

9 files changed

+104
-27
lines changed

.changelog/2437.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note
2+
`kubernetes_manifest`: add TypeCheck for `x-kubernetes-preserve-unknown-fields` to prevent unnecessary replacement
3+
```

manifest/openapi/schema.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64, typeCache *sync
114114
return tftypes.String, nil
115115
}
116116
}
117-
return tftypes.DynamicPseudoType, nil
117+
return tftypes.DynamicPseudoType, nil // this is where DynamicType is set for when an attribute is tagged as 'x-kubernetes-preserve-unknown-fields'
118118

119119
case "array":
120120
switch {

manifest/provider/plan.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,11 @@ func (s *RawProviderServer) PlanResourceChange(ctx context.Context, req *tfproto
459459
if hasChanged {
460460
h, ok := hints[morph.ValueToTypePath(ap).String()]
461461
if ok && h == manifest.PreserveUnknownFieldsLabel {
462-
apm := append(tftypes.NewAttributePath().WithAttributeName("manifest").Steps(), ap.Steps()...)
463-
resp.RequiresReplace = append(resp.RequiresReplace, tftypes.NewAttributePathWithSteps(apm))
462+
resp.Diagnostics = append(resp.Diagnostics, &tfprotov5.Diagnostic{
463+
Severity: tfprotov5.DiagnosticSeverityWarning,
464+
Summary: fmt.Sprintf("The attribute path %v value's type is an x-kubernetes-preserve-unknown-field", morph.ValueToTypePath(ap).String()),
465+
Detail: "Changes to the type may cause some unexpected behavior.",
466+
})
464467
}
465468
}
466469
if isComputed {

manifest/test/acceptance/customresource_x_preserve_unknown_fields_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,39 @@ func TestKubernetesManifest_CustomResource_x_preserve_unknown_fields(t *testing.
114114
"baz": interface{}("42"),
115115
},
116116
})
117+
118+
tfconfig = loadTerraformConfig(t, "x-kubernetes-preserve-unknown-fields/test-cr-3.tf", tfvars)
119+
step1.SetConfig(ctx, string(tfconfig))
120+
step1.Apply(ctx)
121+
122+
s3, err := step1.State(ctx)
123+
if err != nil {
124+
t.Fatalf("Failed to retrieve terraform state: %q", err)
125+
}
126+
tfstate3 := tfstatehelper.NewHelper(s3)
127+
tfstate3.AssertAttributeValues(t, tfstatehelper.AttributeValues{
128+
"kubernetes_manifest.test.object.metadata.name": name,
129+
"kubernetes_manifest.test.object.metadata.namespace": namespace,
130+
"kubernetes_manifest.test.object.spec.count": json.Number("100"),
131+
"kubernetes_manifest.test.object.spec.resources": map[string]interface{}{
132+
"foo": interface{}([]interface{}{"bar"}),
133+
"baz": interface{}("42"),
134+
},
135+
})
136+
137+
tfconfig = loadTerraformConfig(t, "x-kubernetes-preserve-unknown-fields/test-cr-4.tf", tfvars)
138+
step1.SetConfig(ctx, string(tfconfig))
139+
step1.Apply(ctx)
140+
141+
s4, err := step1.State(ctx)
142+
if err != nil {
143+
t.Fatalf("Failed to retrieve terraform state: %q", err)
144+
}
145+
tfstate4 := tfstatehelper.NewHelper(s4)
146+
tfstate4.AssertAttributeValues(t, tfstatehelper.AttributeValues{
147+
"kubernetes_manifest.test.object.metadata.name": name,
148+
"kubernetes_manifest.test.object.metadata.namespace": namespace,
149+
"kubernetes_manifest.test.object.spec.count": json.Number("100"),
150+
"kubernetes_manifest.test.object.spec.resources": false,
151+
})
117152
}

manifest/test/acceptance/testdata/x-kubernetes-preserve-unknown-fields/crd/test.tf

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
resource "kubernetes_manifest" "customresourcedefinition_cephrbdmirrors_ceph_rook_io" {
55
manifest = {
66
apiVersion = "apiextensions.k8s.io/v1"
7-
kind = "CustomResourceDefinition"
7+
kind = "CustomResourceDefinition"
88
metadata = {
99
name = "${var.plural}.${var.group}"
1010
}
1111
spec = {
1212
group = var.group
1313
names = {
14-
kind = var.kind
14+
kind = var.kind
1515
plural = var.plural
1616
}
1717
scope = "Namespaced"
@@ -24,14 +24,14 @@ resource "kubernetes_manifest" "customresourcedefinition_cephrbdmirrors_ceph_roo
2424
spec = {
2525
properties = {
2626
annotations = {
27-
nullable = true
28-
type = "object"
27+
nullable = true
28+
type = "object"
2929
"x-kubernetes-preserve-unknown-fields" = true
3030
}
3131
count = {
3232
maximum = 100
3333
minimum = 1
34-
type = "integer"
34+
type = "integer"
3535
}
3636
peers = {
3737
properties = {
@@ -45,30 +45,29 @@ resource "kubernetes_manifest" "customresourcedefinition_cephrbdmirrors_ceph_roo
4545
type = "object"
4646
}
4747
placement = {
48-
nullable = true
49-
type = "object"
48+
nullable = true
49+
type = "object"
5050
"x-kubernetes-preserve-unknown-fields" = true
5151
}
5252
priorityClassName = {
5353
type = "string"
5454
}
5555
resources = {
56-
nullable = true
57-
type = "object"
56+
nullable = true
5857
"x-kubernetes-preserve-unknown-fields" = true
5958
}
6059
}
6160
type = "object"
6261
}
6362
status = {
64-
type = "object"
63+
type = "object"
6564
"x-kubernetes-preserve-unknown-fields" = true
6665
}
6766
}
6867
type = "object"
6968
}
7069
}
71-
served = true
70+
served = true
7271
storage = true
7372
subresources = {
7473
status = {}

manifest/test/acceptance/testdata/x-kubernetes-preserve-unknown-fields/test-cr-1.tf

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44
resource "kubernetes_manifest" "test" {
55
manifest = {
66
apiVersion = var.group_version
7-
kind = var.kind
7+
kind = var.kind
88
metadata = {
9-
name = var.name
9+
name = var.name
1010
namespace = var.namespace
1111
}
1212
spec = {
13-
count = 100
14-
resources = {
15-
foo = "bar"
16-
}
13+
count = 100
14+
resources = {
15+
foo = "bar"
16+
}
1717
}
1818
}
1919
}

manifest/test/acceptance/testdata/x-kubernetes-preserve-unknown-fields/test-cr-2.tf

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
resource "kubernetes_manifest" "test" {
55
manifest = {
66
apiVersion = var.group_version
7-
kind = var.kind
7+
kind = var.kind
88
metadata = {
9-
name = var.name
9+
name = var.name
1010
namespace = var.namespace
1111
}
1212
spec = {
13-
count = 100
14-
resources = {
15-
foo = "bar"
16-
baz = "42"
17-
}
13+
count = 100
14+
resources = {
15+
foo = "bar"
16+
baz = "42"
17+
}
1818
}
1919
}
2020
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) HashiCorp, Inc.
2+
# SPDX-License-Identifier: MPL-2.0
3+
4+
resource "kubernetes_manifest" "test" {
5+
manifest = {
6+
apiVersion = var.group_version
7+
kind = var.kind
8+
metadata = {
9+
name = var.name
10+
namespace = var.namespace
11+
}
12+
spec = {
13+
count = 100
14+
resources = {
15+
foo = ["bar"]
16+
baz = "42"
17+
}
18+
}
19+
}
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright (c) HashiCorp, Inc.
2+
# SPDX-License-Identifier: MPL-2.0
3+
4+
resource "kubernetes_manifest" "test" {
5+
manifest = {
6+
apiVersion = var.group_version
7+
kind = var.kind
8+
metadata = {
9+
name = var.name
10+
namespace = var.namespace
11+
}
12+
spec = {
13+
count = 100
14+
resources = false
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)