1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package krmtotf
16
17 import (
18 "fmt"
19 "reflect"
20 "strings"
21
22 corekccv1alpha1 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/core/v1alpha1"
23 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/deepcopy"
24 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/gcp"
25 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
26 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/text"
27 tfresource "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/tf/resource"
28 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/util"
29
30 tfschema "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
31 "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
32 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
33 )
34
35
36
37
38
39
40
41
42
43 func ResolveSpecAndStatus(resource *Resource, state *terraform.InstanceState) (
44 spec map[string]interface{}, status map[string]interface{}) {
45 val, found := k8s.GetAnnotation(k8s.StateIntoSpecAnnotation, resource)
46 if !found || val == k8s.StateMergeIntoSpec {
47 return GetSpecAndStatusFromState(resource, state)
48 }
49 return resolveDesiredStateInSpecAndObservedStateInStatus(resource, state)
50 }
51
52
53
54
55
56
57
58
59
60
61
62
63
64 func GetSpecAndStatusFromState(resource *Resource, state *terraform.InstanceState) (
65 spec map[string]interface{}, status map[string]interface{}) {
66 unmodifiedState := InstanceStateToMap(resource.TFResource, state)
67 krmState := ConvertTFObjToKCCObj(unmodifiedState, resource.Spec, resource.TFResource.Schema,
68 &resource.ResourceConfig, "", resource.ManagedFields)
69 krmState = withCustomExpanders(krmState, resource, resource.Kind)
70 spec = make(map[string]interface{})
71 status = make(map[string]interface{})
72 for field, fieldSchema := range resource.TFResource.Schema {
73 key := text.SnakeCaseToLowerCamelCase(field)
74 if ok, refConfig := IsReferenceField(field, &resource.ResourceConfig); ok && refConfig.Key != "" {
75 key = refConfig.Key
76 }
77 val := krmState[key]
78 if val == nil {
79 continue
80 }
81 target := &spec
82 if !fieldSchema.Required && !fieldSchema.Optional {
83 target = &status
84 key = renameStatusFieldIfNeeded(resource.ResourceConfig.Name, key)
85 }
86 (*target)[key] = val
87 }
88 if location, ok := getLocationValueFromResourceOrState(resource, unmodifiedState); ok {
89 spec["location"] = location
90 }
91 if conditions, ok := resource.Status["conditions"]; ok {
92 status["conditions"] = deepcopy.DeepCopy(conditions)
93 }
94 if observedGeneration, ok := resource.Status["observedGeneration"]; ok {
95 status["observedGeneration"] = deepcopy.DeepCopy(observedGeneration)
96 }
97 if len(spec) == 0 {
98 spec = nil
99 }
100 if len(status) == 0 {
101 status = nil
102 }
103 return spec, status
104 }
105
106
107
108 func ResolveSpecAndStatusWithResourceID(resource *Resource, state *terraform.InstanceState) (
109 spec map[string]interface{}, status map[string]interface{}) {
110 spec, status = ResolveSpecAndStatus(resource, state)
111
112 resourceID, ok := getResourceIDIfSupported(resource, status)
113 if !ok {
114 return spec, status
115 }
116
117 if spec == nil {
118 spec = make(map[string]interface{})
119 }
120 spec[k8s.ResourceIDFieldName] = resourceID
121 return spec, status
122 }
123
124
125
126 func resolveDesiredStateInSpecAndObservedStateInStatus(resource *Resource, state *terraform.InstanceState) (
127 spec map[string]interface{}, status map[string]interface{}) {
128 spec = deepcopy.MapStringInterface(resource.Spec)
129 _, status = GetSpecAndStatusFromState(resource, state)
130 return spec, status
131 }
132
133
134
135
136
137
138
139
140 func getLocationValueFromResourceOrState(resource *Resource, state map[string]interface{}) (interface{}, bool) {
141
142
143
144
145 if location, ok := resource.Spec["location"]; ok {
146 return location, true
147 }
148 if resource.ResourceConfig.Locationality == "" {
149 return "", false
150 }
151 switch resource.ResourceConfig.Locationality {
152 case gcp.Global:
153 return "global", true
154 case gcp.Regional, gcp.Zonal:
155 locationFieldName := getTFFieldNameForLocation(resource.ResourceConfig.Locationality)
156 value, ok := state[locationFieldName]
157 if !ok {
158 return nil, false
159 }
160 return value, true
161 }
162 panic(fmt.Errorf("unknown location type: %v", resource.ResourceConfig.Locationality))
163 }
164
165 func getTFFieldNameForLocation(locType string) string {
166 switch locType {
167 case gcp.Regional:
168 return "region"
169 case gcp.Zonal:
170 return "zone"
171 case gcp.Global:
172 return "global"
173 }
174 panic(fmt.Errorf("unknown location type: %v", locType))
175 }
176
177 func getResourceIDIfSupported(resource *Resource, status map[string]interface{}) (interface{}, bool) {
178 if !SupportsResourceIDField(&resource.ResourceConfig) {
179 return nil, false
180 }
181
182 if resourceID, ok := resource.Spec[k8s.ResourceIDFieldName]; ok {
183 return resourceID, true
184 }
185
186 if IsResourceIDFieldServerGenerated(&resource.ResourceConfig) {
187 serverGeneratedIDFromStatus, exists, err :=
188 getServerGeneratedIDFromStatus(&resource.ResourceConfig, status)
189 if !exists || err != nil {
190 panic(fmt.Errorf("server-generated resource ID not "+
191 "returned for resource Kind '%s', Name '%s', Namespace '%s'",
192 resource.Kind, resource.Name, resource.Namespace))
193 }
194
195 resourceID, err := extractValueSegmentFromIDInStatus(
196 serverGeneratedIDFromStatus,
197 resource.ResourceConfig.ResourceID.ValueTemplate)
198 if err != nil {
199 panic(fmt.Errorf("incorrect format of server-generated "+
200 "resource ID for resource Kind '%s', Name '%s', Namespace "+
201 "'%s'", resource.Kind, resource.Name, resource.Namespace))
202 }
203
204 return resourceID, true
205 }
206
207 resourceID := resource.GetName()
208 if resourceID == "" {
209 panic(fmt.Errorf("user-specified resource ID not found for resource "+
210 "Kind '%s', Name '%s', Namespace '%s'", resource.Kind, resource.Name,
211 resource.Namespace))
212 }
213
214 return resourceID, true
215 }
216
217 func GetLabelsFromState(resource *Resource, rawState *terraform.InstanceState) map[string]string {
218 state := InstanceStateToMap(resource.TFResource, rawState)
219 labelsValue, ok := getNestedMapFromState(state, strings.Split(resource.ResourceConfig.MetadataMapping.Labels, ".")...)
220 if !ok {
221 return make(map[string]string)
222 }
223 result := make(map[string]string, len(labelsValue))
224 for k, v := range labelsValue {
225 result[k] = v.(string)
226 }
227 return result
228 }
229
230 func GetEtagFromState(resource *Resource, rawState *terraform.InstanceState) string {
231 state := InstanceStateToMap(resource.TFResource, rawState)
232 etagValue, ok := getNestedFieldFromState(state, "etag")
233 if ok && etagValue != nil {
234 return etagValue.(string)
235 }
236 return ""
237 }
238
239 func GetNameFromState(resource *Resource, rawState *terraform.InstanceState) string {
240 if resource.ResourceConfig.MetadataMapping.Name == "" {
241 return ""
242 }
243 state := InstanceStateToMap(resource.TFResource, rawState)
244 nameValue, ok := getNestedFieldFromState(state, strings.Split(resource.ResourceConfig.MetadataMapping.Name, ".")...)
245 if ok && nameValue != nil {
246 return nameValue.(string)
247 }
248 return ""
249 }
250
251
252
253
254 func getNestedMapFromState(state map[string]interface{}, fields ...string) (map[string]interface{}, bool) {
255 value, ok := getNestedFieldFromState(state, fields...)
256 if !ok || value == nil {
257 return nil, false
258 }
259 result, ok := value.(map[string]interface{})
260 if !ok {
261 panic(fmt.Sprintf("expected type '%v' instead got '%v'", reflect.TypeOf(make(map[string]interface{})).Name(),
262 reflect.TypeOf(value).Name()))
263 }
264 return result, true
265 }
266
267
268
269
270
271 func getNestedFieldFromState(state map[string]interface{}, fields ...string) (interface{}, bool) {
272 var result interface{}
273 result = state
274 for i := 0; i < len(fields); i++ {
275 subMap, ok := result.(map[string]interface{})
276 if !ok {
277 panic(formatUnexpectedValueTypeInStateMessage(result, i-1, fields...))
278 }
279 result, ok = getFieldFromStateMap(subMap, fields[i])
280
281 if !ok || result == nil {
282 return nil, false
283 }
284 }
285 return result, true
286 }
287
288 func formatUnexpectedValueTypeInStateMessage(value interface{}, fieldNum int, fields ...string) string {
289 expectedType := reflect.TypeOf(make(map[string]interface{})).Name()
290 actualType := reflect.TypeOf(value).Name()
291 if fieldNum < 0 {
292 return fmt.Sprintf("expected type '%v' instead got '%v'", expectedType, actualType)
293 }
294 return fmt.Sprintf("expected '%v' to be of type '%v' instead got '%v'", fields[fieldNum], expectedType, actualType)
295 }
296
297 func getFieldFromStateMap(state map[string]interface{}, field string) (interface{}, bool) {
298 value, ok := state[field]
299 if !ok {
300 return nil, false
301 }
302
303 if listVal, ok := value.([]interface{}); ok {
304 return listVal[0], true
305 }
306 return value, true
307 }
308
309
310 func GetAnnotationsFromState(resource *Resource, rawState *terraform.InstanceState) map[string]string {
311 annotations := make(map[string]string, len(resource.ResourceConfig.Directives)+1)
312 state := InstanceStateToMap(resource.TFResource, rawState)
313 for _, directive := range resource.ResourceConfig.Directives {
314 if isIgnoredField(directive, &resource.ResourceConfig) {
315 continue
316 }
317 value, ok := getValueFromState(state, directive)
318 if !ok {
319 continue
320 }
321 key := k8s.FormatAnnotation(text.SnakeCaseToKebabCase(directive))
322 annotations[key] = value
323 }
324 if !SupportsHierarchicalReferences(&resource.ResourceConfig) {
325
326
327 for _, c := range resource.ResourceConfig.Containers {
328 value, ok := getValueFromState(state, c.TFField)
329 if !ok {
330 continue
331 }
332 if valueMatchesTemplate(c.ValueTemplate, value) {
333 key := k8s.GetAnnotationForContainerType(c.Type)
334 annotations[key] = value
335 }
336 }
337 }
338 return annotations
339 }
340
341 func getValueFromState(state map[string]interface{}, key string) (string, bool) {
342 value, ok := state[key]
343
344 if !ok || value == nil {
345 return "", false
346 }
347 stringValue := fmt.Sprintf("%v", value)
348 if stringValue == "" {
349 return "", false
350 }
351 return stringValue, true
352 }
353
354
355
356
357
358
359
360
361
362
363
364
365 func ConvertTFObjToKCCObj(state map[string]interface{}, prevSpec map[string]interface{},
366 schemas map[string]*tfschema.Schema, rc *corekccv1alpha1.ResourceConfig, prefix string,
367 managedFields *fieldpath.Set) map[string]interface{} {
368 raw := convertTFMapToKCCMap(state, prevSpec, schemas, rc, prefix, managedFields)
369
370 var ret map[string]interface{}
371 if err := util.Marshal(raw, &ret); err != nil {
372 panic(fmt.Errorf("error normalizing KRM-ified object: %v", err))
373 }
374 return ret
375 }
376
377 func convertTFMapToKCCMap(state map[string]interface{}, prevSpec map[string]interface{},
378 schemas map[string]*tfschema.Schema, rc *corekccv1alpha1.ResourceConfig, prefix string,
379 managedFields *fieldpath.Set) map[string]interface{} {
380 ret := make(map[string]interface{})
381 for field, schema := range schemas {
382 qualifiedName := field
383 if prefix != "" {
384 qualifiedName = prefix + "." + field
385 }
386 if isOverriddenField(qualifiedName, rc) {
387 continue
388 }
389 if ok, refConfig := IsReferenceField(qualifiedName, rc); ok {
390 key := GetKeyForReferenceField(refConfig)
391 if val := convertTFReferenceToKCCReference(field, key, state, prevSpec, refConfig); val != nil {
392 ret[key] = val
393 }
394 continue
395 }
396 key := text.SnakeCaseToLowerCamelCase(field)
397 stateVal := state[field]
398 prevSpecVal := prevSpec[key]
399 if stateVal == nil {
400
401
402
403
404
405
406 if prevSpecVal != nil && k8s.IsK8sManaged(key, prevSpec, managedFields) {
407 ret[key] = prevSpecVal
408 }
409 continue
410 }
411 if isGCPManagedField(rc.Kind, qualifiedName) {
412 ret[key] = stateVal
413 continue
414 }
415 switch schema.Type {
416
417
418
419
420
421
422
423 case tfschema.TypeBool:
424 if k8s.IsK8sManaged(key, prevSpec, managedFields) {
425 ret[key] = prevSpecVal
426 } else if schema.Required || stateVal.(bool) || (schema.Default != nil && schema.Default != stateVal) {
427 ret[key] = stateVal
428 }
429 case tfschema.TypeFloat, tfschema.TypeInt:
430
431
432 if k8s.IsK8sManaged(key, prevSpec, managedFields) {
433 ret[key] = prevSpecVal
434 } else if schema.Required || stateVal.(float64) != 0 || (schema.Default != nil && schema.Default != stateVal) {
435 ret[key] = stateVal
436 }
437 case tfschema.TypeString:
438 if k8s.IsK8sManaged(key, prevSpec, managedFields) {
439 ret[key] = prevSpecVal
440 } else {
441 if stateVal.(string) == "" {
442 continue
443 }
444 if tfresource.IsSensitiveConfigurableField(schema) {
445 val := stateVal.(string)
446 ret[key] = corekccv1alpha1.SensitiveField{
447 Value: &val,
448 }
449 } else {
450 ret[key] = stateVal
451 }
452 }
453 case tfschema.TypeList, tfschema.TypeSet:
454 list, ok := stateVal.([]interface{})
455 if !ok {
456 panic(fmt.Sprintf("interface conversion for field %v in resource %v: interface {} is %T, not []interface {}. prevSpecVal: %v, stateVal: %v", qualifiedName, rc.Name, stateVal, prevSpecVal, stateVal))
457 }
458 if len(list) == 0 {
459 continue
460 }
461 if schema.MaxItems == 1 {
462
463 tfObjMap := list[0].(map[string]interface{})
464 tfObjSchema := schema.Elem.(*tfschema.Resource).Schema
465 prevObjMap, _ := prevSpecVal.(map[string]interface{})
466 var nestedManagedFields *fieldpath.Set
467 if managedFields != nil {
468 pe := fieldpath.PathElement{FieldName: &key}
469 var found bool
470 nestedManagedFields, found = managedFields.Children.Get(pe)
471 if !found {
472 nestedManagedFields = fieldpath.NewSet()
473 }
474 }
475 if val := convertTFMapToKCCMap(tfObjMap, prevObjMap, tfObjSchema, rc, qualifiedName, nestedManagedFields); val != nil {
476 ret[key] = val
477 }
478 continue
479 }
480 if schema.Type == tfschema.TypeSet {
481
482
483
484
485 if schema.Required || schema.Optional {
486 retObj := convertTFSetToKCCSet(stateVal, prevSpecVal, schema, rc, qualifiedName)
487 if retObj != nil {
488 ret[key] = retObj
489 }
490 continue
491 }
492 }
493
494 switch schema.Elem.(type) {
495 case *tfschema.Schema:
496
497 ret[key] = deepcopy.DeepCopy(list)
498 case *tfschema.Resource:
499
500 prevList, _ := prevSpecVal.([]interface{})
501 tfObjSchema := schema.Elem.(*tfschema.Resource).Schema
502 retObjList := make([]interface{}, 0)
503 for idx, elem := range list {
504 tfObjMap := elem.(map[string]interface{})
505 var prevObjMap map[string]interface{}
506 if idx < len(prevList) {
507 prevObjMap, _ = prevList[idx].(map[string]interface{})
508 }
509 if val := convertTFMapToKCCMap(tfObjMap, prevObjMap, tfObjSchema, rc, qualifiedName, nil); val != nil {
510 retObjList = append(retObjList, val)
511 }
512 }
513 if len(retObjList) == 0 {
514 continue
515 }
516 ret[key] = retObjList
517 }
518 case tfschema.TypeMap:
519 if k8s.IsK8sManaged(key, prevSpec, managedFields) {
520 ret[key] = prevSpecVal
521 continue
522 }
523 m := stateVal.(map[string]interface{})
524
525 if len(m) == 0 {
526 continue
527 }
528
529
530 ret[key] = deepcopy.DeepCopy(m)
531 case tfschema.TypeInvalid:
532 panic("invalid schema type")
533 default:
534 panic(fmt.Errorf("unrecognized schema type %v", schema.Type))
535 }
536 }
537 if len(ret) == 0 {
538 return nil
539 }
540 return ret
541 }
542
543
544
545
546 func convertTFReferenceToKCCReference(tfField, specKey string, state map[string]interface{}, prevSpec map[string]interface{}, refConfig *corekccv1alpha1.ReferenceConfig) interface{} {
547 if prevSpecVal, ok := prevSpec[specKey]; ok {
548
549
550 return prevSpecVal
551 }
552
553 if state[tfField] == nil {
554 return nil
555 }
556
557
558
559
560
561 switch stateVal := state[tfField].(type) {
562 case string:
563 if stateVal == "" {
564 return nil
565 }
566 if len(refConfig.Types) > 0 {
567
568 defaultType := refConfig.Types[0]
569 if defaultType.JSONSchemaType != "" {
570 return map[string]interface{}{
571 defaultType.Key: stateVal,
572 }
573 } else {
574 return map[string]interface{}{
575 defaultType.Key: corekccv1alpha1.ResourceReference{
576 External: stateVal,
577 },
578 }
579 }
580 }
581 return corekccv1alpha1.ResourceReference{
582 External: stateVal,
583 }
584 case []interface{}:
585 if len(stateVal) == 0 {
586 return nil
587 }
588 refs := make([]interface{}, 0)
589 for _, elem := range stateVal {
590 var newRef interface{}
591 newRef = corekccv1alpha1.ResourceReference{
592 External: elem.(string),
593 }
594
595 if len(refConfig.Types) > 0 {
596 newRef = map[string]interface{}{
597 refConfig.Types[0].Key: newRef,
598 }
599 }
600 refs = append(refs, newRef)
601 }
602 return refs
603 default:
604 panic(fmt.Errorf("value of TF reference field '%v' was neither a string nor a list", tfField))
605 }
606 }
607
608
609 func convertTFSetToKCCSet(stateVal, prevSpecVal interface{}, schema *tfschema.Schema, rc *corekccv1alpha1.ResourceConfig, prefix string) interface{} {
610 if containsReferenceField(prefix, rc) {
611
612
613 return prevSpecVal
614 }
615 list := stateVal.([]interface{})
616 if len(list) == 0 {
617 return nil
618 }
619
620 hashFunc := getHashFuncForSchema(schema)
621 stateHashMap := make(map[int]interface{})
622 for _, val := range list {
623 stateHashMap[hashFunc(asHashable(val, schema.Elem))] = val
624 }
625
626
627 prevList, _ := prevSpecVal.([]interface{})
628 retObjList := make([]interface{}, 0)
629 for _, prevElem := range prevList {
630 if prevElem == nil {
631 retObjList = append(retObjList, nil)
632 continue
633 }
634 var prevHashable interface{}
635 switch schemaElem := schema.Elem.(type) {
636 case *tfschema.Schema:
637 prevHashable = asHashable(prevElem, schemaElem)
638 case *tfschema.Resource:
639
640 prevElemAsTFObject, err := KRMObjectToTFObject(prevElem.(map[string]interface{}), schemaElem)
641 if err != nil {
642 panic(fmt.Errorf("error converting set object: %v", err))
643 }
644 prevHashable = asHashable(prevElemAsTFObject, schemaElem)
645 default:
646 panic(fmt.Errorf("unknown schema element type %v", schemaElem))
647 }
648 hash := hashFunc(prevHashable)
649 stateElem, ok := stateHashMap[hash]
650
651
652 if ok {
653 delete(stateHashMap, hash)
654 } else {
655 stateElem = map[string]interface{}{}
656 }
657 retObjList = append(retObjList,
658 convertTFElemToKCCElem(schema.Elem, stateElem, prevElem, rc, prefix))
659 }
660
661 for _, newElem := range stateHashMap {
662 retObjList = append(retObjList,
663 convertTFElemToKCCElem(schema.Elem, newElem, nil, rc, prefix))
664 }
665 if len(retObjList) == 0 {
666 return nil
667 }
668 return retObjList
669 }
670
671 func getHashFuncForSchema(schema *tfschema.Schema) tfschema.SchemaSetFunc {
672
673 hashFunc := schema.Set
674 if hashFunc == nil {
675 switch schemaElem := schema.Elem.(type) {
676 case *tfschema.Schema:
677 hashFunc = tfschema.HashSchema(schemaElem)
678 case *tfschema.Resource:
679 hashFunc = tfschema.HashResource(schemaElem)
680 }
681 }
682 return hashFunc
683 }
684
685 func asHashable(o, schemaElem interface{}) interface{} {
686 if o == nil {
687 return nil
688 }
689 switch schemaElem := schemaElem.(type) {
690 case *tfschema.Schema:
691
692
693 key := "k"
694 reader := tfschema.MapFieldReader{
695 Map: tfschema.BasicMapReader(map[string]string{key: fmt.Sprintf("%v", o)}),
696 Schema: map[string]*tfschema.Schema{key: schemaElem},
697 }
698 val, err := reader.ReadField([]string{key})
699 if err != nil {
700 panic(fmt.Errorf("unable to convert field to hashable: %v", err))
701 }
702 var ret interface{}
703 if val.Exists {
704 ret = val.Value
705 }
706 return ret
707 case *tfschema.Resource:
708
709
710
711
712 m := o.(map[string]interface{})
713 reader := tfschema.MapFieldReader{
714 Map: tfschema.BasicMapReader(MapToInstanceState(schemaElem, m).Attributes),
715 Schema: schemaElem.Schema,
716 }
717 res := make(map[string]interface{})
718 for k, s := range schemaElem.Schema {
719 val, err := reader.ReadField([]string{k})
720 if err != nil {
721 panic(fmt.Errorf("unable to read field %v: %v", k, err))
722 }
723 if val.Exists {
724 res[k] = val.Value
725 } else {
726 res[k] = getDefaultValueForTFType(s.Type)
727 }
728 }
729 return res
730 default:
731 panic(fmt.Errorf("unknown schema element type %v", schemaElem))
732 }
733 }
734
735 func getDefaultValueForTFType(tfType tfschema.ValueType) interface{} {
736 switch tfType {
737 case tfschema.TypeBool:
738 return false
739 case tfschema.TypeString:
740 return ""
741 case tfschema.TypeFloat:
742 return 0.0
743 case tfschema.TypeInt:
744 return 0
745 case tfschema.TypeList:
746 return make([]interface{}, 0)
747 case tfschema.TypeSet:
748 return &tfschema.Set{}
749 case tfschema.TypeMap:
750 return make(map[string]interface{})
751 case tfschema.TypeInvalid:
752 panic("schema type is invalid")
753 default:
754 panic(fmt.Errorf("unrecognized schema type %v", tfType))
755 }
756 }
757
758 func convertTFElemToKCCElem(elemSchema, tfObj, prevSpecObj interface{}, rc *corekccv1alpha1.ResourceConfig, prefix string) interface{} {
759 switch elemSchema.(type) {
760 case *tfschema.Schema:
761 if prevSpecObj != nil {
762 return prevSpecObj
763 }
764 return tfObj
765 case *tfschema.Resource:
766 tfObjSchema := elemSchema.(*tfschema.Resource).Schema
767 tfObjMap, _ := tfObj.(map[string]interface{})
768 prevObjMap, _ := prevSpecObj.(map[string]interface{})
769 return convertTFMapToKCCMap(tfObjMap, prevObjMap, tfObjSchema, rc, prefix, nil)
770 default:
771 return prevSpecObj
772 }
773 }
774
775 func isOverriddenField(field string, rc *corekccv1alpha1.ResourceConfig) bool {
776 if field == rc.MetadataMapping.Name || field == rc.MetadataMapping.Labels {
777 return true
778 }
779 if rc.Locationality != "" && (field == "zone" || field == "region") {
780 return true
781 }
782 if isIgnoredField(field, rc) {
783 return true
784 }
785 for _, f := range rc.Directives {
786 if field == f {
787 return true
788 }
789 }
790 if !SupportsHierarchicalReferences(rc) {
791
792
793 for _, c := range rc.Containers {
794 if field == c.TFField {
795 return true
796 }
797 }
798
799 }
800 return false
801 }
802
803 func isIgnoredField(field string, rc *corekccv1alpha1.ResourceConfig) bool {
804 for _, f := range rc.IgnoredFields {
805 if field == f {
806 return true
807 }
808 }
809 return false
810 }
811
812 func renameStatusFieldIfNeeded(tfResourceName, key string) string {
813 reservedNames := k8s.ReservedStatusFieldNames()
814 if _, found := reservedNames[key]; found {
815 return k8s.RenameStatusFieldWithReservedNameIfResourceNotExcluded(tfResourceName, key)
816 }
817 return key
818 }
819
View as plain text