github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/builtin/providers/kubernetes/structures.go (about)

     1  package kubernetes
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"strings"
     7  
     8  	"encoding/base64"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"k8s.io/apimachinery/pkg/api/resource"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  	api "k8s.io/kubernetes/pkg/api/v1"
    13  )
    14  
    15  func idParts(id string) (string, string) {
    16  	parts := strings.Split(id, "/")
    17  	return parts[0], parts[1]
    18  }
    19  
    20  func buildId(meta metav1.ObjectMeta) string {
    21  	return meta.Namespace + "/" + meta.Name
    22  }
    23  
    24  func expandMetadata(in []interface{}) metav1.ObjectMeta {
    25  	meta := metav1.ObjectMeta{}
    26  	if len(in) < 1 {
    27  		return meta
    28  	}
    29  	m := in[0].(map[string]interface{})
    30  
    31  	meta.Annotations = expandStringMap(m["annotations"].(map[string]interface{}))
    32  	meta.Labels = expandStringMap(m["labels"].(map[string]interface{}))
    33  
    34  	if v, ok := m["generate_name"]; ok {
    35  		meta.GenerateName = v.(string)
    36  	}
    37  	if v, ok := m["name"]; ok {
    38  		meta.Name = v.(string)
    39  	}
    40  	if v, ok := m["namespace"]; ok {
    41  		meta.Namespace = v.(string)
    42  	}
    43  
    44  	return meta
    45  }
    46  
    47  func patchMetadata(keyPrefix, pathPrefix string, d *schema.ResourceData) PatchOperations {
    48  	ops := make([]PatchOperation, 0, 0)
    49  	if d.HasChange(keyPrefix + "annotations") {
    50  		oldV, newV := d.GetChange(keyPrefix + "annotations")
    51  		diffOps := diffStringMap(pathPrefix+"annotations", oldV.(map[string]interface{}), newV.(map[string]interface{}))
    52  		ops = append(ops, diffOps...)
    53  	}
    54  	if d.HasChange(keyPrefix + "labels") {
    55  		oldV, newV := d.GetChange(keyPrefix + "labels")
    56  		diffOps := diffStringMap(pathPrefix+"labels", oldV.(map[string]interface{}), newV.(map[string]interface{}))
    57  		ops = append(ops, diffOps...)
    58  	}
    59  	return ops
    60  }
    61  
    62  func expandStringMap(m map[string]interface{}) map[string]string {
    63  	result := make(map[string]string)
    64  	for k, v := range m {
    65  		result[k] = v.(string)
    66  	}
    67  	return result
    68  }
    69  
    70  func expandStringSlice(s []interface{}) []string {
    71  	result := make([]string, len(s), len(s))
    72  	for k, v := range s {
    73  		result[k] = v.(string)
    74  	}
    75  	return result
    76  }
    77  
    78  func flattenMetadata(meta metav1.ObjectMeta) []map[string]interface{} {
    79  	m := make(map[string]interface{})
    80  	m["annotations"] = removeInternalKeys(meta.Annotations)
    81  	if meta.GenerateName != "" {
    82  		m["generate_name"] = meta.GenerateName
    83  	}
    84  	m["labels"] = removeInternalKeys(meta.Labels)
    85  	m["name"] = meta.Name
    86  	m["resource_version"] = meta.ResourceVersion
    87  	m["self_link"] = meta.SelfLink
    88  	m["uid"] = fmt.Sprintf("%v", meta.UID)
    89  	m["generation"] = meta.Generation
    90  
    91  	if meta.Namespace != "" {
    92  		m["namespace"] = meta.Namespace
    93  	}
    94  
    95  	return []map[string]interface{}{m}
    96  }
    97  
    98  func removeInternalKeys(m map[string]string) map[string]string {
    99  	for k, _ := range m {
   100  		if isInternalKey(k) {
   101  			delete(m, k)
   102  		}
   103  	}
   104  	return m
   105  }
   106  
   107  func isInternalKey(annotationKey string) bool {
   108  	u, err := url.Parse("//" + annotationKey)
   109  	if err == nil && strings.HasSuffix(u.Hostname(), "kubernetes.io") {
   110  		return true
   111  	}
   112  
   113  	return false
   114  }
   115  
   116  func byteMapToStringMap(m map[string][]byte) map[string]string {
   117  	result := make(map[string]string)
   118  	for k, v := range m {
   119  		result[k] = string(v)
   120  	}
   121  	return result
   122  }
   123  
   124  func ptrToString(s string) *string {
   125  	return &s
   126  }
   127  
   128  func ptrToInt(i int) *int {
   129  	return &i
   130  }
   131  
   132  func ptrToBool(b bool) *bool {
   133  	return &b
   134  }
   135  
   136  func ptrToInt32(i int32) *int32 {
   137  	return &i
   138  }
   139  
   140  func sliceOfString(slice []interface{}) []string {
   141  	result := make([]string, len(slice), len(slice))
   142  	for i, s := range slice {
   143  		result[i] = s.(string)
   144  	}
   145  	return result
   146  }
   147  
   148  func base64EncodeStringMap(m map[string]interface{}) map[string]interface{} {
   149  	result := make(map[string]interface{})
   150  	for k, v := range m {
   151  		value := v.(string)
   152  		result[k] = (base64.StdEncoding.EncodeToString([]byte(value)))
   153  	}
   154  	return result
   155  }
   156  
   157  func flattenResourceList(l api.ResourceList) map[string]string {
   158  	m := make(map[string]string)
   159  	for k, v := range l {
   160  		m[string(k)] = v.String()
   161  	}
   162  	return m
   163  }
   164  
   165  func expandMapToResourceList(m map[string]interface{}) (api.ResourceList, error) {
   166  	out := make(map[api.ResourceName]resource.Quantity)
   167  	for stringKey, origValue := range m {
   168  		key := api.ResourceName(stringKey)
   169  		var value resource.Quantity
   170  
   171  		if v, ok := origValue.(int); ok {
   172  			q := resource.NewQuantity(int64(v), resource.DecimalExponent)
   173  			value = *q
   174  		} else if v, ok := origValue.(string); ok {
   175  			var err error
   176  			value, err = resource.ParseQuantity(v)
   177  			if err != nil {
   178  				return out, err
   179  			}
   180  		} else {
   181  			return out, fmt.Errorf("Unexpected value type: %#v", origValue)
   182  		}
   183  
   184  		out[key] = value
   185  	}
   186  	return out, nil
   187  }
   188  
   189  func flattenPersistentVolumeAccessModes(in []api.PersistentVolumeAccessMode) *schema.Set {
   190  	var out = make([]interface{}, len(in), len(in))
   191  	for i, v := range in {
   192  		out[i] = string(v)
   193  	}
   194  	return schema.NewSet(schema.HashString, out)
   195  }
   196  
   197  func expandPersistentVolumeAccessModes(s []interface{}) []api.PersistentVolumeAccessMode {
   198  	out := make([]api.PersistentVolumeAccessMode, len(s), len(s))
   199  	for i, v := range s {
   200  		out[i] = api.PersistentVolumeAccessMode(v.(string))
   201  	}
   202  	return out
   203  }
   204  
   205  func flattenResourceQuotaSpec(in api.ResourceQuotaSpec) []interface{} {
   206  	out := make([]interface{}, 1)
   207  
   208  	m := make(map[string]interface{}, 0)
   209  	m["hard"] = flattenResourceList(in.Hard)
   210  	m["scopes"] = flattenResourceQuotaScopes(in.Scopes)
   211  
   212  	out[0] = m
   213  	return out
   214  }
   215  
   216  func expandResourceQuotaSpec(s []interface{}) (api.ResourceQuotaSpec, error) {
   217  	out := api.ResourceQuotaSpec{}
   218  	if len(s) < 1 {
   219  		return out, nil
   220  	}
   221  	m := s[0].(map[string]interface{})
   222  
   223  	if v, ok := m["hard"]; ok {
   224  		list, err := expandMapToResourceList(v.(map[string]interface{}))
   225  		if err != nil {
   226  			return out, err
   227  		}
   228  		out.Hard = list
   229  	}
   230  
   231  	if v, ok := m["scopes"]; ok {
   232  		out.Scopes = expandResourceQuotaScopes(v.(*schema.Set).List())
   233  	}
   234  
   235  	return out, nil
   236  }
   237  
   238  func flattenResourceQuotaScopes(in []api.ResourceQuotaScope) *schema.Set {
   239  	out := make([]string, len(in), len(in))
   240  	for i, scope := range in {
   241  		out[i] = string(scope)
   242  	}
   243  	return newStringSet(schema.HashString, out)
   244  }
   245  
   246  func expandResourceQuotaScopes(s []interface{}) []api.ResourceQuotaScope {
   247  	out := make([]api.ResourceQuotaScope, len(s), len(s))
   248  	for i, scope := range s {
   249  		out[i] = api.ResourceQuotaScope(scope.(string))
   250  	}
   251  	return out
   252  }
   253  
   254  func newStringSet(f schema.SchemaSetFunc, in []string) *schema.Set {
   255  	var out = make([]interface{}, len(in), len(in))
   256  	for i, v := range in {
   257  		out[i] = v
   258  	}
   259  	return schema.NewSet(f, out)
   260  }
   261  
   262  func resourceListEquals(x, y api.ResourceList) bool {
   263  	for k, v := range x {
   264  		yValue, ok := y[k]
   265  		if !ok {
   266  			return false
   267  		}
   268  		if v.Cmp(yValue) != 0 {
   269  			return false
   270  		}
   271  	}
   272  	for k, v := range y {
   273  		xValue, ok := x[k]
   274  		if !ok {
   275  			return false
   276  		}
   277  		if v.Cmp(xValue) != 0 {
   278  			return false
   279  		}
   280  	}
   281  	return true
   282  }
   283  
   284  func expandLimitRangeSpec(s []interface{}, isNew bool) (api.LimitRangeSpec, error) {
   285  	out := api.LimitRangeSpec{}
   286  	if len(s) < 1 || s[0] == nil {
   287  		return out, nil
   288  	}
   289  	m := s[0].(map[string]interface{})
   290  
   291  	if limits, ok := m["limit"].([]interface{}); ok {
   292  		newLimits := make([]api.LimitRangeItem, len(limits), len(limits))
   293  
   294  		for i, l := range limits {
   295  			lrItem := api.LimitRangeItem{}
   296  			limit := l.(map[string]interface{})
   297  
   298  			if v, ok := limit["type"]; ok {
   299  				lrItem.Type = api.LimitType(v.(string))
   300  			}
   301  
   302  			// defaultRequest is forbidden for Pod limits, even though it's set & returned by API
   303  			// this is how we avoid sending it back
   304  			if v, ok := limit["default_request"]; ok {
   305  				drm := v.(map[string]interface{})
   306  				if lrItem.Type == api.LimitTypePod && len(drm) > 0 {
   307  					if isNew {
   308  						return out, fmt.Errorf("limit.%d.default_request cannot be set for Pod limit", i)
   309  					}
   310  				} else {
   311  					el, err := expandMapToResourceList(drm)
   312  					if err != nil {
   313  						return out, err
   314  					}
   315  					lrItem.DefaultRequest = el
   316  				}
   317  			}
   318  
   319  			if v, ok := limit["default"]; ok {
   320  				el, err := expandMapToResourceList(v.(map[string]interface{}))
   321  				if err != nil {
   322  					return out, err
   323  				}
   324  				lrItem.Default = el
   325  			}
   326  			if v, ok := limit["max"]; ok {
   327  				el, err := expandMapToResourceList(v.(map[string]interface{}))
   328  				if err != nil {
   329  					return out, err
   330  				}
   331  				lrItem.Max = el
   332  			}
   333  			if v, ok := limit["max_limit_request_ratio"]; ok {
   334  				el, err := expandMapToResourceList(v.(map[string]interface{}))
   335  				if err != nil {
   336  					return out, err
   337  				}
   338  				lrItem.MaxLimitRequestRatio = el
   339  			}
   340  			if v, ok := limit["min"]; ok {
   341  				el, err := expandMapToResourceList(v.(map[string]interface{}))
   342  				if err != nil {
   343  					return out, err
   344  				}
   345  				lrItem.Min = el
   346  			}
   347  
   348  			newLimits[i] = lrItem
   349  		}
   350  
   351  		out.Limits = newLimits
   352  	}
   353  
   354  	return out, nil
   355  }
   356  
   357  func flattenLimitRangeSpec(in api.LimitRangeSpec) []interface{} {
   358  	out := make([]interface{}, 1)
   359  	limits := make([]interface{}, len(in.Limits), len(in.Limits))
   360  
   361  	for i, l := range in.Limits {
   362  		m := make(map[string]interface{}, 0)
   363  		m["default"] = flattenResourceList(l.Default)
   364  		m["default_request"] = flattenResourceList(l.DefaultRequest)
   365  		m["max"] = flattenResourceList(l.Max)
   366  		m["max_limit_request_ratio"] = flattenResourceList(l.MaxLimitRequestRatio)
   367  		m["min"] = flattenResourceList(l.Min)
   368  		m["type"] = string(l.Type)
   369  
   370  		limits[i] = m
   371  	}
   372  	out[0] = map[string]interface{}{
   373  		"limit": limits,
   374  	}
   375  	return out
   376  }