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