diff --git a/config/common/common.go b/config/common/common.go index 05d864e004..08e43f25ed 100644 --- a/config/common/common.go +++ b/config/common/common.go @@ -16,6 +16,7 @@ import ( xpresource "github.com/crossplane/crossplane-runtime/pkg/resource" "github.com/crossplane/upjet/pkg/config" "github.com/crossplane/upjet/pkg/resource" + jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" @@ -126,3 +127,18 @@ func PasswordGenerator(secretRefFieldPath, toggleFieldPath string) config.NewIni }) } } + +// RemovePolicyVersion removes the "Version" field from a JSON-encoded policy string. +func RemovePolicyVersion(p string) (string, error) { + var policy any + if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(p), &policy); err != nil { + return "", errors.Wrap(err, "failed to unmarshal the policy from JSON") + } + m, ok := policy.(map[string]any) + if !ok { + return p, nil + } + delete(m, "Version") + r, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(m) + return string(r), errors.Wrap(err, "failed to marshal the policy map as JSON") +} diff --git a/config/sns/config.go b/config/sns/config.go index 3913cd0103..702a1e028c 100644 --- a/config/sns/config.go +++ b/config/sns/config.go @@ -8,7 +8,6 @@ import ( "github.com/crossplane/upjet/pkg/config" awspolicy "github.com/hashicorp/awspolicyequivalence" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" "github.com/upbound/provider-aws/config/common" @@ -35,11 +34,11 @@ func Configure(p *config.Provider) { return diff, nil } - vOld, err := removePolicyVersion(diff.Attributes["policy"].Old) + vOld, err := common.RemovePolicyVersion(diff.Attributes["policy"].Old) if err != nil { return nil, errors.Wrap(err, "failed to remove Version from the old AWS policy document") } - vNew, err := removePolicyVersion(diff.Attributes["policy"].New) + vNew, err := common.RemovePolicyVersion(diff.Attributes["policy"].New) if err != nil { return nil, errors.Wrap(err, "failed to remove Version from the new AWS policy document") } @@ -55,17 +54,3 @@ func Configure(p *config.Provider) { } }) } - -func removePolicyVersion(p string) (string, error) { - var policy any - if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(p), &policy); err != nil { - return "", errors.Wrap(err, "failed to unmarshal the policy from JSON") - } - m, ok := policy.(map[string]any) - if !ok { - return p, nil - } - delete(m, "Version") - r, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(m) - return string(r), errors.Wrap(err, "failed to marshal the policy map as JSON") -} diff --git a/config/sqs/config.go b/config/sqs/config.go index 2c6e190fa9..6ececc5a39 100644 --- a/config/sqs/config.go +++ b/config/sqs/config.go @@ -6,6 +6,9 @@ package sqs import ( "github.com/crossplane/upjet/pkg/config" + awspolicy "github.com/hashicorp/awspolicyequivalence" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/pkg/errors" "github.com/upbound/provider-aws/config/common" ) @@ -30,6 +33,30 @@ func Configure(p *config.Provider) { // If the key policy is unset on the Queue resource, don't late initialize it, to avoid conflicts with the policy // managed by a QueuePolicy resource. r.LateInitializer.IgnoredFields = append(r.LateInitializer.IgnoredFields, "name_prefix", "policy") + r.TerraformCustomDiff = func(diff *terraform.InstanceDiff, _ *terraform.InstanceState, _ *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { + if diff == nil || diff.Attributes["policy"] == nil || diff.Attributes["policy"].Old == "" || diff.Attributes["policy"].New == "" { + return diff, nil + } + + vOld, err := common.RemovePolicyVersion(diff.Attributes["policy"].Old) + if err != nil { + return nil, errors.Wrap(err, "failed to remove Version from the old AWS policy document") + } + vNew, err := common.RemovePolicyVersion(diff.Attributes["policy"].New) + if err != nil { + return nil, errors.Wrap(err, "failed to remove Version from the new AWS policy document") + } + + ok, err := awspolicy.PoliciesAreEquivalent(vOld, vNew) + if err != nil { + return nil, errors.Wrap(err, "failed to compare the old and the new AWS policy documents") + } + if ok { + delete(diff.Attributes, "policy") + } + return diff, nil + } + }) p.AddResourceConfigurator("aws_sqs_queue_redrive_policy", func(r *config.Resource) { diff --git a/examples/sqs/v1beta1/queue-with-policy.yaml b/examples/sqs/v1beta1/queue-with-policy.yaml new file mode 100644 index 0000000000..c4f31d1d05 --- /dev/null +++ b/examples/sqs/v1beta1/queue-with-policy.yaml @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2024 The Crossplane Authors +# +# SPDX-License-Identifier: CC0-1.0 + +apiVersion: sqs.aws.upbound.io/v1beta1 +kind: Queue +metadata: + name: example-with-policy + labels: + testing.upbound.io/example-name: example +spec: + forProvider: + name: upbound-sqs-with-policy + policy: | + { + "Statement": [ + { + "Sid": "example", + "Effect": "Allow", + "Principal": { + "Service": "s3.amazonaws.com" + }, + "Action": "sqs:SendMessage", + "Resource": "arn:aws:sqs:us-west-1:*:queue-policy" + } + ] + } + delaySeconds: 90 + maxMessageSize: 2048 + messageRetentionSeconds: 86400 + receiveWaitTimeSeconds: 10 + region: us-west-1 + tags: + Environment: production + writeConnectionSecretToRef: + name: "upbound-sqs-with-policy" + namespace: "upbound-system"