Skip to content

add field for PersistentVolumeClaim resource #2644

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions .changelog/2644.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
Added support for the `data_source` field in the PersistentVolumeClaim resource.
```
25 changes: 24 additions & 1 deletion docs/resources/persistent_volume_claim_v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Required:
- `resources` (Block List, Min: 1, Max: 1) A list of the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources (see [below for nested schema](#nestedblock--spec--resources))

Optional:

- `data_source` (Block List, Max: 1) Specifies the data source for the PersistentVolumeClaim. Allows creating a PersistentVolumeClaim from another PVC, a VolumeSnapshot, or a VolumePopulator. (see [below for nested schema](#nestedblock--spec--data_source))
- `selector` (Block List, Max: 1) A label query over volumes to consider for binding. (see [below for nested schema](#nestedblock--spec--selector))
- `storage_class_name` (String) Name of the storage class requested by the claim
- `volume_mode` (String) Defines what type of volume is required by the claim.
Expand All @@ -67,6 +67,11 @@ Optional:
- `limits` (Map of String) Map describing the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
- `requests` (Map of String) Map describing the minimum amount of compute resources required. If this is omitted for a container, it defaults to `limits` if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/

<a id="nestedblock--spec--data_source"></a>
### Nested Schema for `spec.data_source`

Optional:
- `name` (String) The name of the source PersistentVolumeClaim.

<a id="nestedblock--spec--selector"></a>
### Nested Schema for `spec.selector`
Expand Down Expand Up @@ -132,6 +137,24 @@ resource "kubernetes_persistent_volume_v1" "example" {
}
}
}

resource "kubernetes_persistent_volume_claim_v1" "example_clone" {
metadata {
name = "example-clone-pvc"
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = "1Gi"
}
}
data_source {
name = "example-source-pvc"
}
}
}

```

## Import
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ func resourceKubernetesPersistentVolumeClaimV1Create(ctx context.Context, d *sch
if err != nil {
return diag.FromErr(err)
}
if claim.Spec.DataSource != nil {
_, err := conn.CoreV1().PersistentVolumeClaims(claim.Namespace).Get(ctx, claim.Spec.DataSource.Name, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
return diag.Errorf("data source PersistentVolumeClaim '%s' not found", claim.Spec.DataSource.Name)
}
return diag.FromErr(err)
}
}
log.Printf("[INFO] Creating new persistent volume claim: %#v", claim)
out, err := conn.CoreV1().PersistentVolumeClaims(claim.Namespace).Create(ctx, claim, metav1.CreateOptions{})
if err != nil {
Expand Down
103 changes: 103 additions & 0 deletions kubernetes/resource_kubernetes_persistent_volume_claim_v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"fmt"
"os"
"regexp"
"testing"
"time"

Expand Down Expand Up @@ -562,6 +563,61 @@ func TestAccKubernetesPersistentVolumeClaimV1_volumeMode(t *testing.T) {
})
}

func TestAccKubernetesPersistentVolumeClaimV1_dataSource(t *testing.T) {
var conf corev1.PersistentVolumeClaim
originalPVC := fmt.Sprintf("tf-acc-test-original-%s", acctest.RandString(10))
clonedPVC := fmt.Sprintf("tf-acc-test-clone-%s", acctest.RandString(10))
resourceName := "kubernetes_persistent_volume_claim_v1.test_clone"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: resourceName,
IDRefreshIgnore: []string{"metadata.0.resource_version"},
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccCheckKubernetesPersistentVolumeClaimV1Destroy,
Steps: []resource.TestStep{
{
Config: testAccKubernetesPersistentVolumeClaimV1Config_dataSourceOriginal(originalPVC),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckKubernetesPersistentVolumeClaimV1Exists("kubernetes_persistent_volume_claim_v1.test_original", &conf),
resource.TestCheckResourceAttr("kubernetes_persistent_volume_claim_v1.test_original", "metadata.0.name", originalPVC),
resource.TestCheckResourceAttr("kubernetes_persistent_volume_claim_v1.test_original", "spec.0.resources.0.requests.storage", "1Gi"),
),
},
{
Config: testAccKubernetesPersistentVolumeClaimV1Config_dataSourceClone(originalPVC, clonedPVC),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckKubernetesPersistentVolumeClaimV1Exists(resourceName, &conf),
resource.TestCheckResourceAttr(resourceName, "metadata.0.name", clonedPVC),
resource.TestCheckResourceAttr(resourceName, "spec.0.data_source.0.name", originalPVC),
),
},
},
})
}

