From b0089fb1a6d5025facfdfa05f01b4b4e39700df7 Mon Sep 17 00:00:00 2001 From: Alper Rifat Ulucinar Date: Sun, 21 Apr 2024 03:19:49 +0300 Subject: [PATCH] Fix connection details state value map conversion - Fix runtime conversion for expanded field paths of length greater than 1. Signed-off-by: Alper Rifat Ulucinar --- pkg/config/conversion/runtime_conversion.go | 21 ++++++-------- pkg/controller/external_tfpluginsdk.go | 31 +++++++++++++-------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/pkg/config/conversion/runtime_conversion.go b/pkg/config/conversion/runtime_conversion.go index 73d8fb89..d3b22016 100644 --- a/pkg/config/conversion/runtime_conversion.go +++ b/pkg/config/conversion/runtime_conversion.go @@ -89,18 +89,15 @@ func Convert(params map[string]any, paths []string, mode Mode) (map[string]any, if err != nil { return nil, errors.Wrapf(err, "cannot expand wildcards for the field path expression %s", fp) } - switch len(exp) { - case 0: - continue - case 1: - v, err := pv.GetValue(exp[0]) + for _, e := range exp { + v, err := pv.GetValue(e) if err != nil { - return nil, errors.Wrapf(err, "cannot get the value at the field path %s with the conversion mode set to %q", exp[0], mode) + return nil, errors.Wrapf(err, "cannot get the value at the field path %s with the conversion mode set to %q", e, mode) } switch mode { case ToSingletonList: - if err := setValue(pv, []any{v}, exp[0]); err != nil { - return nil, errors.Wrapf(err, "cannot set the singleton list's value at the field path %s", exp[0]) + if err := setValue(pv, []any{v}, e); err != nil { + return nil, errors.Wrapf(err, "cannot set the singleton list's value at the field path %s", e) } case ToEmbeddedObject: var newVal any = nil @@ -109,18 +106,16 @@ func Convert(params map[string]any, paths []string, mode Mode) (map[string]any, s, ok := v.([]any) if !ok || len(s) > 1 { // if len(s) is 0, then it's not a slice - return nil, errors.Errorf("singleton list, at the field path %s, must have a length of at most 1 but it has a length of %d", exp[0], len(s)) + return nil, errors.Errorf("singleton list, at the field path %s, must have a length of at most 1 but it has a length of %d", e, len(s)) } if len(s) > 0 { newVal = s[0] } } - if err := setValue(pv, newVal, exp[0]); err != nil { - return nil, errors.Wrapf(err, "cannot set the embedded object's value at the field path %s", exp[0]) + if err := setValue(pv, newVal, e); err != nil { + return nil, errors.Wrapf(err, "cannot set the embedded object's value at the field path %s", e) } } - default: - return nil, errors.Errorf("unexpected number of expansions (%d) for the wildcard field path expression %s", len(exp), fp) } } return params, nil diff --git a/pkg/controller/external_tfpluginsdk.go b/pkg/controller/external_tfpluginsdk.go index 0262e0f0..8b82877e 100644 --- a/pkg/controller/external_tfpluginsdk.go +++ b/pkg/controller/external_tfpluginsdk.go @@ -503,11 +503,12 @@ func (n *terraformPluginSDKExternal) Observe(ctx context.Context, mg xpresource. n.instanceDiff = instanceDiff noDiff := instanceDiff.Empty() - var connDetails managed.ConnectionDetails if !resourceExists && mg.GetDeletionTimestamp() != nil { gvk := mg.GetObjectKind().GroupVersionKind() metrics.DeletionTime.WithLabelValues(gvk.Group, gvk.Version, gvk.Kind).Observe(time.Since(mg.GetDeletionTimestamp().Time).Seconds()) } + + var connDetails managed.ConnectionDetails specUpdateRequired := false if resourceExists { if mg.GetCondition(xpv1.TypeReady).Status == corev1.ConditionUnknown || @@ -516,9 +517,17 @@ func (n *terraformPluginSDKExternal) Observe(ctx context.Context, mg xpresource. } mg.SetConditions(xpv1.Available()) + // we get the connection details from the observed state before + // the conversion because the sensitive paths assume the native Terraform + // schema. + connDetails, err = resource.GetConnectionDetails(stateValueMap, mg.(resource.Terraformed), n.config) + if err != nil { + return managed.ExternalObservation{}, errors.Wrap(err, "cannot get connection details") + } + stateValueMap, err = conversion.Convert(stateValueMap, n.config.TFListConversionPaths(), conversion.ToEmbeddedObject) if err != nil { - return managed.ExternalObservation{}, err + return managed.ExternalObservation{}, errors.Wrap(err, "cannot convert the singleton lists in the observed state value map into embedded objects") } buff, err := json.TFParser.Marshal(stateValueMap) if err != nil { @@ -538,10 +547,6 @@ func (n *terraformPluginSDKExternal) Observe(ctx context.Context, mg xpresource. if err != nil { return managed.ExternalObservation{}, errors.Errorf("could not set observation: %v", err) } - connDetails, err = resource.GetConnectionDetails(stateValueMap, mg.(resource.Terraformed), n.config) - if err != nil { - return managed.ExternalObservation{}, errors.Wrap(err, "cannot get connection details") - } if noDiff { n.metricRecorder.SetReconcileTime(mg.GetName()) @@ -632,18 +637,22 @@ func (n *terraformPluginSDKExternal) Create(ctx context.Context, mg xpresource.M if _, err := n.setExternalName(mg, stateValueMap); err != nil { return managed.ExternalCreation{}, errors.Wrap(err, "failed to set the external-name of the managed resource during create") } + // we get the connection details from the observed state before + // the conversion because the sensitive paths assume the native Terraform + // schema. + conn, err := resource.GetConnectionDetails(stateValueMap, mg.(resource.Terraformed), n.config) + if err != nil { + return managed.ExternalCreation{}, errors.Wrap(err, "cannot get connection details") + } + stateValueMap, err = conversion.Convert(stateValueMap, n.config.TFListConversionPaths(), conversion.ToEmbeddedObject) if err != nil { - return managed.ExternalCreation{}, err + return managed.ExternalCreation{}, errors.Wrap(err, "cannot convert the singleton lists in the state value map of the newly created resource into embedded objects") } err = mg.(resource.Terraformed).SetObservation(stateValueMap) if err != nil { return managed.ExternalCreation{}, errors.Errorf("could not set observation: %v", err) } - conn, err := resource.GetConnectionDetails(stateValueMap, mg.(resource.Terraformed), n.config) - if err != nil { - return managed.ExternalCreation{}, errors.Wrap(err, "cannot get connection details") - } return managed.ExternalCreation{ConnectionDetails: conn}, nil }