github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/builtin/providers/kubernetes/resource_kubernetes_resource_quota.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 resourceKubernetesResourceQuota() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceKubernetesResourceQuotaCreate, 19 Read: resourceKubernetesResourceQuotaRead, 20 Exists: resourceKubernetesResourceQuotaExists, 21 Update: resourceKubernetesResourceQuotaUpdate, 22 Delete: resourceKubernetesResourceQuotaDelete, 23 Importer: &schema.ResourceImporter{ 24 State: schema.ImportStatePassthrough, 25 }, 26 27 Schema: map[string]*schema.Schema{ 28 "metadata": namespacedMetadataSchema("resource quota", true), 29 "spec": { 30 Type: schema.TypeList, 31 Description: "Spec defines the desired quota. http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status", 32 Optional: true, 33 MaxItems: 1, 34 Elem: &schema.Resource{ 35 Schema: map[string]*schema.Schema{ 36 "hard": { 37 Type: schema.TypeMap, 38 Description: "The set of desired hard limits for each named resource. More info: http://releases.k8s.io/HEAD/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota", 39 Optional: true, 40 Elem: schema.TypeString, 41 ValidateFunc: validateResourceList, 42 }, 43 "scopes": { 44 Type: schema.TypeSet, 45 Description: "A collection of filters that must match each object tracked by a quota. If not specified, the quota matches all objects.", 46 Optional: true, 47 ForceNew: true, 48 Elem: &schema.Schema{Type: schema.TypeString}, 49 Set: schema.HashString, 50 }, 51 }, 52 }, 53 }, 54 }, 55 } 56 } 57 58 func resourceKubernetesResourceQuotaCreate(d *schema.ResourceData, meta interface{}) error { 59 conn := meta.(*kubernetes.Clientset) 60 61 metadata := expandMetadata(d.Get("metadata").([]interface{})) 62 spec, err := expandResourceQuotaSpec(d.Get("spec").([]interface{})) 63 if err != nil { 64 return err 65 } 66 resQuota := api.ResourceQuota{ 67 ObjectMeta: metadata, 68 Spec: spec, 69 } 70 log.Printf("[INFO] Creating new resource quota: %#v", resQuota) 71 out, err := conn.CoreV1().ResourceQuotas(metadata.Namespace).Create(&resQuota) 72 if err != nil { 73 return fmt.Errorf("Failed to create resource quota: %s", err) 74 } 75 log.Printf("[INFO] Submitted new resource quota: %#v", out) 76 d.SetId(buildId(out.ObjectMeta)) 77 78 err = resource.Retry(1*time.Minute, func() *resource.RetryError { 79 quota, err := conn.CoreV1().ResourceQuotas(out.Namespace).Get(out.Name) 80 if err != nil { 81 return resource.NonRetryableError(err) 82 } 83 if resourceListEquals(spec.Hard, quota.Status.Hard) { 84 return nil 85 } 86 err = fmt.Errorf("Quotas don't match after creation.\nExpected: %#v\nGiven: %#v", 87 spec.Hard, quota.Status.Hard) 88 return resource.RetryableError(err) 89 }) 90 if err != nil { 91 return err 92 } 93 94 return resourceKubernetesResourceQuotaRead(d, meta) 95 } 96 97 func resourceKubernetesResourceQuotaRead(d *schema.ResourceData, meta interface{}) error { 98 conn := meta.(*kubernetes.Clientset) 99 100 namespace, name := idParts(d.Id()) 101 log.Printf("[INFO] Reading resource quota %s", name) 102 resQuota, err := conn.CoreV1().ResourceQuotas(namespace).Get(name) 103 if err != nil { 104 log.Printf("[DEBUG] Received error: %#v", err) 105 return err 106 } 107 log.Printf("[INFO] Received resource quota: %#v", resQuota) 108 109 // This is to work around K8S bug 110 // See https://github.com/kubernetes/kubernetes/issues/44539 111 if resQuota.ObjectMeta.GenerateName == "" { 112 if v, ok := d.GetOk("metadata.0.generate_name"); ok { 113 resQuota.ObjectMeta.GenerateName = v.(string) 114 } 115 } 116 117 err = d.Set("metadata", flattenMetadata(resQuota.ObjectMeta)) 118 if err != nil { 119 return err 120 } 121 err = d.Set("spec", flattenResourceQuotaSpec(resQuota.Spec)) 122 if err != nil { 123 return err 124 } 125 126 return nil 127 } 128 129 func resourceKubernetesResourceQuotaUpdate(d *schema.ResourceData, meta interface{}) error { 130 conn := meta.(*kubernetes.Clientset) 131 132 namespace, name := idParts(d.Id()) 133 134 ops := patchMetadata("metadata.0.", "/metadata/", d) 135 var spec api.ResourceQuotaSpec 136 waitForChangedSpec := false 137 if d.HasChange("spec") { 138 var err error 139 spec, err = expandResourceQuotaSpec(d.Get("spec").([]interface{})) 140 if err != nil { 141 return err 142 } 143 ops = append(ops, &ReplaceOperation{ 144 Path: "/spec", 145 Value: spec, 146 }) 147 waitForChangedSpec = true 148 } 149 data, err := ops.MarshalJSON() 150 if err != nil { 151 return fmt.Errorf("Failed to marshal update operations: %s", err) 152 } 153 log.Printf("[INFO] Updating resource quota %q: %v", name, string(data)) 154 out, err := conn.CoreV1().ResourceQuotas(namespace).Patch(name, pkgApi.JSONPatchType, data) 155 if err != nil { 156 return fmt.Errorf("Failed to update resource quota: %s", err) 157 } 158 log.Printf("[INFO] Submitted updated resource quota: %#v", out) 159 d.SetId(buildId(out.ObjectMeta)) 160 161 if waitForChangedSpec { 162 err = resource.Retry(1*time.Minute, func() *resource.RetryError { 163 quota, err := conn.CoreV1().ResourceQuotas(namespace).Get(name) 164 if err != nil { 165 return resource.NonRetryableError(err) 166 } 167 if resourceListEquals(spec.Hard, quota.Status.Hard) { 168 return nil 169 } 170 err = fmt.Errorf("Quotas don't match after update.\nExpected: %#v\nGiven: %#v", 171 spec.Hard, quota.Status.Hard) 172 return resource.RetryableError(err) 173 }) 174 if err != nil { 175 return err 176 } 177 } 178 179 return resourceKubernetesResourceQuotaRead(d, meta) 180 } 181 182 func resourceKubernetesResourceQuotaDelete(d *schema.ResourceData, meta interface{}) error { 183 conn := meta.(*kubernetes.Clientset) 184 185 namespace, name := idParts(d.Id()) 186 log.Printf("[INFO] Deleting resource quota: %#v", name) 187 err := conn.CoreV1().ResourceQuotas(namespace).Delete(name, &api.DeleteOptions{}) 188 if err != nil { 189 return err 190 } 191 192 log.Printf("[INFO] Resource quota %s deleted", name) 193 194 d.SetId("") 195 return nil 196 } 197 198 func resourceKubernetesResourceQuotaExists(d *schema.ResourceData, meta interface{}) (bool, error) { 199 conn := meta.(*kubernetes.Clientset) 200 201 namespace, name := idParts(d.Id()) 202 log.Printf("[INFO] Checking resource quota %s", name) 203 _, err := conn.CoreV1().ResourceQuotas(namespace).Get(name) 204 if err != nil { 205 if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 { 206 return false, nil 207 } 208 log.Printf("[DEBUG] Received error: %#v", err) 209 } 210 return true, err 211 }