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  }