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 }