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 }