func TestAccKubernetesPersistentVolumeClaimV1_invalidDataSource(t *testing.T) {
invalidSourcePVC := fmt.Sprintf("tf-acc-test-nonexistent-%s", acctest.RandString(10))
clonedPVC := fmt.Sprintf("tf-acc-test-clone-%s", acctest.RandString(10))
resourceName := "kubernetes_persistent_volume_claim_v1.test_clone_invalid"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: resourceName,
IDRefreshIgnore: []string{"metadata.0.resource_version"},
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccCheckKubernetesPersistentVolumeClaimV1Destroy,
Steps: []resource.TestStep{
{
Config: testAccKubernetesPersistentVolumeClaimV1Config_dataSourceClone(invalidSourcePVC, clonedPVC),
ExpectError: regexp.MustCompile(
fmt.Sprintf(`data source PersistentVolumeClaim '%s' not found`, invalidSourcePVC),
),
},
},
})
}

func testAccCheckKubernetesPersistentVolumeClaimV1Destroy(s *terraform.State) error {
conn, err := testAccProvider.Meta().(KubeClientsets).MainClientset()
if err != nil {
Expand Down Expand Up @@ -961,6 +1017,53 @@ resource "kubernetes_persistent_volume_claim_v1" "test" {
`, volumeName, diskName, zone, claimName)
}

func testAccKubernetesPersistentVolumeClaimV1Config_dataSourceOriginal(name string) string {
return fmt.Sprintf(`
resource "kubernetes_persistent_volume_claim_v1" "test_original" {
metadata {
name = "%s"
}

spec {
access_modes = ["ReadWriteOnce"]

resources {
requests = {
storage = "1Gi"
}
}
}

wait_until_bound = false
}
`, name)
}
func testAccKubernetesPersistentVolumeClaimV1Config_dataSourceClone(sourceName, cloneName string) string {
return fmt.Sprintf(`
resource "kubernetes_persistent_volume_claim_v1" "test_clone" {
metadata {
name = "%s"
}

spec {
access_modes = ["ReadWriteOnce"]

resources {
requests = {
storage = "1Gi"
}
}

data_source {
name = "%s"
}
}

wait_until_bound = false
}
`, cloneName, sourceName)
}

// func testAccKubernetesPersistentVolumeClaimConfig_labelsMatch(volumeName, claimName string) string {
// return fmt.Sprintf(`// resource "kubernetes_persistent_volume" "test" {
// metadata {
Expand Down
15 changes: 15 additions & 0 deletions kubernetes/schema_persistent_volume_claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ func persistentVolumeClaimSpecFields() map[string]*schema.Schema {
},
},
},
"data_source": {
Type: schema.TypeList,
Description: "Specifies the data source for the PVC. Allows creating a PVC from another PVC, VolumeSnapshot, or VolumePopulator.",
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Description: "The name of the source PersistentVolumeClaim.",
Required: true,
},
},
},
},
"selector": {
Type: schema.TypeList,
Description: "A label query over volumes to consider for binding.",
Expand Down
17 changes: 17 additions & 0 deletions kubernetes/structure_persistent_volume_claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ func flattenPersistentVolumeClaimSpec(in corev1.PersistentVolumeClaimSpec) []int
if in.VolumeMode != nil {
att["volume_mode"] = in.VolumeMode
}
if in.DataSource != nil && in.DataSource.Name != "" {
att["data_source"] = []interface{}{
map[string]interface{}{
"name": in.DataSource.Name,
},
}
}
return []interface{}{att}
}

Expand Down Expand Up @@ -91,6 +98,16 @@ func expandPersistentVolumeClaimSpec(l []interface{}) (*corev1.PersistentVolumeC
if v, ok := in["volume_mode"].(string); ok && v != "" {
obj.VolumeMode = ptr.To(corev1.PersistentVolumeMode(v))
}
if v, ok := in["data_source"].([]interface{}); ok && len(v) > 0 && v[0] != nil {
dataSource := v[0].(map[string]interface{})
if name, ok := dataSource["name"].(string); ok && name != "" {
obj.DataSource = &corev1.TypedLocalObjectReference{
Kind: "PersistentVolumeClaim",
Name: name,
APIGroup: ptr.To(""),
}
}
}
return obj, nil
}

Expand Down
Loading