diff --git a/pkg/resource/sensitive.go b/pkg/resource/sensitive.go index 29cfb16..2a37f83 100644 --- a/pkg/resource/sensitive.go +++ b/pkg/resource/sensitive.go @@ -25,6 +25,7 @@ import ( v1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/crossplane/crossplane-runtime/pkg/fieldpath" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" + "github.com/crossplane/crossplane-runtime/pkg/resource" "github.com/pkg/errors" kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -212,9 +213,15 @@ func GetSensitiveParameters(ctx context.Context, client SecretClient, from runti sensitives := make(map[string]interface{}) for key, value := range *sel { sensitive, err = client.GetSecretValue(ctx, value) - if err != nil { + if resource.IgnoreNotFound(err) != nil { return errors.Wrapf(err, errFmtCannotGetSecretValue, sel) } + + // If referenced k8s secret is deleted before the MR, we pass empty string for the sensitive + // field to be able to destroy the resource. + if kerrors.IsNotFound(err) { + sensitive = []byte("") + } sensitives[key] = string(sensitive) } if err := setSensitiveParametersWithPaved(pavedTF, expandedJSONPath, tfPath, mapping, sensitives); err != nil { @@ -226,7 +233,7 @@ func GetSensitiveParameters(ctx context.Context, client SecretClient, from runti return errors.Wrapf(err, errFmtCannotGetSecretKeySelector, expandedJSONPath) } sensitive, err = client.GetSecretValue(ctx, *sel) - if err != nil { + if resource.IgnoreNotFound(err) != nil { return errors.Wrapf(err, errFmtCannotGetSecretValue, sel) } if err := setSensitiveParametersWithPaved(pavedTF, expandedJSONPath, tfPath, mapping, string(sensitive)); err != nil { @@ -241,9 +248,15 @@ func GetSensitiveParameters(ctx context.Context, client SecretClient, from runti var sensitives []interface{} for _, s := range *sel { sensitive, err = client.GetSecretValue(ctx, s) - if err != nil { + if resource.IgnoreNotFound(err) != nil { return errors.Wrapf(err, errFmtCannotGetSecretValue, sel) } + + // If referenced k8s secret is deleted before the MR, we pass empty string for the sensitive + // field to be able to destroy the resource. + if kerrors.IsNotFound(err) { + sensitive = []byte("") + } sensitives = append(sensitives, string(sensitive)) } if err := setSensitiveParametersWithPaved(pavedTF, expandedJSONPath, tfPath, mapping, sensitives); err != nil { diff --git a/pkg/resource/sensitive_test.go b/pkg/resource/sensitive_test.go index 866d17c..78204c5 100644 --- a/pkg/resource/sensitive_test.go +++ b/pkg/resource/sensitive_test.go @@ -26,6 +26,8 @@ import ( "github.com/golang/mock/gomock" "github.com/google/go-cmp/cmp" "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -511,6 +513,44 @@ func TestGetSensitiveParameters(t *testing.T) { }, }, }, + "SingleNoWildcardWithNoSecret": { + args: args{ + clientFn: func(client *mocks.MockSecretClient) { + client.EXPECT().GetSecretValue(gomock.Any(), gomock.Eq(xpv1.SecretKeySelector{ + SecretReference: xpv1.SecretReference{ + Name: "admin-password", + Namespace: "crossplane-system", + }, + Key: "pass", + })).Return([]byte(""), kerrors.NewNotFound(v1.Resource("secret"), "admin-password")) + }, + from: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "forProvider": map[string]interface{}{ + "adminPasswordSecretRef": map[string]interface{}{ + "key": "pass", + "name": "admin-password", + "namespace": "crossplane-system", + }, + }, + }, + }, + }, + into: map[string]interface{}{ + "some_other_key": "some_other_value", + }, + mapping: map[string]string{ + "admin_password": "spec.forProvider.adminPasswordSecretRef", + }, + }, + want: want{ + out: map[string]interface{}{ + "some_other_key": "some_other_value", + "admin_password": "", + }, + }, + }, "SingleNoWildcardWithSlice": { args: args{ clientFn: func(client *mocks.MockSecretClient) {