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
}