diff --git a/apis/mq/generator-config.yaml b/apis/mq/generator-config.yaml
index 610a06d889..5f5f35f582 100644
--- a/apis/mq/generator-config.yaml
+++ b/apis/mq/generator-config.yaml
@@ -1,4 +1,6 @@
ignore:
+ operations:
+ - UpdateConfiguration
field_paths:
- CreateBrokerRequest.Users
- CreateBrokerRequest.BrokerName
@@ -7,9 +9,20 @@ ignore:
- CreateUserRequest.Username
- CreateUserRequest.BrokerId
- CreateUserRequest.Password
- resource_names:
- - Configuration
resources:
+ Configuration:
+ fields:
+ LatestRevision.Data:
+ is_read_only: true
+ from:
+ operation: DescribeConfigurationRevision
+ path: Data
+ Tags:
+ is_read_only: true
+ from:
+ operation: DescribeConfiguration
+ path: Tags
+
Broker:
fields:
BrokerInstances:
diff --git a/apis/mq/v1alpha1/custom_types.go b/apis/mq/v1alpha1/custom_types.go
index df70f4fac3..ee103eaa4d 100644
--- a/apis/mq/v1alpha1/custom_types.go
+++ b/apis/mq/v1alpha1/custom_types.go
@@ -81,3 +81,18 @@ type CustomUserParameters struct {
PasswordSecretRef xpv1.SecretKeySelector `json:"passwordSecretRef,omitempty"`
}
+
+// CustomConfigurationParameters contains the additional fields for CustomConfigurationParameters
+type CustomConfigurationParameters struct {
+ Data *string `json:"data,omitempty"`
+ Description *string `json:"description,omitempty"`
+}
+
+const (
+ // LatestUnsanitizedConfiguration is the key in the annotations map of a
+ // Configuration resource to track the latest unsanitized version
+ // and stop the update loop if the external update result always results in
+ // sanitization of the desired configuration.spec.data
+ // the latest desired config is stored as
+ LatestUnsanitizedConfiguration = "crossplane.io/latest-unsanitized-desired"
+)
diff --git a/apis/mq/v1alpha1/zz_configuration.go b/apis/mq/v1alpha1/zz_configuration.go
new file mode 100644
index 0000000000..d7fdf2f431
--- /dev/null
+++ b/apis/mq/v1alpha1/zz_configuration.go
@@ -0,0 +1,111 @@
+/*
+Copyright 2021 The Crossplane Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by ack-generate. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// ConfigurationParameters defines the desired state of Configuration
+type ConfigurationParameters struct {
+ // Region is which region the Configuration will be created.
+ // +kubebuilder:validation:Required
+ Region string `json:"region"`
+
+ AuthenticationStrategy *string `json:"authenticationStrategy,omitempty"`
+
+ // +kubebuilder:validation:Required
+ EngineType *string `json:"engineType"`
+
+ // +kubebuilder:validation:Required
+ EngineVersion *string `json:"engineVersion"`
+
+ // +kubebuilder:validation:Required
+ Name *string `json:"name"`
+
+ Tags map[string]*string `json:"tags,omitempty"`
+ CustomConfigurationParameters `json:",inline"`
+}
+
+// ConfigurationSpec defines the desired state of Configuration
+type ConfigurationSpec struct {
+ xpv1.ResourceSpec `json:",inline"`
+ ForProvider ConfigurationParameters `json:"forProvider"`
+}
+
+// ConfigurationObservation defines the observed state of Configuration
+type ConfigurationObservation struct {
+ ARN *string `json:"arn,omitempty"`
+
+ Created *metav1.Time `json:"created,omitempty"`
+
+ ID *string `json:"id,omitempty"`
+
+ LatestRevision *ConfigurationRevision `json:"latestRevision,omitempty"`
+
+ LatestRevisionData *string `json:"latestRevisionData,omitempty"`
+
+ Tags map[string]*string `json:"tags,omitempty"`
+}
+
+// ConfigurationStatus defines the observed state of Configuration.
+type ConfigurationStatus struct {
+ xpv1.ResourceStatus `json:",inline"`
+ AtProvider ConfigurationObservation `json:"atProvider,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// Configuration is the Schema for the Configurations API
+// +kubebuilder:printcolumn:name="READY",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status"
+// +kubebuilder:printcolumn:name="SYNCED",type="string",JSONPath=".status.conditions[?(@.type=='Synced')].status"
+// +kubebuilder:printcolumn:name="EXTERNAL-NAME",type="string",JSONPath=".metadata.annotations.crossplane\\.io/external-name"
+// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
+// +kubebuilder:subresource:status
+// +kubebuilder:storageversion
+// +kubebuilder:resource:scope=Cluster,categories={crossplane,managed,aws}
+type Configuration struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+ Spec ConfigurationSpec `json:"spec"`
+ Status ConfigurationStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ConfigurationList contains a list of Configurations
+type ConfigurationList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []Configuration `json:"items"`
+}
+
+// Repository type metadata.
+var (
+ ConfigurationKind = "Configuration"
+ ConfigurationGroupKind = schema.GroupKind{Group: CRDGroup, Kind: ConfigurationKind}.String()
+ ConfigurationKindAPIVersion = ConfigurationKind + "." + GroupVersion.String()
+ ConfigurationGroupVersionKind = GroupVersion.WithKind(ConfigurationKind)
+)
+
+func init() {
+ SchemeBuilder.Register(&Configuration{}, &ConfigurationList{})
+}
diff --git a/apis/mq/v1alpha1/zz_generated.deepcopy.go b/apis/mq/v1alpha1/zz_generated.deepcopy.go
index afe2b84e76..bc8e3ea382 100644
--- a/apis/mq/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/mq/v1alpha1/zz_generated.deepcopy.go
@@ -526,13 +526,92 @@ func (in *BrokerSummary) DeepCopy() *BrokerSummary {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Configuration) DeepCopyInto(out *Configuration) {
*out = *in
- if in.ARN != nil {
- in, out := &in.ARN, &out.ARN
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Configuration.
+func (in *Configuration) DeepCopy() *Configuration {
+ if in == nil {
+ return nil
+ }
+ out := new(Configuration)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *Configuration) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ConfigurationID) DeepCopyInto(out *ConfigurationID) {
+ *out = *in
+ if in.ID != nil {
+ in, out := &in.ID, &out.ID
*out = new(string)
**out = **in
}
- if in.AuthenticationStrategy != nil {
- in, out := &in.AuthenticationStrategy, &out.AuthenticationStrategy
+ if in.Revision != nil {
+ in, out := &in.Revision, &out.Revision
+ *out = new(int64)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationID.
+func (in *ConfigurationID) DeepCopy() *ConfigurationID {
+ if in == nil {
+ return nil
+ }
+ out := new(ConfigurationID)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ConfigurationList) DeepCopyInto(out *ConfigurationList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]Configuration, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationList.
+func (in *ConfigurationList) DeepCopy() *ConfigurationList {
+ if in == nil {
+ return nil
+ }
+ out := new(ConfigurationList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ConfigurationList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ConfigurationObservation) DeepCopyInto(out *ConfigurationObservation) {
+ *out = *in
+ if in.ARN != nil {
+ in, out := &in.ARN, &out.ARN
*out = new(string)
**out = **in
}
@@ -540,8 +619,54 @@ func (in *Configuration) DeepCopyInto(out *Configuration) {
in, out := &in.Created, &out.Created
*out = (*in).DeepCopy()
}
- if in.Description != nil {
- in, out := &in.Description, &out.Description
+ if in.ID != nil {
+ in, out := &in.ID, &out.ID
+ *out = new(string)
+ **out = **in
+ }
+ if in.LatestRevision != nil {
+ in, out := &in.LatestRevision, &out.LatestRevision
+ *out = new(ConfigurationRevision)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.LatestRevisionData != nil {
+ in, out := &in.LatestRevisionData, &out.LatestRevisionData
+ *out = new(string)
+ **out = **in
+ }
+ if in.Tags != nil {
+ in, out := &in.Tags, &out.Tags
+ *out = make(map[string]*string, len(*in))
+ for key, val := range *in {
+ var outVal *string
+ if val == nil {
+ (*out)[key] = nil
+ } else {
+ inVal := (*in)[key]
+ in, out := &inVal, &outVal
+ *out = new(string)
+ **out = **in
+ }
+ (*out)[key] = outVal
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationObservation.
+func (in *ConfigurationObservation) DeepCopy() *ConfigurationObservation {
+ if in == nil {
+ return nil
+ }
+ out := new(ConfigurationObservation)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ConfigurationParameters) DeepCopyInto(out *ConfigurationParameters) {
+ *out = *in
+ if in.AuthenticationStrategy != nil {
+ in, out := &in.AuthenticationStrategy, &out.AuthenticationStrategy
*out = new(string)
**out = **in
}
@@ -555,11 +680,6 @@ func (in *Configuration) DeepCopyInto(out *Configuration) {
*out = new(string)
**out = **in
}
- if in.ID != nil {
- in, out := &in.ID, &out.ID
- *out = new(string)
- **out = **in
- }
if in.Name != nil {
in, out := &in.Name, &out.Name
*out = new(string)
@@ -581,23 +701,28 @@ func (in *Configuration) DeepCopyInto(out *Configuration) {
(*out)[key] = outVal
}
}
+ in.CustomConfigurationParameters.DeepCopyInto(&out.CustomConfigurationParameters)
}
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Configuration.
-func (in *Configuration) DeepCopy() *Configuration {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationParameters.
+func (in *ConfigurationParameters) DeepCopy() *ConfigurationParameters {
if in == nil {
return nil
}
- out := new(Configuration)
+ out := new(ConfigurationParameters)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ConfigurationID) DeepCopyInto(out *ConfigurationID) {
+func (in *ConfigurationRevision) DeepCopyInto(out *ConfigurationRevision) {
*out = *in
- if in.ID != nil {
- in, out := &in.ID, &out.ID
+ if in.Created != nil {
+ in, out := &in.Created, &out.Created
+ *out = (*in).DeepCopy()
+ }
+ if in.Description != nil {
+ in, out := &in.Description, &out.Description
*out = new(string)
**out = **in
}
@@ -608,19 +733,63 @@ func (in *ConfigurationID) DeepCopyInto(out *ConfigurationID) {
}
}
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationID.
-func (in *ConfigurationID) DeepCopy() *ConfigurationID {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationRevision.
+func (in *ConfigurationRevision) DeepCopy() *ConfigurationRevision {
if in == nil {
return nil
}
- out := new(ConfigurationID)
+ out := new(ConfigurationRevision)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ConfigurationRevision) DeepCopyInto(out *ConfigurationRevision) {
+func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) {
*out = *in
+ in.ResourceSpec.DeepCopyInto(&out.ResourceSpec)
+ in.ForProvider.DeepCopyInto(&out.ForProvider)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationSpec.
+func (in *ConfigurationSpec) DeepCopy() *ConfigurationSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ConfigurationSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ConfigurationStatus) DeepCopyInto(out *ConfigurationStatus) {
+ *out = *in
+ in.ResourceStatus.DeepCopyInto(&out.ResourceStatus)
+ in.AtProvider.DeepCopyInto(&out.AtProvider)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationStatus.
+func (in *ConfigurationStatus) DeepCopy() *ConfigurationStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ConfigurationStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Configuration_SDK) DeepCopyInto(out *Configuration_SDK) {
+ *out = *in
+ if in.ARN != nil {
+ in, out := &in.ARN, &out.ARN
+ *out = new(string)
+ **out = **in
+ }
+ if in.AuthenticationStrategy != nil {
+ in, out := &in.AuthenticationStrategy, &out.AuthenticationStrategy
+ *out = new(string)
+ **out = **in
+ }
if in.Created != nil {
in, out := &in.Created, &out.Created
*out = (*in).DeepCopy()
@@ -630,19 +799,55 @@ func (in *ConfigurationRevision) DeepCopyInto(out *ConfigurationRevision) {
*out = new(string)
**out = **in
}
- if in.Revision != nil {
- in, out := &in.Revision, &out.Revision
- *out = new(int64)
+ if in.EngineType != nil {
+ in, out := &in.EngineType, &out.EngineType
+ *out = new(string)
+ **out = **in
+ }
+ if in.EngineVersion != nil {
+ in, out := &in.EngineVersion, &out.EngineVersion
+ *out = new(string)
+ **out = **in
+ }
+ if in.ID != nil {
+ in, out := &in.ID, &out.ID
+ *out = new(string)
**out = **in
}
+ if in.LatestRevision != nil {
+ in, out := &in.LatestRevision, &out.LatestRevision
+ *out = new(ConfigurationRevision)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Name != nil {
+ in, out := &in.Name, &out.Name
+ *out = new(string)
+ **out = **in
+ }
+ if in.Tags != nil {
+ in, out := &in.Tags, &out.Tags
+ *out = make(map[string]*string, len(*in))
+ for key, val := range *in {
+ var outVal *string
+ if val == nil {
+ (*out)[key] = nil
+ } else {
+ inVal := (*in)[key]
+ in, out := &inVal, &outVal
+ *out = new(string)
+ **out = **in
+ }
+ (*out)[key] = outVal
+ }
+ }
}
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationRevision.
-func (in *ConfigurationRevision) DeepCopy() *ConfigurationRevision {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Configuration_SDK.
+func (in *Configuration_SDK) DeepCopy() *Configuration_SDK {
if in == nil {
return nil
}
- out := new(ConfigurationRevision)
+ out := new(Configuration_SDK)
in.DeepCopyInto(out)
return out
}
@@ -755,6 +960,31 @@ func (in *CustomBrokerParameters) DeepCopy() *CustomBrokerParameters {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CustomConfigurationParameters) DeepCopyInto(out *CustomConfigurationParameters) {
+ *out = *in
+ if in.Data != nil {
+ in, out := &in.Data, &out.Data
+ *out = new(string)
+ **out = **in
+ }
+ if in.Description != nil {
+ in, out := &in.Description, &out.Description
+ *out = new(string)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomConfigurationParameters.
+func (in *CustomConfigurationParameters) DeepCopy() *CustomConfigurationParameters {
+ if in == nil {
+ return nil
+ }
+ out := new(CustomConfigurationParameters)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomUser) DeepCopyInto(out *CustomUser) {
*out = *in
diff --git a/apis/mq/v1alpha1/zz_generated.managed.go b/apis/mq/v1alpha1/zz_generated.managed.go
index 1d51fe4362..7f0c5d5c49 100644
--- a/apis/mq/v1alpha1/zz_generated.managed.go
+++ b/apis/mq/v1alpha1/zz_generated.managed.go
@@ -80,6 +80,66 @@ func (mg *Broker) SetWriteConnectionSecretToReference(r *xpv1.SecretReference) {
mg.Spec.WriteConnectionSecretToReference = r
}
+// GetCondition of this Configuration.
+func (mg *Configuration) GetCondition(ct xpv1.ConditionType) xpv1.Condition {
+ return mg.Status.GetCondition(ct)
+}
+
+// GetDeletionPolicy of this Configuration.
+func (mg *Configuration) GetDeletionPolicy() xpv1.DeletionPolicy {
+ return mg.Spec.DeletionPolicy
+}
+
+// GetManagementPolicies of this Configuration.
+func (mg *Configuration) GetManagementPolicies() xpv1.ManagementPolicies {
+ return mg.Spec.ManagementPolicies
+}
+
+// GetProviderConfigReference of this Configuration.
+func (mg *Configuration) GetProviderConfigReference() *xpv1.Reference {
+ return mg.Spec.ProviderConfigReference
+}
+
+// GetPublishConnectionDetailsTo of this Configuration.
+func (mg *Configuration) GetPublishConnectionDetailsTo() *xpv1.PublishConnectionDetailsTo {
+ return mg.Spec.PublishConnectionDetailsTo
+}
+
+// GetWriteConnectionSecretToReference of this Configuration.
+func (mg *Configuration) GetWriteConnectionSecretToReference() *xpv1.SecretReference {
+ return mg.Spec.WriteConnectionSecretToReference
+}
+
+// SetConditions of this Configuration.
+func (mg *Configuration) SetConditions(c ...xpv1.Condition) {
+ mg.Status.SetConditions(c...)
+}
+
+// SetDeletionPolicy of this Configuration.
+func (mg *Configuration) SetDeletionPolicy(r xpv1.DeletionPolicy) {
+ mg.Spec.DeletionPolicy = r
+}
+
+// SetManagementPolicies of this Configuration.
+func (mg *Configuration) SetManagementPolicies(r xpv1.ManagementPolicies) {
+ mg.Spec.ManagementPolicies = r
+}
+
+// SetProviderConfigReference of this Configuration.
+func (mg *Configuration) SetProviderConfigReference(r *xpv1.Reference) {
+ mg.Spec.ProviderConfigReference = r
+}
+
+// SetPublishConnectionDetailsTo of this Configuration.
+func (mg *Configuration) SetPublishConnectionDetailsTo(r *xpv1.PublishConnectionDetailsTo) {
+ mg.Spec.PublishConnectionDetailsTo = r
+}
+
+// SetWriteConnectionSecretToReference of this Configuration.
+func (mg *Configuration) SetWriteConnectionSecretToReference(r *xpv1.SecretReference) {
+ mg.Spec.WriteConnectionSecretToReference = r
+}
+
// GetCondition of this User.
func (mg *User) GetCondition(ct xpv1.ConditionType) xpv1.Condition {
return mg.Status.GetCondition(ct)
diff --git a/apis/mq/v1alpha1/zz_generated.managedlist.go b/apis/mq/v1alpha1/zz_generated.managedlist.go
index 799595d4ff..fe5c815af3 100644
--- a/apis/mq/v1alpha1/zz_generated.managedlist.go
+++ b/apis/mq/v1alpha1/zz_generated.managedlist.go
@@ -29,6 +29,15 @@ func (l *BrokerList) GetItems() []resource.Managed {
return items
}
+// GetItems of this ConfigurationList.
+func (l *ConfigurationList) GetItems() []resource.Managed {
+ items := make([]resource.Managed, len(l.Items))
+ for i := range l.Items {
+ items[i] = &l.Items[i]
+ }
+ return items
+}
+
// GetItems of this UserList.
func (l *UserList) GetItems() []resource.Managed {
items := make([]resource.Managed, len(l.Items))
diff --git a/apis/mq/v1alpha1/zz_types.go b/apis/mq/v1alpha1/zz_types.go
index 03ae39e91a..3d03cba0b0 100644
--- a/apis/mq/v1alpha1/zz_types.go
+++ b/apis/mq/v1alpha1/zz_types.go
@@ -88,7 +88,23 @@ type BrokerSummary struct {
}
// +kubebuilder:skipversion
-type Configuration struct {
+type ConfigurationID struct {
+ ID *string `json:"id,omitempty"`
+
+ Revision *int64 `json:"revision,omitempty"`
+}
+
+// +kubebuilder:skipversion
+type ConfigurationRevision struct {
+ Created *metav1.Time `json:"created,omitempty"`
+
+ Description *string `json:"description,omitempty"`
+
+ Revision *int64 `json:"revision,omitempty"`
+}
+
+// +kubebuilder:skipversion
+type Configuration_SDK struct {
ARN *string `json:"arn,omitempty"`
// Optional. The authentication strategy used to secure the broker. The default
// is SIMPLE.
@@ -103,28 +119,14 @@ type Configuration struct {
EngineVersion *string `json:"engineVersion,omitempty"`
ID *string `json:"id,omitempty"`
+ // Returns information about the specified configuration revision.
+ LatestRevision *ConfigurationRevision `json:"latestRevision,omitempty"`
Name *string `json:"name,omitempty"`
Tags map[string]*string `json:"tags,omitempty"`
}
-// +kubebuilder:skipversion
-type ConfigurationID struct {
- ID *string `json:"id,omitempty"`
-
- Revision *int64 `json:"revision,omitempty"`
-}
-
-// +kubebuilder:skipversion
-type ConfigurationRevision struct {
- Created *metav1.Time `json:"created,omitempty"`
-
- Description *string `json:"description,omitempty"`
-
- Revision *int64 `json:"revision,omitempty"`
-}
-
// +kubebuilder:skipversion
type Configurations struct {
// A list of information about the configuration.
diff --git a/examples/mq/activemq-config.yaml b/examples/mq/activemq-config.yaml
new file mode 100644
index 0000000000..4625402bac
--- /dev/null
+++ b/examples/mq/activemq-config.yaml
@@ -0,0 +1,25 @@
+apiVersion: mq.aws.crossplane.io/v1alpha1
+kind: Configuration
+metadata:
+ name: example-mq-config
+spec:
+ forProvider:
+ name: example-mq-config
+ description: example description
+ data: |
+
+
+
+
+
+
+
+
+
+ region: eu-central-1
+ engineType: ActiveMQ
+ engineVersion: 5.17.6
+ tags:
+ Test: test
+ providerConfigRef:
+ name: default
\ No newline at end of file
diff --git a/package/crds/mq.aws.crossplane.io_configurations.yaml b/package/crds/mq.aws.crossplane.io_configurations.yaml
new file mode 100644
index 0000000000..a64d85a96b
--- /dev/null
+++ b/package/crds/mq.aws.crossplane.io_configurations.yaml
@@ -0,0 +1,362 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.14.0
+ name: configurations.mq.aws.crossplane.io
+spec:
+ group: mq.aws.crossplane.io
+ names:
+ categories:
+ - crossplane
+ - managed
+ - aws
+ kind: Configuration
+ listKind: ConfigurationList
+ plural: configurations
+ singular: configuration
+ scope: Cluster
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .status.conditions[?(@.type=='Ready')].status
+ name: READY
+ type: string
+ - jsonPath: .status.conditions[?(@.type=='Synced')].status
+ name: SYNCED
+ type: string
+ - jsonPath: .metadata.annotations.crossplane\.io/external-name
+ name: EXTERNAL-NAME
+ type: string
+ - jsonPath: .metadata.creationTimestamp
+ name: AGE
+ type: date
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: Configuration is the Schema for the Configurations API
+ properties:
+ apiVersion:
+ description: |-
+ APIVersion defines the versioned schema of this representation of an object.
+ Servers should convert recognized schemas to the latest internal value, and
+ may reject unrecognized values.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+ type: string
+ kind:
+ description: |-
+ Kind is a string value representing the REST resource this object represents.
+ Servers may infer this from the endpoint the client submits requests to.
+ Cannot be updated.
+ In CamelCase.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: ConfigurationSpec defines the desired state of Configuration
+ properties:
+ deletionPolicy:
+ default: Delete
+ description: |-
+ DeletionPolicy specifies what will happen to the underlying external
+ when this managed resource is deleted - either "Delete" or "Orphan" the
+ external resource.
+ This field is planned to be deprecated in favor of the ManagementPolicies
+ field in a future release. Currently, both could be set independently and
+ non-default values would be honored if the feature flag is enabled.
+ See the design doc for more information: https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223
+ enum:
+ - Orphan
+ - Delete
+ type: string
+ forProvider:
+ description: ConfigurationParameters defines the desired state of
+ Configuration
+ properties:
+ authenticationStrategy:
+ type: string
+ data:
+ type: string
+ description:
+ type: string
+ engineType:
+ type: string
+ engineVersion:
+ type: string
+ name:
+ type: string
+ region:
+ description: Region is which region the Configuration will be
+ created.
+ type: string
+ tags:
+ additionalProperties:
+ type: string
+ type: object
+ required:
+ - engineType
+ - engineVersion
+ - name
+ - region
+ type: object
+ managementPolicies:
+ default:
+ - '*'
+ description: |-
+ THIS IS A BETA FIELD. It is on by default but can be opted out
+ through a Crossplane feature flag.
+ ManagementPolicies specify the array of actions Crossplane is allowed to
+ take on the managed and external resources.
+ This field is planned to replace the DeletionPolicy field in a future
+ release. Currently, both could be set independently and non-default
+ values would be honored if the feature flag is enabled. If both are
+ custom, the DeletionPolicy field will be ignored.
+ See the design doc for more information: https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223
+ and this one: https://github.com/crossplane/crossplane/blob/444267e84783136daa93568b364a5f01228cacbe/design/one-pager-ignore-changes.md
+ items:
+ description: |-
+ A ManagementAction represents an action that the Crossplane controllers
+ can take on an external resource.
+ enum:
+ - Observe
+ - Create
+ - Update
+ - Delete
+ - LateInitialize
+ - '*'
+ type: string
+ type: array
+ providerConfigRef:
+ default:
+ name: default
+ description: |-
+ ProviderConfigReference specifies how the provider that will be used to
+ create, observe, update, and delete this managed resource should be
+ configured.
+ properties:
+ name:
+ description: Name of the referenced object.
+ type: string
+ policy:
+ description: Policies for referencing.
+ properties:
+ resolution:
+ default: Required
+ description: |-
+ Resolution specifies whether resolution of this reference is required.
+ The default is 'Required', which means the reconcile will fail if the
+ reference cannot be resolved. 'Optional' means this reference will be
+ a no-op if it cannot be resolved.
+ enum:
+ - Required
+ - Optional
+ type: string
+ resolve:
+ description: |-
+ Resolve specifies when this reference should be resolved. The default
+ is 'IfNotPresent', which will attempt to resolve the reference only when
+ the corresponding field is not present. Use 'Always' to resolve the
+ reference on every reconcile.
+ enum:
+ - Always
+ - IfNotPresent
+ type: string
+ type: object
+ required:
+ - name
+ type: object
+ publishConnectionDetailsTo:
+ description: |-
+ PublishConnectionDetailsTo specifies the connection secret config which
+ contains a name, metadata and a reference to secret store config to
+ which any connection details for this managed resource should be written.
+ Connection details frequently include the endpoint, username,
+ and password required to connect to the managed resource.
+ properties:
+ configRef:
+ default:
+ name: default
+ description: |-
+ SecretStoreConfigRef specifies which secret store config should be used
+ for this ConnectionSecret.
+ properties:
+ name:
+ description: Name of the referenced object.
+ type: string
+ policy:
+ description: Policies for referencing.
+ properties:
+ resolution:
+ default: Required
+ description: |-
+ Resolution specifies whether resolution of this reference is required.
+ The default is 'Required', which means the reconcile will fail if the
+ reference cannot be resolved. 'Optional' means this reference will be
+ a no-op if it cannot be resolved.
+ enum:
+ - Required
+ - Optional
+ type: string
+ resolve:
+ description: |-
+ Resolve specifies when this reference should be resolved. The default
+ is 'IfNotPresent', which will attempt to resolve the reference only when
+ the corresponding field is not present. Use 'Always' to resolve the
+ reference on every reconcile.
+ enum:
+ - Always
+ - IfNotPresent
+ type: string
+ type: object
+ required:
+ - name
+ type: object
+ metadata:
+ description: Metadata is the metadata for connection secret.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: |-
+ Annotations are the annotations to be added to connection secret.
+ - For Kubernetes secrets, this will be used as "metadata.annotations".
+ - It is up to Secret Store implementation for others store types.
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ description: |-
+ Labels are the labels/tags to be added to connection secret.
+ - For Kubernetes secrets, this will be used as "metadata.labels".
+ - It is up to Secret Store implementation for others store types.
+ type: object
+ type:
+ description: |-
+ Type is the SecretType for the connection secret.
+ - Only valid for Kubernetes Secret Stores.
+ type: string
+ type: object
+ name:
+ description: Name is the name of the connection secret.
+ type: string
+ required:
+ - name
+ type: object
+ writeConnectionSecretToRef:
+ description: |-
+ WriteConnectionSecretToReference specifies the namespace and name of a
+ Secret to which any connection details for this managed resource should
+ be written. Connection details frequently include the endpoint, username,
+ and password required to connect to the managed resource.
+ This field is planned to be replaced in a future release in favor of
+ PublishConnectionDetailsTo. Currently, both could be set independently
+ and connection details would be published to both without affecting
+ each other.
+ properties:
+ name:
+ description: Name of the secret.
+ type: string
+ namespace:
+ description: Namespace of the secret.
+ type: string
+ required:
+ - name
+ - namespace
+ type: object
+ required:
+ - forProvider
+ type: object
+ status:
+ description: ConfigurationStatus defines the observed state of Configuration.
+ properties:
+ atProvider:
+ description: ConfigurationObservation defines the observed state of
+ Configuration
+ properties:
+ arn:
+ type: string
+ created:
+ format: date-time
+ type: string
+ id:
+ type: string
+ latestRevision:
+ properties:
+ created:
+ format: date-time
+ type: string
+ description:
+ type: string
+ revision:
+ format: int64
+ type: integer
+ type: object
+ latestRevisionData:
+ type: string
+ tags:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ conditions:
+ description: Conditions of the resource.
+ items:
+ description: A Condition that may apply to a resource.
+ properties:
+ lastTransitionTime:
+ description: |-
+ LastTransitionTime is the last time this condition transitioned from one
+ status to another.
+ format: date-time
+ type: string
+ message:
+ description: |-
+ A Message containing details about this condition's last transition from
+ one status to another, if any.
+ type: string
+ observedGeneration:
+ description: |-
+ ObservedGeneration represents the .metadata.generation that the condition was set based upon.
+ For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+ with respect to the current state of the instance.
+ format: int64
+ type: integer
+ reason:
+ description: A Reason for this condition's last transition from
+ one status to another.
+ type: string
+ status:
+ description: Status of this condition; is it currently True,
+ False, or Unknown?
+ type: string
+ type:
+ description: |-
+ Type of this condition. At most one of each condition type may apply to
+ a resource at any point in time.
+ type: string
+ required:
+ - lastTransitionTime
+ - reason
+ - status
+ - type
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - type
+ x-kubernetes-list-type: map
+ observedGeneration:
+ description: |-
+ ObservedGeneration is the latest metadata.generation
+ which resulted in either a ready state, or stalled due to error
+ it can not recover from without human intervention.
+ format: int64
+ type: integer
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/pkg/controller/mq/configuration/conversions.go b/pkg/controller/mq/configuration/conversions.go
new file mode 100644
index 0000000000..1d407ba580
--- /dev/null
+++ b/pkg/controller/mq/configuration/conversions.go
@@ -0,0 +1,61 @@
+package configuration
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+
+ svcsdk "github.com/aws/aws-sdk-go/service/mq"
+ cperrors "github.com/crossplane/crossplane-runtime/pkg/errors"
+ "github.com/crossplane/crossplane-runtime/pkg/meta"
+
+ svcapitypes "github.com/crossplane-contrib/provider-aws/apis/mq/v1alpha1"
+ "github.com/crossplane-contrib/provider-aws/pkg/utils/pointer"
+)
+
+func generateDescribeConfigurationRevisionInput(id *string, revision *int64) *svcsdk.DescribeConfigurationRevisionInput {
+ currRevision := strconv.FormatInt(pointer.Int64Value(revision), 10)
+ res := &svcsdk.DescribeConfigurationRevisionInput{
+ ConfigurationId: id,
+ ConfigurationRevision: &currRevision,
+ }
+
+ return res
+}
+
+func generateUpdateConfigurationRequest(cr *svcapitypes.Configuration) *svcsdk.UpdateConfigurationRequest {
+ res := &svcsdk.UpdateConfigurationRequest{
+ ConfigurationId: pointer.ToOrNilIfZeroValue(meta.GetExternalName(cr)),
+ Data: pointer.ToOrNilIfZeroValue(base64.StdEncoding.EncodeToString([]byte(pointer.StringValue(cr.Spec.ForProvider.Data)))),
+ Description: cr.Spec.ForProvider.Description,
+ }
+ return res
+}
+
+const (
+ ErrCannotAddTags = "cannot add tags"
+ ErrCannotRemoveTags = "cannot remove tags"
+ ErrSanitizedConfig = "The desired configuration has been sanitized, please adjust the data field accordingly:\n"
+ ErrUnknownSanitization = "An unknown sanitization reason occurred."
+ ErrDisallowedElement = "The element '%s' was removed because it is disallowed.\n"
+ ErrDisallowedAttribute = "The attribute '%s' of element '%s' was removed because it is disallowed.\n"
+ ErrInvalidAttributeValue = "The attribute '%s' of element '%s' was removed because it had an invalid value.\n"
+)
+
+func handleSanitizationWarnings(warnings []*svcsdk.SanitizationWarning) error {
+ message := ErrSanitizedConfig
+ for _, w := range warnings {
+ reason := pointer.StringValue(w.Reason)
+ switch svcapitypes.SanitizationWarningReason(reason) {
+ case svcapitypes.SanitizationWarningReason_DISALLOWED_ELEMENT_REMOVED:
+ message += fmt.Sprintf(ErrDisallowedElement, pointer.StringValue(w.ElementName))
+ case svcapitypes.SanitizationWarningReason_DISALLOWED_ATTRIBUTE_REMOVED:
+ message += fmt.Sprintf(ErrDisallowedAttribute, pointer.StringValue(w.AttributeName), pointer.StringValue(w.ElementName))
+ case svcapitypes.SanitizationWarningReason_INVALID_ATTRIBUTE_VALUE_REMOVED:
+ message += fmt.Sprintf(ErrInvalidAttributeValue, pointer.StringValue(w.AttributeName), pointer.StringValue(w.ElementName))
+ default:
+ message += ErrUnknownSanitization
+ }
+ }
+ return cperrors.New(message)
+}
diff --git a/pkg/controller/mq/configuration/setup.go b/pkg/controller/mq/configuration/setup.go
new file mode 100644
index 0000000000..5d4ab5bfb2
--- /dev/null
+++ b/pkg/controller/mq/configuration/setup.go
@@ -0,0 +1,247 @@
+package configuration
+
+import (
+ "context"
+ "encoding/base64"
+
+ svcsdk "github.com/aws/aws-sdk-go/service/mq"
+ svcsdkapi "github.com/aws/aws-sdk-go/service/mq/mqiface"
+ xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
+ "github.com/crossplane/crossplane-runtime/pkg/connection"
+ "github.com/crossplane/crossplane-runtime/pkg/controller"
+ "github.com/crossplane/crossplane-runtime/pkg/event"
+ "github.com/crossplane/crossplane-runtime/pkg/meta"
+ "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
+ "github.com/crossplane/crossplane-runtime/pkg/resource"
+ cpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
+ "github.com/pkg/errors"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ svcapitypes "github.com/crossplane-contrib/provider-aws/apis/mq/v1alpha1"
+ "github.com/crossplane-contrib/provider-aws/apis/v1alpha1"
+ mqconfutils "github.com/crossplane-contrib/provider-aws/pkg/controller/mq/configuration/utils"
+ "github.com/crossplane-contrib/provider-aws/pkg/features"
+ errorutils "github.com/crossplane-contrib/provider-aws/pkg/utils/errors"
+ "github.com/crossplane-contrib/provider-aws/pkg/utils/pointer"
+ custommanaged "github.com/crossplane-contrib/provider-aws/pkg/utils/reconciler/managed"
+ "github.com/crossplane-contrib/provider-aws/pkg/utils/tags"
+)
+
+func SetupConfiguration(mgr ctrl.Manager, o controller.Options) error {
+ name := managed.ControllerName(svcapitypes.ConfigurationGroupKind)
+ opts := []option{
+ func(e *external) {
+ c := &custom{client: e.client, kube: e.kube, external: e}
+ e.isUpToDate = c.isUpToDate
+ e.postCreate = c.postCreate
+ e.preObserve = preObserve
+ e.postObserve = c.postObserve
+ e.update = c.update
+ },
+ }
+
+ cps := []managed.ConnectionPublisher{managed.NewAPISecretPublisher(mgr.GetClient(), mgr.GetScheme())}
+ if o.Features.Enabled(features.EnableAlphaExternalSecretStores) {
+ cps = append(cps, connection.NewDetailsManager(mgr.GetClient(), v1alpha1.StoreConfigGroupVersionKind))
+ }
+ reconcilerOpts := []managed.ReconcilerOption{
+ managed.WithInitializers(),
+ managed.WithCriticalAnnotationUpdater(custommanaged.NewRetryingCriticalAnnotationUpdater(mgr.GetClient())),
+ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), opts: opts}),
+ managed.WithPollInterval(o.PollInterval),
+ managed.WithLogger(o.Logger.WithValues("controller", name)),
+ managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))),
+ managed.WithConnectionPublishers(cps...),
+ }
+
+ if o.Features.Enabled(features.EnableAlphaManagementPolicies) {
+ reconcilerOpts = append(reconcilerOpts, managed.WithManagementPolicies())
+ }
+
+ r := managed.NewReconciler(mgr,
+ resource.ManagedKind(svcapitypes.ConfigurationGroupVersionKind),
+ reconcilerOpts...)
+
+ return ctrl.NewControllerManagedBy(mgr).
+ Named(name).
+ WithOptions(o.ForControllerRuntime()).
+ WithEventFilter(resource.DesiredStateChanged()).
+ For(&svcapitypes.Configuration{}).
+ Complete(r)
+}
+
+type custom struct {
+ kube client.Client
+ client svcsdkapi.MQAPI
+ external *external
+}
+
+func preObserve(_ context.Context, cr *svcapitypes.Configuration, obj *svcsdk.DescribeConfigurationInput) error {
+ obj.ConfigurationId = pointer.ToOrNilIfZeroValue(meta.GetExternalName(cr))
+ return nil
+}
+
+func (e *custom) postObserve(ctx context.Context, cr *svcapitypes.Configuration, obj *svcsdk.DescribeConfigurationOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) {
+ if err != nil {
+ return managed.ExternalObservation{}, err
+ }
+ switch {
+ case meta.WasDeleted(cr):
+ obs.ResourceExists = false
+ case mqconfutils.HasBeenSanitized(cr):
+ cr.SetConditions(xpv1.Unavailable())
+ default:
+ cr.SetConditions(xpv1.Available())
+ }
+
+ return obs, nil
+}
+
+func (e *custom) postCreate(ctx context.Context, cr *svcapitypes.Configuration, obj *svcsdk.CreateConfigurationResponse, cre managed.ExternalCreation, err error) (managed.ExternalCreation, error) {
+ if err != nil {
+ return managed.ExternalCreation{}, err
+ }
+ meta.SetExternalName(cr, pointer.StringValue(obj.Id))
+ return cre, nil
+}
+
+func (e *custom) isUpToDate(ctx context.Context, cr *svcapitypes.Configuration, describeConfigOutput *svcsdk.DescribeConfigurationOutput) (bool, string, error) {
+ atProviderConfig, err := setData(ctx, e, cr, describeConfigOutput.Id, describeConfigOutput.LatestRevision.Revision)
+ if err != nil {
+ return false, "", err
+ }
+ setTags(cr, describeConfigOutput)
+ lateInitialize(describeConfigOutput, &cr.Spec.ForProvider, atProviderConfig)
+ // stops the update loop for the data field if the MQ Configuration sanitizes a revision
+ // any additional pending updates are postponed until the sanitization warnings
+ // in the error message are applied
+ if mqconfutils.HasBeenSanitized(cr) {
+ hasBeenUpdated := mqconfutils.HasBeenUpdatedPostSanitization(cr)
+ return !hasBeenUpdated, "", nil
+ }
+ isRevisionUpToDate, err := isRevisionUpToDate(cr)
+ if err != nil {
+ return false, "", err
+ }
+
+ add, remove := tags.DiffTagsMapPtr(cr.Spec.ForProvider.Tags, describeConfigOutput.Tags)
+ areTagsUpToDate := len(add) == 0 && len(remove) == 0
+
+ return isRevisionUpToDate && areTagsUpToDate, "", nil
+}
+
+func (e *custom) update(ctx context.Context, mg cpresource.Managed) (managed.ExternalUpdate, error) {
+ cr, ok := mg.(*svcapitypes.Configuration)
+ if !ok {
+ return managed.ExternalUpdate{}, errors.New(errUnexpectedObject)
+ }
+
+ if cr.Status.AtProvider.ARN == nil {
+ return managed.ExternalUpdate{}, nil
+ }
+ added, removed := tags.DiffTagsMapPtr(cr.Spec.ForProvider.Tags, cr.Status.AtProvider.Tags)
+ if len(added) > 0 {
+ _, err := e.client.CreateTagsWithContext(ctx, &svcsdk.CreateTagsInput{
+ ResourceArn: cr.Status.AtProvider.ARN,
+ Tags: added,
+ })
+ if err != nil {
+ return managed.ExternalUpdate{}, errorutils.Wrap(err, ErrCannotAddTags)
+ }
+ }
+ if len(removed) > 0 {
+ _, err := e.client.DeleteTagsWithContext(ctx, &svcsdk.DeleteTagsInput{
+ ResourceArn: cr.Status.AtProvider.ARN,
+ TagKeys: removed,
+ })
+ if err != nil {
+ return managed.ExternalUpdate{}, errorutils.Wrap(err, ErrCannotRemoveTags)
+ }
+
+ }
+ // update configuration only if its latest revision is not up to date
+ // a revision is up to date if both description and data are the same
+ // sanitization without warnings of the data field may potentially result in a new revision
+ // which can be halted in isUpToDate for the following observe
+ isRevisionUpToDate, err := isRevisionUpToDate(cr)
+ if err != nil {
+ return managed.ExternalUpdate{}, errorutils.Wrap(err, "cannot check if revision is up to date")
+ }
+ if isRevisionUpToDate {
+ return managed.ExternalUpdate{}, nil
+ }
+ input := generateUpdateConfigurationRequest(cr)
+ resp, err := e.client.UpdateConfigurationWithContext(ctx, input)
+ return e.postUpdate(ctx, cr, resp, managed.ExternalUpdate{}, errorutils.Wrap(err, errUpdate))
+}
+
+func (e *custom) postUpdate(ctx context.Context, cr *svcapitypes.Configuration, obj *svcsdk.UpdateConfigurationResponse, cre managed.ExternalUpdate, err error) (managed.ExternalUpdate, error) {
+ if err != nil {
+ return cre, err
+ }
+
+ if len(obj.Warnings) == 0 && !mqconfutils.HasBeenSanitized(cr) {
+ return cre, nil
+ }
+
+ currentObj := cr.DeepCopy()
+ if len(obj.Warnings) == 0 {
+ meta.RemoveAnnotations(cr, svcapitypes.LatestUnsanitizedConfiguration)
+ } else {
+ err = handleSanitizationWarnings(obj.Warnings)
+ mqconfutils.SetLatestUnsanitizedConfiguration(cr)
+ }
+ patch := client.MergeFrom(currentObj)
+ if err := e.kube.Patch(ctx, cr, patch); err != nil {
+ return cre, err
+ }
+ return cre, err
+}
+
+func setData(ctx context.Context, e *custom, cr *svcapitypes.Configuration, id *string, revision *int64) (string, error) {
+ describeConfigRevisionOutput, err := getLatestRevisionData(ctx, e, id, revision)
+ if err != nil {
+ return "", err
+ }
+ atProviderDataLatestRevision, err := base64.StdEncoding.DecodeString(pointer.StringValue(describeConfigRevisionOutput.Data))
+ if err != nil {
+ return "", err
+ }
+ atProviderConfig := string(atProviderDataLatestRevision)
+ cr.Status.AtProvider.LatestRevisionData = &atProviderConfig
+ return atProviderConfig, nil
+}
+
+func setTags(cr *svcapitypes.Configuration, describeConfigOutput *svcsdk.DescribeConfigurationOutput) {
+ cr.Status.AtProvider.Tags = describeConfigOutput.Tags
+}
+
+func getLatestRevisionData(ctx context.Context, e *custom, id *string, revision *int64) (*svcsdk.DescribeConfigurationRevisionResponse, error) {
+ describeRevisionInput := generateDescribeConfigurationRevisionInput(id, revision)
+ describeConfigRevisionOutput, err := e.client.DescribeConfigurationRevisionWithContext(ctx, describeRevisionInput)
+ if err != nil {
+ return nil, err
+ }
+ return describeConfigRevisionOutput, nil
+}
+
+func lateInitialize(describeConfigOutput *svcsdk.DescribeConfigurationOutput, in *svcapitypes.ConfigurationParameters, out string) {
+ if pointer.StringValue(in.Data) == "" {
+ in.Data = pointer.ToOrNilIfZeroValue(out)
+ }
+ in.Description = pointer.LateInitialize(in.Description, describeConfigOutput.LatestRevision.Description)
+}
+
+func isRevisionUpToDate(cr *svcapitypes.Configuration) (bool, error) {
+ forProviderConfig := pointer.StringValue(cr.Spec.ForProvider.Data)
+ atProviderConfig := pointer.StringValue(cr.Status.AtProvider.LatestRevisionData)
+ diffDataAtAndForProviderConfig, err := mqconfutils.DiffXMLConfigs(atProviderConfig, forProviderConfig)
+ if err != nil {
+ return false, err
+ }
+
+ isDataUpToDate := diffDataAtAndForProviderConfig == ""
+ isDescriptionUpToDate := pointer.StringValue(cr.Spec.ForProvider.Description) == pointer.StringValue(cr.Status.AtProvider.LatestRevision.Description)
+ return isDataUpToDate && isDescriptionUpToDate, nil
+}
diff --git a/pkg/controller/mq/configuration/utils/annotations.go b/pkg/controller/mq/configuration/utils/annotations.go
new file mode 100644
index 0000000000..c396b72996
--- /dev/null
+++ b/pkg/controller/mq/configuration/utils/annotations.go
@@ -0,0 +1,34 @@
+package utils
+
+import (
+ "crypto/sha256"
+ "encoding/hex"
+
+ "github.com/crossplane/crossplane-runtime/pkg/meta"
+
+ svcapitypes "github.com/crossplane-contrib/provider-aws/apis/mq/v1alpha1"
+ "github.com/crossplane-contrib/provider-aws/pkg/utils/pointer"
+)
+
+func SetLatestUnsanitizedConfiguration(cr *svcapitypes.Configuration) {
+ latestDesiredConfig := pointer.StringValue(cr.Spec.ForProvider.Data)
+ meta.AddAnnotations(cr, map[string]string{svcapitypes.LatestUnsanitizedConfiguration: hashText(latestDesiredConfig)})
+}
+
+func GetLatestUnsanitizedConfiguration(o *svcapitypes.Configuration) string {
+ return o.GetAnnotations()[svcapitypes.LatestUnsanitizedConfiguration]
+}
+
+func hashText(s string) string {
+ hash := sha256.Sum256([]byte(s))
+ return hex.EncodeToString(hash[:])
+}
+
+func HasBeenSanitized(o *svcapitypes.Configuration) bool {
+ return GetLatestUnsanitizedConfiguration(o) != ""
+}
+
+func HasBeenUpdatedPostSanitization(o *svcapitypes.Configuration) bool {
+ latestDesiredConfig := pointer.StringValue(o.Spec.ForProvider.Data)
+ return GetLatestUnsanitizedConfiguration(o) != hashText(latestDesiredConfig)
+}
diff --git a/pkg/controller/mq/configuration/utils/xmlparse.go b/pkg/controller/mq/configuration/utils/xmlparse.go
new file mode 100644
index 0000000000..43be95ed75
--- /dev/null
+++ b/pkg/controller/mq/configuration/utils/xmlparse.go
@@ -0,0 +1,84 @@
+package utils
+
+import (
+ "bytes"
+ "encoding/xml"
+ "sort"
+
+ "github.com/google/go-cmp/cmp"
+)
+
+//nolint:musttag
+type Node struct {
+ XMLName xml.Name
+ Attr []xml.Attr `xml:",any,attr"`
+ Content []byte `xml:",innerxml"`
+ Nodes []Node `xml:",any"`
+}
+
+func (n *Node) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
+ //nolint:musttag
+ type node Node
+ return d.DecodeElement((*node)(n), &start)
+}
+
+func DiffXMLConfigs(c1, c2 string) (string, error) {
+ var configNode1 Node
+ if err := decodeString(c1, &configNode1); err != nil {
+ return "", err
+ }
+ var configNode2 Node
+ if err := decodeString(c2, &configNode2); err != nil {
+ return "", err
+ }
+ return diffNodes(configNode1, configNode2), nil
+}
+
+func decodeString(xmlString string, node *Node) error {
+ buf := bytes.NewBuffer([]byte(xmlString))
+ dec := xml.NewDecoder(buf)
+ return dec.Decode(node)
+}
+
+func diffNodes(forProvider, atProvider Node) string {
+ diff := cmp.Diff(forProvider, atProvider, nodeComparerOpt())
+ return diff
+}
+
+// recursively check equality of nodes
+// based on attributes, subnodes and tag name equality
+func nodeComparerOpt() cmp.Option {
+ return cmp.Comparer(func(x, y Node) bool {
+ if x.XMLName.Local != y.XMLName.Local {
+ return false
+ }
+ if len(x.Nodes) != len(y.Nodes) {
+ return false
+ }
+
+ sort.Slice(x.Attr, func(i, j int) bool {
+ return x.Attr[i].Name.Local < x.Attr[j].Name.Local
+ })
+ sort.Slice(y.Attr, func(i, j int) bool {
+ return y.Attr[i].Name.Local < y.Attr[j].Name.Local
+ })
+
+ if !cmp.Equal(x.Attr, y.Attr) {
+ return false
+ }
+
+ sort.Slice(x.Nodes, func(i, j int) bool {
+ return x.Nodes[i].XMLName.Local < x.Nodes[j].XMLName.Local
+ })
+ sort.Slice(y.Nodes, func(i, j int) bool {
+ return y.Nodes[i].XMLName.Local < y.Nodes[j].XMLName.Local
+ })
+
+ for i := range x.Nodes {
+ if !cmp.Equal(x.Nodes[i], y.Nodes[i], nodeComparerOpt()) {
+ return false
+ }
+ }
+ return true
+ })
+}
diff --git a/pkg/controller/mq/configuration/utils/xmlparse_test.go b/pkg/controller/mq/configuration/utils/xmlparse_test.go
new file mode 100644
index 0000000000..fa539fc67b
--- /dev/null
+++ b/pkg/controller/mq/configuration/utils/xmlparse_test.go
@@ -0,0 +1,118 @@
+package utils
+
+import (
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+)
+
+func TestDiffMQConfiguration(t *testing.T) {
+ type args struct {
+ in string
+ out string
+ }
+
+ type want struct {
+ diff string
+ }
+
+ cases := map[string]struct {
+ args
+ want
+ }{
+ "IdenticalConfigs with unsorted attributes": {
+ args: args{
+ in: `
+
+
+
+
+
+
+ `,
+ out: `
+
+
+
+
+
+
+ `,
+ },
+ want: want{
+ diff: "",
+ },
+ },
+ "IdenticalConfigs, ignore comments": {
+ args: args{
+ in: `
+
+
+
+
+
+
+
+ `,
+ out: `
+
+
+
+
+
+
+ `,
+ },
+ want: want{
+ diff: "",
+ },
+ },
+ "Same config with diff tag order and wrong attribute order": {
+ args: args{
+ in: `
+
+
+
+
+
+
+ `,
+ out: `
+
+
+
+
+
+
+ `,
+ },
+ want: want{
+ diff: "",
+ },
+ },
+ }
+
+ for name, tc := range cases {
+ t.Run(name, func(t *testing.T) {
+ diff, err := DiffXMLConfigs(tc.args.in, tc.args.out)
+ if diff := cmp.Diff(tc.want.diff, diff); diff != "" || err != nil {
+ t.Errorf("DiffXMLConfigs() mismatch (-want +got):\n%s", diff)
+ }
+ })
+ }
+}
diff --git a/pkg/controller/mq/configuration/zz_controller.go b/pkg/controller/mq/configuration/zz_controller.go
new file mode 100644
index 0000000000..2fd701c6db
--- /dev/null
+++ b/pkg/controller/mq/configuration/zz_controller.go
@@ -0,0 +1,241 @@
+/*
+Copyright 2021 The Crossplane Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by ack-generate. DO NOT EDIT.
+
+package configuration
+
+import (
+ "context"
+
+ svcapi "github.com/aws/aws-sdk-go/service/mq"
+ svcsdk "github.com/aws/aws-sdk-go/service/mq"
+ svcsdkapi "github.com/aws/aws-sdk-go/service/mq/mqiface"
+ "github.com/google/go-cmp/cmp"
+ "github.com/pkg/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
+ "github.com/crossplane/crossplane-runtime/pkg/meta"
+ "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
+ cpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
+
+ svcapitypes "github.com/crossplane-contrib/provider-aws/apis/mq/v1alpha1"
+ connectaws "github.com/crossplane-contrib/provider-aws/pkg/utils/connect/aws"
+ errorutils "github.com/crossplane-contrib/provider-aws/pkg/utils/errors"
+)
+
+const (
+ errUnexpectedObject = "managed resource is not an Configuration resource"
+
+ errCreateSession = "cannot create a new session"
+ errCreate = "cannot create Configuration in AWS"
+ errUpdate = "cannot update Configuration in AWS"
+ errDescribe = "failed to describe Configuration"
+ errDelete = "failed to delete Configuration"
+)
+
+type connector struct {
+ kube client.Client
+ opts []option
+}
+
+func (c *connector) Connect(ctx context.Context, mg cpresource.Managed) (managed.ExternalClient, error) {
+ cr, ok := mg.(*svcapitypes.Configuration)
+ if !ok {
+ return nil, errors.New(errUnexpectedObject)
+ }
+ sess, err := connectaws.GetConfigV1(ctx, c.kube, mg, cr.Spec.ForProvider.Region)
+ if err != nil {
+ return nil, errors.Wrap(err, errCreateSession)
+ }
+ return newExternal(c.kube, svcapi.New(sess), c.opts), nil
+}
+
+func (e *external) Observe(ctx context.Context, mg cpresource.Managed) (managed.ExternalObservation, error) {
+ cr, ok := mg.(*svcapitypes.Configuration)
+ if !ok {
+ return managed.ExternalObservation{}, errors.New(errUnexpectedObject)
+ }
+ if meta.GetExternalName(cr) == "" {
+ return managed.ExternalObservation{
+ ResourceExists: false,
+ }, nil
+ }
+ input := GenerateDescribeConfigurationInput(cr)
+ if err := e.preObserve(ctx, cr, input); err != nil {
+ return managed.ExternalObservation{}, errors.Wrap(err, "pre-observe failed")
+ }
+ resp, err := e.client.DescribeConfigurationWithContext(ctx, input)
+ if err != nil {
+ return managed.ExternalObservation{ResourceExists: false}, errorutils.Wrap(cpresource.Ignore(IsNotFound, err), errDescribe)
+ }
+ currentSpec := cr.Spec.ForProvider.DeepCopy()
+ if err := e.lateInitialize(&cr.Spec.ForProvider, resp); err != nil {
+ return managed.ExternalObservation{}, errors.Wrap(err, "late-init failed")
+ }
+ GenerateConfiguration(resp).Status.AtProvider.DeepCopyInto(&cr.Status.AtProvider)
+ upToDate := true
+ diff := ""
+ if !meta.WasDeleted(cr) { // There is no need to run isUpToDate if the resource is deleted
+ upToDate, diff, err = e.isUpToDate(ctx, cr, resp)
+ if err != nil {
+ return managed.ExternalObservation{}, errors.Wrap(err, "isUpToDate check failed")
+ }
+ }
+ return e.postObserve(ctx, cr, resp, managed.ExternalObservation{
+ ResourceExists: true,
+ ResourceUpToDate: upToDate,
+ Diff: diff,
+ ResourceLateInitialized: !cmp.Equal(&cr.Spec.ForProvider, currentSpec),
+ }, nil)
+}
+
+func (e *external) Create(ctx context.Context, mg cpresource.Managed) (managed.ExternalCreation, error) {
+ cr, ok := mg.(*svcapitypes.Configuration)
+ if !ok {
+ return managed.ExternalCreation{}, errors.New(errUnexpectedObject)
+ }
+ cr.Status.SetConditions(xpv1.Creating())
+ input := GenerateCreateConfigurationRequest(cr)
+ if err := e.preCreate(ctx, cr, input); err != nil {
+ return managed.ExternalCreation{}, errors.Wrap(err, "pre-create failed")
+ }
+ resp, err := e.client.CreateConfigurationWithContext(ctx, input)
+ if err != nil {
+ return managed.ExternalCreation{}, errorutils.Wrap(err, errCreate)
+ }
+
+ if resp.Arn != nil {
+ cr.Status.AtProvider.ARN = resp.Arn
+ } else {
+ cr.Status.AtProvider.ARN = nil
+ }
+ if resp.AuthenticationStrategy != nil {
+ cr.Spec.ForProvider.AuthenticationStrategy = resp.AuthenticationStrategy
+ } else {
+ cr.Spec.ForProvider.AuthenticationStrategy = nil
+ }
+ if resp.Created != nil {
+ cr.Status.AtProvider.Created = &metav1.Time{*resp.Created}
+ } else {
+ cr.Status.AtProvider.Created = nil
+ }
+ if resp.Id != nil {
+ cr.Status.AtProvider.ID = resp.Id
+ } else {
+ cr.Status.AtProvider.ID = nil
+ }
+ if resp.LatestRevision != nil {
+ f4 := &svcapitypes.ConfigurationRevision{}
+ if resp.LatestRevision.Created != nil {
+ f4.Created = &metav1.Time{*resp.LatestRevision.Created}
+ }
+ if resp.LatestRevision.Description != nil {
+ f4.Description = resp.LatestRevision.Description
+ }
+ if resp.LatestRevision.Revision != nil {
+ f4.Revision = resp.LatestRevision.Revision
+ }
+ cr.Status.AtProvider.LatestRevision = f4
+ } else {
+ cr.Status.AtProvider.LatestRevision = nil
+ }
+ if resp.Name != nil {
+ cr.Spec.ForProvider.Name = resp.Name
+ } else {
+ cr.Spec.ForProvider.Name = nil
+ }
+
+ return e.postCreate(ctx, cr, resp, managed.ExternalCreation{}, err)
+}
+
+func (e *external) Update(ctx context.Context, mg cpresource.Managed) (managed.ExternalUpdate, error) {
+ return e.update(ctx, mg)
+
+}
+
+func (e *external) Delete(ctx context.Context, mg cpresource.Managed) error {
+ cr, ok := mg.(*svcapitypes.Configuration)
+ if !ok {
+ return errors.New(errUnexpectedObject)
+ }
+ cr.Status.SetConditions(xpv1.Deleting())
+ return e.delete(ctx, mg)
+
+}
+
+type option func(*external)
+
+func newExternal(kube client.Client, client svcsdkapi.MQAPI, opts []option) *external {
+ e := &external{
+ kube: kube,
+ client: client,
+ preObserve: nopPreObserve,
+ postObserve: nopPostObserve,
+ lateInitialize: nopLateInitialize,
+ isUpToDate: alwaysUpToDate,
+ preCreate: nopPreCreate,
+ postCreate: nopPostCreate,
+ delete: nopDelete,
+ update: nopUpdate,
+ }
+ for _, f := range opts {
+ f(e)
+ }
+ return e
+}
+
+type external struct {
+ kube client.Client
+ client svcsdkapi.MQAPI
+ preObserve func(context.Context, *svcapitypes.Configuration, *svcsdk.DescribeConfigurationInput) error
+ postObserve func(context.Context, *svcapitypes.Configuration, *svcsdk.DescribeConfigurationOutput, managed.ExternalObservation, error) (managed.ExternalObservation, error)
+ lateInitialize func(*svcapitypes.ConfigurationParameters, *svcsdk.DescribeConfigurationOutput) error
+ isUpToDate func(context.Context, *svcapitypes.Configuration, *svcsdk.DescribeConfigurationOutput) (bool, string, error)
+ preCreate func(context.Context, *svcapitypes.Configuration, *svcsdk.CreateConfigurationRequest) error
+ postCreate func(context.Context, *svcapitypes.Configuration, *svcsdk.CreateConfigurationResponse, managed.ExternalCreation, error) (managed.ExternalCreation, error)
+ delete func(context.Context, cpresource.Managed) error
+ update func(context.Context, cpresource.Managed) (managed.ExternalUpdate, error)
+}
+
+func nopPreObserve(context.Context, *svcapitypes.Configuration, *svcsdk.DescribeConfigurationInput) error {
+ return nil
+}
+
+func nopPostObserve(_ context.Context, _ *svcapitypes.Configuration, _ *svcsdk.DescribeConfigurationOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) {
+ return obs, err
+}
+func nopLateInitialize(*svcapitypes.ConfigurationParameters, *svcsdk.DescribeConfigurationOutput) error {
+ return nil
+}
+func alwaysUpToDate(context.Context, *svcapitypes.Configuration, *svcsdk.DescribeConfigurationOutput) (bool, string, error) {
+ return true, "", nil
+}
+
+func nopPreCreate(context.Context, *svcapitypes.Configuration, *svcsdk.CreateConfigurationRequest) error {
+ return nil
+}
+func nopPostCreate(_ context.Context, _ *svcapitypes.Configuration, _ *svcsdk.CreateConfigurationResponse, cre managed.ExternalCreation, err error) (managed.ExternalCreation, error) {
+ return cre, err
+}
+func nopDelete(context.Context, cpresource.Managed) error {
+ return nil
+}
+func nopUpdate(context.Context, cpresource.Managed) (managed.ExternalUpdate, error) {
+ return managed.ExternalUpdate{}, nil
+}
diff --git a/pkg/controller/mq/configuration/zz_conversions.go b/pkg/controller/mq/configuration/zz_conversions.go
new file mode 100644
index 0000000000..c3ea6b9251
--- /dev/null
+++ b/pkg/controller/mq/configuration/zz_conversions.go
@@ -0,0 +1,142 @@
+/*
+Copyright 2021 The Crossplane Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by ack-generate. DO NOT EDIT.
+
+package configuration
+
+import (
+ "github.com/aws/aws-sdk-go/aws/awserr"
+ svcsdk "github.com/aws/aws-sdk-go/service/mq"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ svcapitypes "github.com/crossplane-contrib/provider-aws/apis/mq/v1alpha1"
+)
+
+// NOTE(muvaf): We return pointers in case the function needs to start with an
+// empty object, hence need to return a new pointer.
+
+// GenerateDescribeConfigurationInput returns input for read
+// operation.
+func GenerateDescribeConfigurationInput(cr *svcapitypes.Configuration) *svcsdk.DescribeConfigurationInput {
+ res := &svcsdk.DescribeConfigurationInput{}
+
+ return res
+}
+
+// GenerateConfiguration returns the current state in the form of *svcapitypes.Configuration.
+func GenerateConfiguration(resp *svcsdk.DescribeConfigurationOutput) *svcapitypes.Configuration {
+ cr := &svcapitypes.Configuration{}
+
+ if resp.Arn != nil {
+ cr.Status.AtProvider.ARN = resp.Arn
+ } else {
+ cr.Status.AtProvider.ARN = nil
+ }
+ if resp.AuthenticationStrategy != nil {
+ cr.Spec.ForProvider.AuthenticationStrategy = resp.AuthenticationStrategy
+ } else {
+ cr.Spec.ForProvider.AuthenticationStrategy = nil
+ }
+ if resp.Created != nil {
+ cr.Status.AtProvider.Created = &metav1.Time{*resp.Created}
+ } else {
+ cr.Status.AtProvider.Created = nil
+ }
+ if resp.EngineType != nil {
+ cr.Spec.ForProvider.EngineType = resp.EngineType
+ } else {
+ cr.Spec.ForProvider.EngineType = nil
+ }
+ if resp.EngineVersion != nil {
+ cr.Spec.ForProvider.EngineVersion = resp.EngineVersion
+ } else {
+ cr.Spec.ForProvider.EngineVersion = nil
+ }
+ if resp.Id != nil {
+ cr.Status.AtProvider.ID = resp.Id
+ } else {
+ cr.Status.AtProvider.ID = nil
+ }
+ if resp.LatestRevision != nil {
+ f7 := &svcapitypes.ConfigurationRevision{}
+ if resp.LatestRevision.Created != nil {
+ f7.Created = &metav1.Time{*resp.LatestRevision.Created}
+ }
+ if resp.LatestRevision.Description != nil {
+ f7.Description = resp.LatestRevision.Description
+ }
+ if resp.LatestRevision.Revision != nil {
+ f7.Revision = resp.LatestRevision.Revision
+ }
+ cr.Status.AtProvider.LatestRevision = f7
+ } else {
+ cr.Status.AtProvider.LatestRevision = nil
+ }
+ if resp.Name != nil {
+ cr.Spec.ForProvider.Name = resp.Name
+ } else {
+ cr.Spec.ForProvider.Name = nil
+ }
+ if resp.Tags != nil {
+ f9 := map[string]*string{}
+ for f9key, f9valiter := range resp.Tags {
+ var f9val string
+ f9val = *f9valiter
+ f9[f9key] = &f9val
+ }
+ cr.Spec.ForProvider.Tags = f9
+ } else {
+ cr.Spec.ForProvider.Tags = nil
+ }
+
+ return cr
+}
+
+// GenerateCreateConfigurationRequest returns a create input.
+func GenerateCreateConfigurationRequest(cr *svcapitypes.Configuration) *svcsdk.CreateConfigurationRequest {
+ res := &svcsdk.CreateConfigurationRequest{}
+
+ if cr.Spec.ForProvider.AuthenticationStrategy != nil {
+ res.SetAuthenticationStrategy(*cr.Spec.ForProvider.AuthenticationStrategy)
+ }
+ if cr.Spec.ForProvider.EngineType != nil {
+ res.SetEngineType(*cr.Spec.ForProvider.EngineType)
+ }
+ if cr.Spec.ForProvider.EngineVersion != nil {
+ res.SetEngineVersion(*cr.Spec.ForProvider.EngineVersion)
+ }
+ if cr.Spec.ForProvider.Name != nil {
+ res.SetName(*cr.Spec.ForProvider.Name)
+ }
+ if cr.Spec.ForProvider.Tags != nil {
+ f4 := map[string]*string{}
+ for f4key, f4valiter := range cr.Spec.ForProvider.Tags {
+ var f4val string
+ f4val = *f4valiter
+ f4[f4key] = &f4val
+ }
+ res.SetTags(f4)
+ }
+
+ return res
+}
+
+// IsNotFound returns whether the given error is of type NotFound or not.
+func IsNotFound(err error) bool {
+ awsErr, ok := err.(awserr.Error)
+ return ok && awsErr.Code() == "NotFoundException"
+}
diff --git a/pkg/controller/mwaa/setup.go b/pkg/controller/mwaa/setup.go
index 6f906e5026..bb394024e8 100644
--- a/pkg/controller/mwaa/setup.go
+++ b/pkg/controller/mwaa/setup.go
@@ -21,6 +21,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"github.com/crossplane-contrib/provider-aws/pkg/controller/mq/broker"
+ "github.com/crossplane-contrib/provider-aws/pkg/controller/mq/configuration"
"github.com/crossplane-contrib/provider-aws/pkg/controller/mq/user"
"github.com/crossplane-contrib/provider-aws/pkg/utils/setup"
)
@@ -31,5 +32,6 @@ func Setup(mgr ctrl.Manager, o controller.Options) error {
mgr, o,
broker.SetupBroker,
user.SetupUser,
+ configuration.SetupConfiguration,
)
}