func expandFieldTemplate()

in pkg/krmtotf/templating.go [102:202]


func expandFieldTemplate(template string, r *Resource, c client.Client, smLoader *servicemappingloader.ServiceMappingLoader) (string, error) {
	var resolutionError error
	resolveFunc := func(s string) string {
		field := fieldRegex.FindStringSubmatch(s)[1]
		isRequired := true
		if strings.HasSuffix(field, "?") {
			isRequired = false
			field = strings.TrimSuffix(field, "?")
		}
		if isRef, refConfig := IsReferenceField(field, &r.ResourceConfig); isRef {
			val, found, err := getValueFromReference(refConfig, r, c, smLoader)
			if err != nil {
				resolutionError = fmt.Errorf("error getting value from reference: %w", err)
				return ""
			}
			if !found {
				if isRequired {
					resolutionError = fmt.Errorf("required reference '%v' could not be found in spec", field)
				}
				return ""
			}
			return val
		}
		if field == r.ResourceConfig.ResourceID.TargetField {
			val, err := resolveResourceID(r, c, smLoader)
			if err != nil {
				resolutionError = fmt.Errorf("error resolving resource ID: %w", err)
				return ""
			}
			return val
		}
		if field == r.ResourceConfig.MetadataMapping.Name {
			val, err := resolveNameMetadataMapping(r, c, smLoader)
			if err != nil {
				resolutionError = fmt.Errorf("error resolving metadata name mapping value: %w", err)
				return ""
			}
			return val
		}

		if field == r.ResourceConfig.MetadataMapping.Labels {
			resolutionError = fmt.Errorf("cannot map labels (map[string]string) to string field '%v'", field)
			return ""
		}
		if field == "region" && r.ResourceConfig.Locationality == gcp.Regional ||
			field == "zone" && r.ResourceConfig.Locationality == gcp.Zonal {
			if val, exists, _ := unstructured.NestedString(r.Spec, "location"); exists {
				return val
			}
		}
		if !SupportsHierarchicalReferences(&r.ResourceConfig) {
			// TODO(b/193177782): Delete this if-block once all resources
			// support hierarchical references.
			for _, c := range r.ResourceConfig.Containers {
				if field == c.TFField {
					annotation := k8s.GetAnnotationForContainerType(c.Type)
					val, ok := k8s.GetAnnotation(annotation, r)
					if (!ok || val == "") && isRequired {
						resolutionError = fmt.Errorf("no value found for annotation %v", annotation)
						return ""
					}
					return val
				}
			}
		}
		for _, d := range r.ResourceConfig.Directives {
			if field == d {
				annotation := k8s.FormatAnnotation(text.SnakeCaseToKebabCase(d))
				val, ok := k8s.GetAnnotation(annotation, r)
				if (!ok || val == "") && isRequired {
					resolutionError = fmt.Errorf("no value found for annotation %v", annotation)
					return ""
				}
				return val
			}
		}
		path := text.SnakeCaseToLowerCamelCase(field)
		if val, exists, _ := unstructured.NestedString(r.Spec, strings.Split(path, ".")...); exists {
			return val
		}
		if val, exists, _ := unstructured.NestedString(r.GetStatusOrObservedState(), strings.Split(path, ".")...); exists {
			return val
		}

		// Special handling to resolve project from DCL-based resource
		// Only applied to a referenced NetworkSecurityClientTLSPolicy resource
		// and tested by fixtures/globalcomputebackendservicesecuritysettings test for now
		if path == "project" && r.Kind == "NetworkSecurityClientTLSPolicy" {
			dclPath := "projectRef.external"
			if val, exists, _ := unstructured.NestedString(r.Spec, strings.Split(dclPath, ".")...); exists {
				return val
			}
		}

		if isRequired {
			resolutionError = fmt.Errorf("unable to resolve missing value: %v", field)
		}
		return ""
	}
	return fieldRegex.ReplaceAllStringFunc(template, resolveFunc), resolutionError
}