github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/kubernetes/resource_kubernetes_persistent_volume_claim.go (about) 1 package kubernetes 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/hashicorp/terraform/helper/resource" 9 "github.com/hashicorp/terraform/helper/schema" 10 pkgApi "k8s.io/kubernetes/pkg/api" 11 "k8s.io/kubernetes/pkg/api/errors" 12 api "k8s.io/kubernetes/pkg/api/v1" 13 kubernetes "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5" 14 ) 15 16 func resourceKubernetesPersistentVolumeClaim() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceKubernetesPersistentVolumeClaimCreate, 19 Read: resourceKubernetesPersistentVolumeClaimRead, 20 Exists: resourceKubernetesPersistentVolumeClaimExists, 21 Update: resourceKubernetesPersistentVolumeClaimUpdate, 22 Delete: resourceKubernetesPersistentVolumeClaimDelete, 23 Importer: &schema.ResourceImporter{ 24 State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { 25 d.Set("wait_until_bound", true) 26 return []*schema.ResourceData{d}, nil 27 }, 28 }, 29 30 Timeouts: &schema.ResourceTimeout{ 31 Create: schema.DefaultTimeout(5 * time.Minute), 32 }, 33 34 Schema: map[string]*schema.Schema{ 35 "metadata": namespacedMetadataSchema("persistent volume claim", true), 36 "spec": { 37 Type: schema.TypeList, 38 Description: "Spec defines the desired characteristics of a volume requested by a pod author. More info: http://kubernetes.io/docs/user-guide/persistent-volumes#persistentvolumeclaims", 39 Required: true, 40 ForceNew: true, 41 MaxItems: 1, 42 Elem: &schema.Resource{ 43 Schema: map[string]*schema.Schema{ 44 "access_modes": { 45 Type: schema.TypeSet, 46 Description: "A set of the desired access modes the volume should have. More info: http://kubernetes.io/docs/user-guide/persistent-volumes#access-modes-1", 47 Required: true, 48 ForceNew: true, 49 Elem: &schema.Schema{Type: schema.TypeString}, 50 Set: schema.HashString, 51 }, 52 "resources": { 53 Type: schema.TypeList, 54 Description: "A list of the minimum resources the volume should have. More info: http://kubernetes.io/docs/user-guide/persistent-volumes#resources", 55 Required: true, 56 ForceNew: true, 57 MaxItems: 1, 58 Elem: &schema.Resource{ 59 Schema: map[string]*schema.Schema{ 60 "limits": { 61 Type: schema.TypeMap, 62 Description: "Map describing the maximum amount of compute resources allowed. More info: http://kubernetes.io/docs/user-guide/compute-resources/", 63 Optional: true, 64 ForceNew: true, 65 }, 66 "requests": { 67 Type: schema.TypeMap, 68 Description: "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: http://kubernetes.io/docs/user-guide/compute-resources/", 69 Optional: true, 70 ForceNew: true, 71 }, 72 }, 73 }, 74 }, 75 "selector": { 76 Type: schema.TypeList, 77 Description: "A label query over volumes to consider for binding.", 78 Optional: true, 79 ForceNew: true, 80 MaxItems: 1, 81 Elem: &schema.Resource{ 82 Schema: map[string]*schema.Schema{ 83 "match_expressions": { 84 Type: schema.TypeList, 85 Description: "A list of label selector requirements. The requirements are ANDed.", 86 Optional: true, 87 ForceNew: true, 88 Elem: &schema.Resource{ 89 Schema: map[string]*schema.Schema{ 90 "key": { 91 Type: schema.TypeString, 92 Description: "The label key that the selector applies to.", 93 Optional: true, 94 ForceNew: true, 95 }, 96 "operator": { 97 Type: schema.TypeString, 98 Description: "A key's relationship to a set of values. Valid operators ard `In`, `NotIn`, `Exists` and `DoesNotExist`.", 99 Optional: true, 100 ForceNew: true, 101 }, 102 "values": { 103 Type: schema.TypeSet, 104 Description: "An array of string values. If the operator is `In` or `NotIn`, the values array must be non-empty. If the operator is `Exists` or `DoesNotExist`, the values array must be empty. This array is replaced during a strategic merge patch.", 105 Optional: true, 106 ForceNew: true, 107 Elem: &schema.Schema{Type: schema.TypeString}, 108 Set: schema.HashString, 109 }, 110 }, 111 }, 112 }, 113 "match_labels": { 114 Type: schema.TypeMap, 115 Description: "A map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of `match_expressions`, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.", 116 Optional: true, 117 ForceNew: true, 118 }, 119 }, 120 }, 121 }, 122 "volume_name": { 123 Type: schema.TypeString, 124 Description: "The binding reference to the PersistentVolume backing this claim.", 125 Optional: true, 126 ForceNew: true, 127 Computed: true, 128 }, 129 }, 130 }, 131 }, 132 "wait_until_bound": { 133 Type: schema.TypeBool, 134 Description: "Whether to wait for the claim to reach `Bound` state (to find volume in which to claim the space)", 135 Optional: true, 136 Default: true, 137 }, 138 }, 139 } 140 } 141 142 func resourceKubernetesPersistentVolumeClaimCreate(d *schema.ResourceData, meta interface{}) error { 143 conn := meta.(*kubernetes.Clientset) 144 145 metadata := expandMetadata(d.Get("metadata").([]interface{})) 146 spec, err := expandPersistentVolumeClaimSpec(d.Get("spec").([]interface{})) 147 if err != nil { 148 return err 149 } 150 151 claim := api.PersistentVolumeClaim{ 152 ObjectMeta: metadata, 153 Spec: spec, 154 } 155 156 log.Printf("[INFO] Creating new persistent volume claim: %#v", claim) 157 out, err := conn.CoreV1().PersistentVolumeClaims(metadata.Namespace).Create(&claim) 158 if err != nil { 159 return err 160 } 161 log.Printf("[INFO] Submitted new persistent volume claim: %#v", out) 162 163 d.SetId(buildId(out.ObjectMeta)) 164 name := out.ObjectMeta.Name 165 166 if d.Get("wait_until_bound").(bool) { 167 stateConf := &resource.StateChangeConf{ 168 Target: []string{"Bound"}, 169 Pending: []string{"Pending"}, 170 Timeout: d.Timeout(schema.TimeoutCreate), 171 Refresh: func() (interface{}, string, error) { 172 out, err := conn.CoreV1().PersistentVolumeClaims(metadata.Namespace).Get(name) 173 if err != nil { 174 log.Printf("[ERROR] Received error: %#v", err) 175 return out, "", err 176 } 177 178 statusPhase := fmt.Sprintf("%v", out.Status.Phase) 179 log.Printf("[DEBUG] Persistent volume claim %s status received: %#v", out.Name, statusPhase) 180 return out, statusPhase, nil 181 }, 182 } 183 _, err = stateConf.WaitForState() 184 if err != nil { 185 return err 186 } 187 } 188 log.Printf("[INFO] Persistent volume claim %s created", out.Name) 189 190 return resourceKubernetesPersistentVolumeClaimRead(d, meta) 191 } 192 193 func resourceKubernetesPersistentVolumeClaimRead(d *schema.ResourceData, meta interface{}) error { 194 conn := meta.(*kubernetes.Clientset) 195 196 namespace, name := idParts(d.Id()) 197 log.Printf("[INFO] Reading persistent volume claim %s", name) 198 claim, err := conn.CoreV1().PersistentVolumeClaims(namespace).Get(name) 199 if err != nil { 200 log.Printf("[DEBUG] Received error: %#v", err) 201 return err 202 } 203 log.Printf("[INFO] Received persistent volume claim: %#v", claim) 204 err = d.Set("metadata", flattenMetadata(claim.ObjectMeta)) 205 if err != nil { 206 return err 207 } 208 err = d.Set("spec", flattenPersistentVolumeClaimSpec(claim.Spec)) 209 if err != nil { 210 return err 211 } 212 213 return nil 214 } 215 216 func resourceKubernetesPersistentVolumeClaimUpdate(d *schema.ResourceData, meta interface{}) error { 217 conn := meta.(*kubernetes.Clientset) 218 namespace, name := idParts(d.Id()) 219 220 ops := patchMetadata("metadata.0.", "/metadata/", d) 221 // The whole spec is ForceNew = nothing to update there 222 data, err := ops.MarshalJSON() 223 if err != nil { 224 return fmt.Errorf("Failed to marshal update operations: %s", err) 225 } 226 227 log.Printf("[INFO] Updating persistent volume claim: %s", ops) 228 out, err := conn.CoreV1().PersistentVolumeClaims(namespace).Patch(name, pkgApi.JSONPatchType, data) 229 if err != nil { 230 return err 231 } 232 log.Printf("[INFO] Submitted updated persistent volume claim: %#v", out) 233 234 return resourceKubernetesPersistentVolumeClaimRead(d, meta) 235 } 236 237 func resourceKubernetesPersistentVolumeClaimDelete(d *schema.ResourceData, meta interface{}) error { 238 conn := meta.(*kubernetes.Clientset) 239 240 namespace, name := idParts(d.Id()) 241 log.Printf("[INFO] Deleting persistent volume claim: %#v", name) 242 err := conn.CoreV1().PersistentVolumeClaims(namespace).Delete(name, &api.DeleteOptions{}) 243 if err != nil { 244 return err 245 } 246 247 log.Printf("[INFO] Persistent volume claim %s deleted", name) 248 249 d.SetId("") 250 return nil 251 } 252 253 func resourceKubernetesPersistentVolumeClaimExists(d *schema.ResourceData, meta interface{}) (bool, error) { 254 conn := meta.(*kubernetes.Clientset) 255 256 namespace, name := idParts(d.Id()) 257 log.Printf("[INFO] Checking persistent volume claim %s", name) 258 _, err := conn.CoreV1().PersistentVolumeClaims(namespace).Get(name) 259 if err != nil { 260 if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 { 261 return false, nil 262 } 263 log.Printf("[DEBUG] Received error: %#v", err) 264 } 265 return true, err 266 }