github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/builtin/providers/kubernetes/structures.go (about)

     1  package kubernetes
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"net/url"
     7  	"strings"
     8  
     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 ptrToInt64(i int64) *int64 {
   141  	return &i
   142  }
   143  
   144  func sliceOfString(slice []interface{}) []string {
   145  	result := make([]string, len(slice), len(slice))
   146  	for i, s := range slice {
   147  		result[i] = s.(string)
   148  	}
   149  	return result
   150  }
   151  
   152  func base64EncodeStringMap(m map[string]interface{}) map[string]interface{} {
   153  	result := make(map[string]interface{})
   154  	for k, v := range m {
   155  		value := v.(string)
   156  		result[k] = (base64.StdEncoding.EncodeToString([]byte(value)))
   157  	}
   158  	return result
   159  }
   160  
   161  func flattenResourceList(l api.ResourceList) map[string]string {
   162  	m := make(map[string]string)
   163  	for k, v := range l {
   164  		m[string(k)] = v.String()
   165  	}
   166  	return m
   167  }
   168  
   169  func expandMapToResourceList(m map[string]interface{}) (api.ResourceList, error) {
   170  	out := make(map[api.ResourceName]resource.Quantity)
   171  	for stringKey, origValue := range m {
   172  		key := api.ResourceName(stringKey)
   173  		var value resource.Quantity
   174  
   175  		if v, ok := origValue.(int); ok {
   176  			q := resource.NewQuantity(int64(v), resource.DecimalExponent)
   177  			value = *q
   178  		} else if v, ok := origValue.(string); ok {
   179  			var err error
   180  			value, err = resource.ParseQuantity(v)
   181  			if err != nil {
   182  				return out, err
   183  			}
   184  		} else {
   185  			return out, fmt.Errorf("Unexpected value type: %#v", origValue)
   186  		}
   187  
   188  		out[key] = value
   189  	}
   190  	return out, nil
   191  }
   192  
   193  func flattenPersistentVolumeAccessModes(in []api.PersistentVolumeAccessMode) *schema.Set {
   194  	var out = make([]interface{}, len(in), len(in))
   195  	for i, v := range in {
   196  		out[i] = string(v)
   197  	}
   198  	return schema.NewSet(schema.HashString, out)
   199  }
   200  
   201  func expandPersistentVolumeAccessModes(s []interface{}) []api.PersistentVolumeAccessMode {
   202  	out := make([]api.PersistentVolumeAccessMode, len(s), len(s))
   203  	for i, v := range s {
   204  		out[i] = api.PersistentVolumeAccessMode(v.(string))
   205  	}
   206  	return out
   207  }
   208  
   209  func flattenResourceQuotaSpec(in api.ResourceQuotaSpec) []interface{} {
   210  	out := make([]interface{}, 1)
   211  
   212  	m := make(map[string]interface{}, 0)
   213  	m["hard"] = flattenResourceList(in.Hard)
   214  	m["scopes"] = flattenResourceQuotaScopes(in.Scopes)
   215  
   216  	out[0] = m
   217  	return out
   218  }
   219  
   220  func expandResourceQuotaSpec(s []interface{}) (api.ResourceQuotaSpec, error) {
   221  	out := api.ResourceQuotaSpec{}
   222  	if len(s) < 1 {
   223  		return out, nil
   224  	}
   225  	m := s[0].(map[string]interface{})
   226  
   227  	if v, ok := m["hard"]; ok {
   228  		list, err := expandMapToResourceList(v.(map[string]interface{}))
   229  		if err != nil {
   230  			return out, err
   231  		}
   232  		out.Hard = list
   233  	}
   234  
   235  	if v, ok := m["scopes"]; ok {
   236  		out.Scopes = expandResourceQuotaScopes(v.(*schema.Set).List())
   237  	}
   238  
   239  	return out, nil
   240  }
   241  
   242  func flattenResourceQuotaScopes(in []api.ResourceQuotaScope) *schema.Set {
   243  	out := make([]string, len(in), len(in))
   244  	for i, scope := range in {
   245  		out[i] = string(scope)
   246  	}
   247  	return newStringSet(schema.HashString, out)
   248  }
   249  
   250  func expandResourceQuotaScopes(s []interface{}) []api.ResourceQuotaScope {
   251  	out := make([]api.ResourceQuotaScope, len(s), len(s))
   252  	for i, scope := range s {
   253  		out[i] = api.ResourceQuotaScope(scope.(string))
   254  	}
   255  	return out
   256  }
   257  
   258  func newStringSet(f schema.SchemaSetFunc, in []string) *schema.Set {
   259  	var out = make([]interface{}, len(in), len(in))
   260  	for i, v := range in {
   261  		out[i] = v
   262  	}
   263  	return schema.NewSet(f, out)
   264  }
   265  func newInt64Set(f schema.SchemaSetFunc, in []int64) *schema.Set {
   266  	var out = make([]interface{}, len(in), len(in))
   267  	for i, v := range in {
   268  		out[i] = int(v)
   269  	}
   270  	return schema.NewSet(f, out)
   271  }
   272  
   273  func resourceListEquals(x, y api.ResourceList) bool {
   274  	for k, v := range x {
   275  		yValue, ok := y[k]
   276  		if !ok {
   277  			return false
   278  		}
   279  		if v.Cmp(yValue) != 0 {
   280  			return false
   281  		}
   282  	}
   283  	for k, v := range y {
   284  		xValue, ok := x[k]
   285  		if !ok {
   286  			return false
   287  		}
   288  		if v.Cmp(xValue) != 0 {
   289  			return false
   290  		}
   291  	}
   292  	return true
   293  }
   294  
   295  func expandLimitRangeSpec(s []interface{}, isNew bool) (api.LimitRangeSpec, error) {
   296  	out := api.LimitRangeSpec{}
   297  	if len(s) < 1 || s[0] == nil {
   298  		return out, nil
   299  	}
   300  	m := s[0].(map[string]interface{})
   301  
   302  	if limits, ok := m["limit"].([]interface{}); ok {
   303  		newLimits := make([]api.LimitRangeItem, len(limits), len(limits))
   304  
   305  		for i, l := range limits {
   306  			lrItem := api.LimitRangeItem{}
   307  			limit := l.(map[string]interface{})
   308  
   309  			if v, ok := limit["type"]; ok {
   310  				lrItem.Type = api.LimitType(v.(string))
   311  			}
   312  
   313  			// defaultRequest is forbidden for Pod limits, even though it's set & returned by API
   314  			// this is how we avoid sending it back
   315  			if v, ok := limit["default_request"]; ok {
   316  				drm := v.(map[string]interface{})
   317  				if lrItem.Type == api.LimitTypePod && len(drm) > 0 {
   318  					if isNew {
   319  						return out, fmt.Errorf("limit.%d.default_request cannot be set for Pod limit", i)
   320  					}
   321  				} else {
   322  					el, err := expandMapToResourceList(drm)
   323  					if err != nil {
   324  						return out, err
   325  					}
   326  					lrItem.DefaultRequest = el
   327  				}
   328  			}
   329  
   330  			if v, ok := limit["default"]; ok {
   331  				el, err := expandMapToResourceList(v.(map[string]interface{}))
   332  				if err != nil {
   333  					return out, err
   334  				}
   335  				lrItem.Default = el
   336  			}
   337  			if v, ok := limit["max"]; ok {
   338  				el, err := expandMapToResourceList(v.(map[string]interface{}))
   339  				if err != nil {
   340  					return out, err
   341  				}
   342  				lrItem.Max = el
   343  			}
   344  			if v, ok := limit["max_limit_request_ratio"]; ok {
   345  				el, err := expandMapToResourceList(v.(map[string]interface{}))
   346  				if err != nil {
   347  					return out, err
   348  				}
   349  				lrItem.MaxLimitRequestRatio = el
   350  			}
   351  			if v, ok := limit["min"]; ok {
   352  				el, err := expandMapToResourceList(v.(map[string]interface{}))
   353  				if err != nil {
   354  					return out, err
   355  				}
   356  				lrItem.Min = el
   357  			}
   358  
   359  			newLimits[i] = lrItem
   360  		}
   361  
   362  		out.Limits = newLimits
   363  	}
   364  
   365  	return out, nil
   366  }
   367  
   368  func flattenLimitRangeSpec(in api.LimitRangeSpec) []interface{} {
   369  	out := make([]interface{}, 1)
   370  	limits := make([]interface{}, len(in.Limits), len(in.Limits))
   371  
   372  	for i, l := range in.Limits {
   373  		m := make(map[string]interface{}, 0)
   374  		m["default"] = flattenResourceList(l.Default)
   375  		m["default_request"] = flattenResourceList(l.DefaultRequest)
   376  		m["max"] = flattenResourceList(l.Max)
   377  		m["max_limit_request_ratio"] = flattenResourceList(l.MaxLimitRequestRatio)
   378  		m["min"] = flattenResourceList(l.Min)
   379  		m["type"] = string(l.Type)
   380  
   381  		limits[i] = m
   382  	}
   383  	out[0] = map[string]interface{}{
   384  		"limit": limits,
   385  	}
   386  	return out
   387  }
   388  
   389  func schemaSetToStringArray(set *schema.Set) []string {
   390  	array := make([]string, 0, set.Len())
   391  	for _, elem := range set.List() {
   392  		e := elem.(string)
   393  		array = append(array, e)
   394  	}
   395  	return array
   396  }
   397  
   398  func schemaSetToInt64Array(set *schema.Set) []int64 {
   399  	array := make([]int64, 0, set.Len())
   400  	for _, elem := range set.List() {
   401  		e := elem.(int)
   402  		array = append(array, int64(e))
   403  	}
   404  	return array
   405  }
   406  func flattenLabelSelectorRequirementList(l []metav1.LabelSelectorRequirement) []interface{} {
   407  	att := make([]map[string]interface{}, len(l))
   408  	for i, v := range l {
   409  		m := map[string]interface{}{}
   410  		m["key"] = v.Key
   411  		m["values"] = newStringSet(schema.HashString, v.Values)
   412  		m["operator"] = string(v.Operator)
   413  		att[i] = m
   414  	}
   415  	return []interface{}{att}
   416  }
   417  
   418  func flattenLocalObjectReferenceArray(in []api.LocalObjectReference) []interface{} {
   419  	att := make([]interface{}, len(in))
   420  	for i, v := range in {
   421  		m := map[string]interface{}{}
   422  		if v.Name != "" {
   423  			m["name"] = v.Name
   424  		}
   425  		att[i] = m
   426  	}
   427  	return att
   428  }
   429  func expandLocalObjectReferenceArray(in []interface{}) []api.LocalObjectReference {
   430  	att := []api.LocalObjectReference{}
   431  	if len(in) < 1 {
   432  		return att
   433  	}
   434  	att = make([]api.LocalObjectReference, len(in))
   435  	for i, c := range in {
   436  		p := c.(map[string]interface{})
   437  		if name, ok := p["name"]; ok {
   438  			att[i].Name = name.(string)
   439  		}
   440  	}
   441  	return att
   442  }