Skip to content

Commit f9aeea9

Browse files
authored
Fix perpetual diff in claim_ref (#1227)
The claim_ref attribute would perpetually show a diff if the PV was created without a claim_ref specified. This is because all PVs gain a claimRef once a PVC binds to it. (This creates the bi-directional link between PV and PVC, and it's done on the Kubernetes API side). To support this, `claim_ref` is now a Computed attribute, and it will update to show the claimRef once a PVC has bound to the PV, (only now it will do so without creating a diff in terraform). Also added extra tests to catch this case and moved claim_ref's flatteners/expanders/tests into the correct files.
1 parent cbd512b commit f9aeea9

7 files changed

+183
-74
lines changed

kubernetes/resource_kubernetes_persistent_volume.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,16 @@ func resourceKubernetesPersistentVolume() *schema.Resource {
118118
Type: schema.TypeList,
119119
Description: "A reference to the persistent volume claim details for statically managed PVs. More Info: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#binding",
120120
Optional: true,
121+
Computed: true,
121122
MaxItems: 1,
122123
Elem: &schema.Resource{
123124
Schema: map[string]*schema.Schema{
124125
"namespace": {
125126
Type: schema.TypeString,
126-
Description: "The namespace of the PersistentVolumeClaim",
127+
Description: "The namespace of the PersistentVolumeClaim. Uses 'default' namespace if none is specified.",
127128
Elem: schema.TypeString,
128-
Required: true,
129+
Optional: true,
130+
Default: "default",
129131
},
130132
"name": {
131133
Type: schema.TypeString,

kubernetes/resource_kubernetes_persistent_volume_claim_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -716,11 +716,6 @@ resource "kubernetes_persistent_volume" "test" {
716716
}
717717
}
718718
}
719-
lifecycle {
720-
ignore_changes = [
721-
spec[0].claim_ref,
722-
]
723-
}
724719
}
725720
resource "kubernetes_persistent_volume_claim" "test" {
726721
wait_until_bound = true

kubernetes/resource_kubernetes_persistent_volume_test.go

Lines changed: 124 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,29 @@ import (
1616
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1717
)
1818

19+
func TestAccKubernetesPersistentVolume_minimal(t *testing.T) {
20+
var conf api.PersistentVolume
21+
randString := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
22+
name := fmt.Sprintf("tf-acc-test-%s", randString)
23+
24+
const resourceName = "kubernetes_persistent_volume.test"
25+
resource.Test(t, resource.TestCase{
26+
PreCheck: func() { testAccPreCheck(t) },
27+
IDRefreshName: resourceName,
28+
ProviderFactories: testAccProviderFactories,
29+
CheckDestroy: testAccCheckKubernetesPersistentVolumeDestroy,
30+
Steps: []resource.TestStep{
31+
{
32+
Config: testAccKubernetesPersistentVolumeConfig_hostPath_basic(name),
33+
Check: resource.ComposeAggregateTestCheckFunc(
34+
testAccCheckKubernetesPersistentVolumeExists(resourceName, &conf),
35+
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.#", "0"),
36+
),
37+
},
38+
},
39+
})
40+
}
41+
1942
func TestAccKubernetesPersistentVolume_azure_basic(t *testing.T) {
2043
var conf api.PersistentVolume
2144
randString := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
@@ -923,12 +946,11 @@ func TestAccKubernetesPersistentVolume_regression(t *testing.T) {
923946
})
924947
}
925948

926-
func TestAccKubernetesPersistentVolume_hostPath_claimRef(t *testing.T) {
927-
var conf api.PersistentVolume
949+
func TestAccKubernetesPersistentVolume_hostpath_claimRef(t *testing.T) {
950+
var conf1, conf2 api.PersistentVolume
951+
var conf3 api.PersistentVolumeClaim
928952
randString := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
929953
name := fmt.Sprintf("tf-acc-test-%s", randString)
930-
claimNamespace := "default"
931-
claimName := "expected-claim-name"
932954

933955
const resourceName = "kubernetes_persistent_volume.test"
934956
resource.Test(t, resource.TestCase{
@@ -937,30 +959,32 @@ func TestAccKubernetesPersistentVolume_hostPath_claimRef(t *testing.T) {
937959
ProviderFactories: testAccProviderFactories,
938960
CheckDestroy: testAccCheckKubernetesPersistentVolumeDestroy,
939961
Steps: []resource.TestStep{
940-
// create a volume without a claimRef
941962
{
942-
Config: testAccKubernetesPersistentVolumeConfig_hostPath_basic(name),
963+
Config: testAccKubernetesPersistentVolumeConfig_hostPath_claimRef_noNamespace(name),
943964
Check: resource.ComposeAggregateTestCheckFunc(
944-
testAccCheckKubernetesPersistentVolumeExists(resourceName, &conf),
945-
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.#", "0"),
965+
testAccCheckKubernetesPersistentVolumeExists(resourceName, &conf1),
966+
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.#", "1"),
967+
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.0.name", name),
968+
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.0.namespace", "default"),
946969
),
947970
},
948-
// set the claimRef and assert it's present
949971
{
950-
Config: testAccKubernetesPersistentVolumeConfig_hostPath_claimRef(name, claimNamespace, claimName),
972+
Config: testAccKubernetesPersistentVolumeConfig_hostPath_claimRef_withNamespace(name),
951973
Check: resource.ComposeAggregateTestCheckFunc(
952-
testAccCheckKubernetesPersistentVolumeExists(resourceName, &conf),
953-
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.#", "1"),
954-
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.0.namespace", claimNamespace),
955-
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.0.name", claimName),
974+
testAccCheckKubernetesPersistentVolumeExists(resourceName, &conf2),
975+
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.0.namespace", name),
976+
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.0.name", name),
977+
testAccCheckKubernetesPersistentVolumeForceNew(&conf1, &conf2, false),
956978
),
957979
},
958-
// unset the claimRef and assert it's absent
959980
{
960-
Config: testAccKubernetesPersistentVolumeConfig_hostPath_basic(name),
981+
Config: testAccKubernetesPersistentVolumeConfig_hostPath_claimRef_withPVC(name),
961982
Check: resource.ComposeAggregateTestCheckFunc(
962-
testAccCheckKubernetesPersistentVolumeExists(resourceName, &conf),
963-
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.#", "0"),
983+
testAccCheckKubernetesPersistentVolumeExists(resourceName, &conf2),
984+
testAccCheckKubernetesPersistentVolumeClaimExists("kubernetes_persistent_volume_claim.test", &conf3),
985+
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.0.namespace", name),
986+
resource.TestCheckResourceAttr(resourceName, "spec.0.claim_ref.0.name", name),
987+
testAccCheckKubernetesPersistentVolumeForceNew(&conf1, &conf2, false),
964988
),
965989
},
966990
},
@@ -1920,11 +1944,71 @@ func testAccKubernetesPersistentVolumeConfig_hostPath_basic(name string) string
19201944
}`, name)
19211945
}
19221946

1923-
func testAccKubernetesPersistentVolumeConfig_hostPath_claimRef(name string, claimNamespace string, claimName string) string {
1947+
func testAccKubernetesPersistentVolumeConfig_hostPath_claimRef_noNamespace(name string) string {
19241948
return fmt.Sprintf(`resource "kubernetes_persistent_volume" "test" {
19251949
metadata {
19261950
name = "%s"
19271951
}
1952+
spec {
1953+
capacity = {
1954+
storage = "1Gi"
1955+
}
1956+
access_modes = ["ReadWriteMany"]
1957+
mount_options = ["foo"]
1958+
claim_ref {
1959+
name = "%s"
1960+
}
1961+
1962+
persistent_volume_source {
1963+
host_path {
1964+
path = "/mnt/local-volume"
1965+
}
1966+
}
1967+
}
1968+
}`, name, name)
1969+
}
1970+
1971+
func testAccKubernetesPersistentVolumeConfig_hostPath_claimRef_withNamespace(name string) string {
1972+
return fmt.Sprintf(`resource "kubernetes_namespace" "test" {
1973+
metadata {
1974+
name = "%s"
1975+
}
1976+
}
1977+
resource "kubernetes_persistent_volume" "test" {
1978+
metadata {
1979+
name = "%s"
1980+
}
1981+
spec {
1982+
capacity = {
1983+
storage = "1Gi"
1984+
}
1985+
access_modes = ["ReadWriteMany"]
1986+
mount_options = ["foo"]
1987+
claim_ref {
1988+
name = "%s"
1989+
namespace = kubernetes_namespace.test.metadata.0.name
1990+
}
1991+
1992+
persistent_volume_source {
1993+
host_path {
1994+
path = "/mnt/local-volume"
1995+
}
1996+
}
1997+
}
1998+
}`, name, name, name)
1999+
}
2000+
2001+
func testAccKubernetesPersistentVolumeConfig_hostPath_claimRef_withPVC(name string) string {
2002+
return fmt.Sprintf(`resource "kubernetes_namespace" "test" {
2003+
metadata {
2004+
name = "%s"
2005+
}
2006+
}
2007+
2008+
resource "kubernetes_persistent_volume" "test" {
2009+
metadata {
2010+
name = "%s"
2011+
}
19282012
spec {
19292013
capacity = {
19302014
storage = "1Gi"
@@ -1942,7 +2026,27 @@ func testAccKubernetesPersistentVolumeConfig_hostPath_claimRef(name string, clai
19422026
}
19432027
}
19442028
}
1945-
}`, name, claimName, claimNamespace)
2029+
}
2030+
2031+
resource "kubernetes_persistent_volume_claim" "test" {
2032+
metadata {
2033+
name = "%s"
2034+
namespace = "%s"
2035+
}
2036+
2037+
spec {
2038+
access_modes = ["ReadWriteOnce"]
2039+
2040+
resources {
2041+
requests = {
2042+
storage = "1Gi"
2043+
}
2044+
}
2045+
2046+
volume_name = kubernetes_persistent_volume.test.metadata.0.name
2047+
}
2048+
}
2049+
`, name, name, name, name, name, name)
19462050
}
19472051

19482052
func testAccKubernetesPersistentVolume_regression(provider, name, path, typ string) string {

kubernetes/structure_persistent_volume_spec.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,17 @@ func flattenPersistentVolumeSpec(in v1.PersistentVolumeSpec) []interface{} {
403403
return []interface{}{att}
404404
}
405405

406+
func flattenObjectRef(in *v1.ObjectReference) []interface{} {
407+
att := make(map[string]interface{})
408+
if in.Name != "" {
409+
att["name"] = in.Name
410+
}
411+
if in.Namespace != "" {
412+
att["namespace"] = in.Namespace
413+
}
414+
return []interface{}{att}
415+
}
416+
406417
func flattenPhotonPersistentDiskVolumeSource(in *v1.PhotonPersistentDiskVolumeSource) []interface{} {
407418
att := make(map[string]interface{})
408419
att["pd_id"] = in.PdID
@@ -1025,11 +1036,11 @@ func expandPersistentVolumeSpec(l []interface{}) (*v1.PersistentVolumeSpec, erro
10251036
return obj, nil
10261037
}
10271038

1028-
func expandClaimRef(v []interface{}) *v1.ObjectReference {
1029-
if len(v) == 0 || v[0] == nil {
1030-
return nil
1039+
func expandClaimRef(l []interface{}) *v1.ObjectReference {
1040+
if len(l) == 0 || l[0] == nil {
1041+
return &v1.ObjectReference{}
10311042
}
1032-
o := v[0].(map[string]interface{})
1043+
o := l[0].(map[string]interface{})
10331044
return &v1.ObjectReference{
10341045
Name: o["name"].(string),
10351046
Namespace: o["namespace"].(string),
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package kubernetes
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
v1 "k8s.io/api/core/v1"
8+
)
9+
10+
func TestFlattenObjectRef(t *testing.T) {
11+
cases := []struct {
12+
Input *v1.ObjectReference
13+
ExpectedOutput []interface{}
14+
}{
15+
{
16+
&v1.ObjectReference{
17+
Name: "demo",
18+
Namespace: "default",
19+
},
20+
[]interface{}{
21+
map[string]interface{}{
22+
"name": "demo",
23+
"namespace": "default",
24+
},
25+
},
26+
},
27+
{
28+
&v1.ObjectReference{},
29+
[]interface{}{map[string]interface{}{}},
30+
},
31+
}
32+
33+
for _, tc := range cases {
34+
output := flattenObjectRef(tc.Input)
35+
if !reflect.DeepEqual(output, tc.ExpectedOutput) {
36+
t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v",
37+
tc.ExpectedOutput, output)
38+
}
39+
}
40+
}

kubernetes/structures_container.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,14 +1028,3 @@ func expandContainerResourceRequirements(l []interface{}) (*v1.ResourceRequireme
10281028

10291029
return obj, nil
10301030
}
1031-
1032-
func flattenObjectRef(in *v1.ObjectReference) []interface{} {
1033-
att := make(map[string]interface{})
1034-
if in.Name != "" {
1035-
att["name"] = in.Name
1036-
}
1037-
if in.Namespace != "" {
1038-
att["namespace"] = in.Namespace
1039-
}
1040-
return []interface{}{att}
1041-
}

kubernetes/structures_container_test.go

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -212,35 +212,3 @@ func TestExpandConfigMapKeyRef(t *testing.T) {
212212
}
213213
}
214214
}
215-
216-
func TestFlattenObjectRef(t *testing.T) {
217-
cases := []struct {
218-
Input *v1.ObjectReference
219-
ExpectedOutput []interface{}
220-
}{
221-
{
222-
&v1.ObjectReference{
223-
Name: "demo",
224-
Namespace: "default",
225-
},
226-
[]interface{}{
227-
map[string]interface{}{
228-
"name": "demo",
229-
"namespace": "default",
230-
},
231-
},
232-
},
233-
{
234-
&v1.ObjectReference{},
235-
[]interface{}{map[string]interface{}{}},
236-
},
237-
}
238-
239-
for _, tc := range cases {
240-
output := flattenObjectRef(tc.Input)
241-
if !reflect.DeepEqual(output, tc.ExpectedOutput) {
242-
t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v",
243-
tc.ExpectedOutput, output)
244-
}
245-
}
246-
}

0 commit comments

Comments
 (0)