diff --git a/.golangci.yml b/.golangci.yml index 008747e51a..06065ebf26 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,7 @@ run: timeout: 30m - skip-files: + exclude-files: - "zz_generated\\..+\\.go$" output: @@ -21,11 +21,14 @@ linters-settings: # [deprecated] comma-separated list of pairs of the form pkg:regex # the regex is used to ignore names within pkg. (default "fmt:.*"). # see https://github.com/kisielk/errcheck#the-deprecated-method for details - ignore: fmt:.*,io/ioutil:^Read.* + #ignore: fmt:.*,io/ioutil:^Read.* + exclude-functions: + - fmt.* + - io/ioutil:^Read.* govet: # report about shadowed variables - check-shadowing: false + shadow: false gofmt: # simplify code: gofmt with `-s` option, true by default @@ -112,7 +115,6 @@ linters-settings: linters: enable: - - megacheck - govet - gocyclo - gocritic @@ -125,15 +127,14 @@ linters: - misspell - nakedret - nolintlint + - gosimple + - staticcheck + - unused disable: # These linters are all deprecated as of golangci-lint v1.49.0. We disable # them explicitly to avoid the linter logging deprecation warnings. - - deadcode - - varcheck - - scopelint - - structcheck - - interfacer + - megacheck presets: - bugs diff --git a/OWNERS.md b/OWNERS.md index 14ea228398..8c648972e1 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -10,9 +10,10 @@ guidelines and responsibilities for the steering committee and maintainers. ## Maintainers -* Daniel Mangum ([hasheddan](https://github.com/hasheddan)) -* Krish Chowdhary ([krishchow](https://github.com/krishchow)) * Carl Henrik Lunde ([chlunde](https://github.com/chlunde)) * Maximilian Blatt ([MisterMX](https://github.com/MisterMX)) * Ana Garlau ([anagarlau](https://github.com/anagarlau)) * Christopher Junk ([christophrj](https://github.com/christophrj)) +* Nico Andres ([AndresNico](https://github.com/AndresNico)) +* Kevin Kendzia ([kkendzia](https://github.com/kkendzia)) +* Gosha Khromov ([ggkhrmv](https://github.com/ggkhrmv)) diff --git a/apis/elbv2/generator-config.yaml b/apis/elbv2/generator-config.yaml index 2b4b3e3d7e..c5c8cbfacc 100644 --- a/apis/elbv2/generator-config.yaml +++ b/apis/elbv2/generator-config.yaml @@ -8,8 +8,8 @@ ignore: # Type has a json key of type_, so it's reimplemented with loadBalancerType - CreateLoadBalancerInput.Type - DescribeListenersInput.LoadBalancerArn - resource_names: - - Rule + - CreateRuleInput.ListenerArn + - CreateRuleInput.Priority resources: Listener: exceptions: @@ -26,6 +26,11 @@ resources: errors: 404: code: TargetGroupNotFound + Rule: + exceptions: + errors: + 404: + code: RuleNotFound # Since the Create* actions all return a list and we can't use the same return # type for Create and Generate* functions, use a noop statement here. This is a # bit hacky, but can't be helped without some way to configure this more diff --git a/apis/elbv2/v1alpha1/custom_types.go b/apis/elbv2/v1alpha1/custom_types.go index 226f02d679..6867ff700a 100644 --- a/apis/elbv2/v1alpha1/custom_types.go +++ b/apis/elbv2/v1alpha1/custom_types.go @@ -2,6 +2,26 @@ package v1alpha1 import xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" +type CustomRuleParameters struct { + // The Amazon Resource Name (ARN) of the listener. + // +optional + ListenerARN *string `json:"listenerARN,omitempty"` + + // Reference to Listener for Listener ARN + // +optional + ListenerARNRef *xpv1.Reference `json:"listenerARNRef,omitempty"` + + // Selector for references to Listener for Listener ARN + // +optional + ListenerARNSelector *xpv1.Selector `json:"listenerARNSelector,omitempty"` + + // The priority for the rule , must be unique for each rule in the listener + // +kubebuilder:validation:Required + Priority *int64 `json:"priority"` +} + +type CustomRuleObservation struct{} + // CustomCertificate includes custom fields about certificates. type CustomCertificate struct { // [HTTPS and TLS listeners] The default certificate for the listener. diff --git a/apis/elbv2/v1alpha1/zz_generated.deepcopy.go b/apis/elbv2/v1alpha1/zz_generated.deepcopy.go index ce2570dba5..5803c201de 100644 --- a/apis/elbv2/v1alpha1/zz_generated.deepcopy.go +++ b/apis/elbv2/v1alpha1/zz_generated.deepcopy.go @@ -550,6 +550,56 @@ func (in *CustomLoadBalancerParameters) DeepCopy() *CustomLoadBalancerParameters return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomRuleObservation) DeepCopyInto(out *CustomRuleObservation) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomRuleObservation. +func (in *CustomRuleObservation) DeepCopy() *CustomRuleObservation { + if in == nil { + return nil + } + out := new(CustomRuleObservation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomRuleParameters) DeepCopyInto(out *CustomRuleParameters) { + *out = *in + if in.ListenerARN != nil { + in, out := &in.ListenerARN, &out.ListenerARN + *out = new(string) + **out = **in + } + if in.ListenerARNRef != nil { + in, out := &in.ListenerARNRef, &out.ListenerARNRef + *out = new(v1.Reference) + (*in).DeepCopyInto(*out) + } + if in.ListenerARNSelector != nil { + in, out := &in.ListenerARNSelector, &out.ListenerARNSelector + *out = new(v1.Selector) + (*in).DeepCopyInto(*out) + } + if in.Priority != nil { + in, out := &in.Priority, &out.Priority + *out = new(int64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomRuleParameters. +func (in *CustomRuleParameters) DeepCopy() *CustomRuleParameters { + if in == nil { + return nil + } + out := new(CustomRuleParameters) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CustomTargetGroupObservation) DeepCopyInto(out *CustomTargetGroupObservation) { *out = *in @@ -677,6 +727,89 @@ func (in *ForwardActionConfig) DeepCopy() *ForwardActionConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPHeaderConditionConfig) DeepCopyInto(out *HTTPHeaderConditionConfig) { + *out = *in + if in.HTTPHeaderName != nil { + in, out := &in.HTTPHeaderName, &out.HTTPHeaderName + *out = new(string) + **out = **in + } + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPHeaderConditionConfig. +func (in *HTTPHeaderConditionConfig) DeepCopy() *HTTPHeaderConditionConfig { + if in == nil { + return nil + } + out := new(HTTPHeaderConditionConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPRequestMethodConditionConfig) DeepCopyInto(out *HTTPRequestMethodConditionConfig) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRequestMethodConditionConfig. +func (in *HTTPRequestMethodConditionConfig) DeepCopy() *HTTPRequestMethodConditionConfig { + if in == nil { + return nil + } + out := new(HTTPRequestMethodConditionConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostHeaderConditionConfig) DeepCopyInto(out *HostHeaderConditionConfig) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostHeaderConditionConfig. +func (in *HostHeaderConditionConfig) DeepCopy() *HostHeaderConditionConfig { + if in == nil { + return nil + } + out := new(HostHeaderConditionConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Listener) DeepCopyInto(out *Listener) { *out = *in @@ -1369,6 +1502,83 @@ func (in *Matcher) DeepCopy() *Matcher { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PathPatternConditionConfig) DeepCopyInto(out *PathPatternConditionConfig) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PathPatternConditionConfig. +func (in *PathPatternConditionConfig) DeepCopy() *PathPatternConditionConfig { + if in == nil { + return nil + } + out := new(PathPatternConditionConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *QueryStringConditionConfig) DeepCopyInto(out *QueryStringConditionConfig) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]*QueryStringKeyValuePair, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(QueryStringKeyValuePair) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new QueryStringConditionConfig. +func (in *QueryStringConditionConfig) DeepCopy() *QueryStringConditionConfig { + if in == nil { + return nil + } + out := new(QueryStringConditionConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *QueryStringKeyValuePair) DeepCopyInto(out *QueryStringKeyValuePair) { + *out = *in + if in.Key != nil { + in, out := &in.Key, &out.Key + *out = new(string) + **out = **in + } + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new QueryStringKeyValuePair. +func (in *QueryStringKeyValuePair) DeepCopy() *QueryStringKeyValuePair { + if in == nil { + return nil + } + out := new(QueryStringKeyValuePair) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RedirectActionConfig) DeepCopyInto(out *RedirectActionConfig) { *out = *in @@ -1416,6 +1626,153 @@ func (in *RedirectActionConfig) DeepCopy() *RedirectActionConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Rule) DeepCopyInto(out *Rule) { + *out = *in + 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 Rule. +func (in *Rule) DeepCopy() *Rule { + if in == nil { + return nil + } + out := new(Rule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Rule) 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 *RuleCondition) DeepCopyInto(out *RuleCondition) { + *out = *in + if in.Field != nil { + in, out := &in.Field, &out.Field + *out = new(string) + **out = **in + } + if in.HostHeaderConfig != nil { + in, out := &in.HostHeaderConfig, &out.HostHeaderConfig + *out = new(HostHeaderConditionConfig) + (*in).DeepCopyInto(*out) + } + if in.HTTPHeaderConfig != nil { + in, out := &in.HTTPHeaderConfig, &out.HTTPHeaderConfig + *out = new(HTTPHeaderConditionConfig) + (*in).DeepCopyInto(*out) + } + if in.HTTPRequestMethodConfig != nil { + in, out := &in.HTTPRequestMethodConfig, &out.HTTPRequestMethodConfig + *out = new(HTTPRequestMethodConditionConfig) + (*in).DeepCopyInto(*out) + } + if in.PathPatternConfig != nil { + in, out := &in.PathPatternConfig, &out.PathPatternConfig + *out = new(PathPatternConditionConfig) + (*in).DeepCopyInto(*out) + } + if in.QueryStringConfig != nil { + in, out := &in.QueryStringConfig, &out.QueryStringConfig + *out = new(QueryStringConditionConfig) + (*in).DeepCopyInto(*out) + } + if in.SourceIPConfig != nil { + in, out := &in.SourceIPConfig, &out.SourceIPConfig + *out = new(SourceIPConditionConfig) + (*in).DeepCopyInto(*out) + } + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuleCondition. +func (in *RuleCondition) DeepCopy() *RuleCondition { + if in == nil { + return nil + } + out := new(RuleCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RuleList) DeepCopyInto(out *RuleList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Rule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuleList. +func (in *RuleList) DeepCopy() *RuleList { + if in == nil { + return nil + } + out := new(RuleList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RuleList) 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 *RuleObservation) DeepCopyInto(out *RuleObservation) { + *out = *in + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]*Rule_SDK, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Rule_SDK) + (*in).DeepCopyInto(*out) + } + } + } + out.CustomRuleObservation = in.CustomRuleObservation +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuleObservation. +func (in *RuleObservation) DeepCopy() *RuleObservation { + if in == nil { + return nil + } + out := new(RuleObservation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RuleParameters) DeepCopyInto(out *RuleParameters) { *out = *in if in.Actions != nil { in, out := &in.Actions, &out.Actions @@ -1428,14 +1785,143 @@ func (in *Rule) DeepCopyInto(out *Rule) { } } } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]*RuleCondition, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RuleCondition) + (*in).DeepCopyInto(*out) + } + } + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]*Tag, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Tag) + (*in).DeepCopyInto(*out) + } + } + } + in.CustomRuleParameters.DeepCopyInto(&out.CustomRuleParameters) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rule. -func (in *Rule) DeepCopy() *Rule { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuleParameters. +func (in *RuleParameters) DeepCopy() *RuleParameters { if in == nil { return nil } - out := new(Rule) + out := new(RuleParameters) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RulePriorityPair) DeepCopyInto(out *RulePriorityPair) { + *out = *in + if in.RuleARN != nil { + in, out := &in.RuleARN, &out.RuleARN + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RulePriorityPair. +func (in *RulePriorityPair) DeepCopy() *RulePriorityPair { + if in == nil { + return nil + } + out := new(RulePriorityPair) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RuleSpec) DeepCopyInto(out *RuleSpec) { + *out = *in + in.ResourceSpec.DeepCopyInto(&out.ResourceSpec) + in.ForProvider.DeepCopyInto(&out.ForProvider) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuleSpec. +func (in *RuleSpec) DeepCopy() *RuleSpec { + if in == nil { + return nil + } + out := new(RuleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RuleStatus) DeepCopyInto(out *RuleStatus) { + *out = *in + in.ResourceStatus.DeepCopyInto(&out.ResourceStatus) + in.AtProvider.DeepCopyInto(&out.AtProvider) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuleStatus. +func (in *RuleStatus) DeepCopy() *RuleStatus { + if in == nil { + return nil + } + out := new(RuleStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Rule_SDK) DeepCopyInto(out *Rule_SDK) { + *out = *in + if in.Actions != nil { + in, out := &in.Actions, &out.Actions + *out = make([]*Action, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Action) + (*in).DeepCopyInto(*out) + } + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]*RuleCondition, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RuleCondition) + (*in).DeepCopyInto(*out) + } + } + } + if in.IsDefault != nil { + in, out := &in.IsDefault, &out.IsDefault + *out = new(bool) + **out = **in + } + if in.Priority != nil { + in, out := &in.Priority, &out.Priority + *out = new(string) + **out = **in + } + if in.RuleARN != nil { + in, out := &in.RuleARN, &out.RuleARN + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rule_SDK. +func (in *Rule_SDK) DeepCopy() *Rule_SDK { + if in == nil { + return nil + } + out := new(Rule_SDK) in.DeepCopyInto(out) return out } @@ -1448,6 +1934,17 @@ func (in *SSLPolicy) DeepCopyInto(out *SSLPolicy) { *out = new(string) **out = **in } + if in.SupportedLoadBalancerTypes != nil { + in, out := &in.SupportedLoadBalancerTypes, &out.SupportedLoadBalancerTypes + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SSLPolicy. @@ -1460,6 +1957,32 @@ func (in *SSLPolicy) DeepCopy() *SSLPolicy { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceIPConditionConfig) DeepCopyInto(out *SourceIPConditionConfig) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceIPConditionConfig. +func (in *SourceIPConditionConfig) DeepCopy() *SourceIPConditionConfig { + if in == nil { + return nil + } + out := new(SourceIPConditionConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetMapping) DeepCopyInto(out *SubnetMapping) { *out = *in diff --git a/apis/elbv2/v1alpha1/zz_generated.managed.go b/apis/elbv2/v1alpha1/zz_generated.managed.go index b2d5642833..c473127561 100644 --- a/apis/elbv2/v1alpha1/zz_generated.managed.go +++ b/apis/elbv2/v1alpha1/zz_generated.managed.go @@ -140,6 +140,66 @@ func (mg *LoadBalancer) SetWriteConnectionSecretToReference(r *xpv1.SecretRefere mg.Spec.WriteConnectionSecretToReference = r } +// GetCondition of this Rule. +func (mg *Rule) GetCondition(ct xpv1.ConditionType) xpv1.Condition { + return mg.Status.GetCondition(ct) +} + +// GetDeletionPolicy of this Rule. +func (mg *Rule) GetDeletionPolicy() xpv1.DeletionPolicy { + return mg.Spec.DeletionPolicy +} + +// GetManagementPolicies of this Rule. +func (mg *Rule) GetManagementPolicies() xpv1.ManagementPolicies { + return mg.Spec.ManagementPolicies +} + +// GetProviderConfigReference of this Rule. +func (mg *Rule) GetProviderConfigReference() *xpv1.Reference { + return mg.Spec.ProviderConfigReference +} + +// GetPublishConnectionDetailsTo of this Rule. +func (mg *Rule) GetPublishConnectionDetailsTo() *xpv1.PublishConnectionDetailsTo { + return mg.Spec.PublishConnectionDetailsTo +} + +// GetWriteConnectionSecretToReference of this Rule. +func (mg *Rule) GetWriteConnectionSecretToReference() *xpv1.SecretReference { + return mg.Spec.WriteConnectionSecretToReference +} + +// SetConditions of this Rule. +func (mg *Rule) SetConditions(c ...xpv1.Condition) { + mg.Status.SetConditions(c...) +} + +// SetDeletionPolicy of this Rule. +func (mg *Rule) SetDeletionPolicy(r xpv1.DeletionPolicy) { + mg.Spec.DeletionPolicy = r +} + +// SetManagementPolicies of this Rule. +func (mg *Rule) SetManagementPolicies(r xpv1.ManagementPolicies) { + mg.Spec.ManagementPolicies = r +} + +// SetProviderConfigReference of this Rule. +func (mg *Rule) SetProviderConfigReference(r *xpv1.Reference) { + mg.Spec.ProviderConfigReference = r +} + +// SetPublishConnectionDetailsTo of this Rule. +func (mg *Rule) SetPublishConnectionDetailsTo(r *xpv1.PublishConnectionDetailsTo) { + mg.Spec.PublishConnectionDetailsTo = r +} + +// SetWriteConnectionSecretToReference of this Rule. +func (mg *Rule) SetWriteConnectionSecretToReference(r *xpv1.SecretReference) { + mg.Spec.WriteConnectionSecretToReference = r +} + // GetCondition of this TargetGroup. func (mg *TargetGroup) GetCondition(ct xpv1.ConditionType) xpv1.Condition { return mg.Status.GetCondition(ct) diff --git a/apis/elbv2/v1alpha1/zz_generated.managedlist.go b/apis/elbv2/v1alpha1/zz_generated.managedlist.go index a6901b3a05..de8aa27ff5 100644 --- a/apis/elbv2/v1alpha1/zz_generated.managedlist.go +++ b/apis/elbv2/v1alpha1/zz_generated.managedlist.go @@ -38,6 +38,15 @@ func (l *LoadBalancerList) GetItems() []resource.Managed { return items } +// GetItems of this RuleList. +func (l *RuleList) 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 TargetGroupList. func (l *TargetGroupList) GetItems() []resource.Managed { items := make([]resource.Managed, len(l.Items)) diff --git a/apis/elbv2/v1alpha1/zz_rule.go b/apis/elbv2/v1alpha1/zz_rule.go new file mode 100644 index 0000000000..a418bc1226 --- /dev/null +++ b/apis/elbv2/v1alpha1/zz_rule.go @@ -0,0 +1,99 @@ +/* +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" +) + +// RuleParameters defines the desired state of Rule +type RuleParameters struct { + // Region is which region the Rule will be created. + // +kubebuilder:validation:Required + Region string `json:"region"` + // The actions. + // +kubebuilder:validation:Required + Actions []*Action `json:"actions"` + // The conditions. + // +kubebuilder:validation:Required + Conditions []*RuleCondition `json:"conditions"` + // The tags to assign to the rule. + Tags []*Tag `json:"tags,omitempty"` + CustomRuleParameters `json:",inline"` +} + +// RuleSpec defines the desired state of Rule +type RuleSpec struct { + xpv1.ResourceSpec `json:",inline"` + ForProvider RuleParameters `json:"forProvider"` +} + +// RuleObservation defines the observed state of Rule +type RuleObservation struct { + // Information about the rule. + Rules []*Rule_SDK `json:"rules,omitempty"` + + CustomRuleObservation `json:",inline"` +} + +// RuleStatus defines the observed state of Rule. +type RuleStatus struct { + xpv1.ResourceStatus `json:",inline"` + AtProvider RuleObservation `json:"atProvider,omitempty"` +} + +// +kubebuilder:object:root=true + +// Rule is the Schema for the Rules 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 Rule struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec RuleSpec `json:"spec"` + Status RuleStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// RuleList contains a list of Rules +type RuleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Rule `json:"items"` +} + +// Repository type metadata. +var ( + RuleKind = "Rule" + RuleGroupKind = schema.GroupKind{Group: CRDGroup, Kind: RuleKind}.String() + RuleKindAPIVersion = RuleKind + "." + GroupVersion.String() + RuleGroupVersionKind = GroupVersion.WithKind(RuleKind) +) + +func init() { + SchemeBuilder.Register(&Rule{}, &RuleList{}) +} diff --git a/apis/elbv2/v1alpha1/zz_types.go b/apis/elbv2/v1alpha1/zz_types.go index f8ef34dfaa..451620cbdd 100644 --- a/apis/elbv2/v1alpha1/zz_types.go +++ b/apis/elbv2/v1alpha1/zz_types.go @@ -150,6 +150,23 @@ type ForwardActionConfig struct { TargetGroups []*TargetGroupTuple `json:"targetGroups,omitempty"` } +// +kubebuilder:skipversion +type HTTPHeaderConditionConfig struct { + HTTPHeaderName *string `json:"httpHeaderName,omitempty"` + + Values []*string `json:"values,omitempty"` +} + +// +kubebuilder:skipversion +type HTTPRequestMethodConditionConfig struct { + Values []*string `json:"values,omitempty"` +} + +// +kubebuilder:skipversion +type HostHeaderConditionConfig struct { + Values []*string `json:"values,omitempty"` +} + // +kubebuilder:skipversion type Listener_SDK struct { AlpnPolicy []*string `json:"alpnPolicy,omitempty"` @@ -225,6 +242,23 @@ type Matcher struct { HTTPCode *string `json:"httpCode,omitempty"` } +// +kubebuilder:skipversion +type PathPatternConditionConfig struct { + Values []*string `json:"values,omitempty"` +} + +// +kubebuilder:skipversion +type QueryStringConditionConfig struct { + Values []*QueryStringKeyValuePair `json:"values,omitempty"` +} + +// +kubebuilder:skipversion +type QueryStringKeyValuePair struct { + Key *string `json:"key,omitempty"` + + Value *string `json:"value,omitempty"` +} + // +kubebuilder:skipversion type RedirectActionConfig struct { Host *string `json:"host,omitempty"` @@ -241,13 +275,68 @@ type RedirectActionConfig struct { } // +kubebuilder:skipversion -type Rule struct { +type RuleCondition struct { + Field *string `json:"field,omitempty"` + // Information about a host header condition. + HostHeaderConfig *HostHeaderConditionConfig `json:"hostHeaderConfig,omitempty"` + // Information about an HTTP header condition. + // + // There is a set of standard HTTP header fields. You can also define custom + // HTTP header fields. + HTTPHeaderConfig *HTTPHeaderConditionConfig `json:"httpHeaderConfig,omitempty"` + // Information about an HTTP method condition. + // + // HTTP defines a set of request methods, also referred to as HTTP verbs. For + // more information, see the HTTP Method Registry (https://www.iana.org/assignments/http-methods/http-methods.xhtml). + // You can also define custom HTTP methods. + HTTPRequestMethodConfig *HTTPRequestMethodConditionConfig `json:"httpRequestMethodConfig,omitempty"` + // Information about a path pattern condition. + PathPatternConfig *PathPatternConditionConfig `json:"pathPatternConfig,omitempty"` + // Information about a query string condition. + // + // The query string component of a URI starts after the first '?' character + // and is terminated by either a '#' character or the end of the URI. A typical + // query string contains key/value pairs separated by '&' characters. The allowed + // characters are specified by RFC 3986. Any character can be percentage encoded. + QueryStringConfig *QueryStringConditionConfig `json:"queryStringConfig,omitempty"` + // Information about a source IP condition. + // + // You can use this condition to route based on the IP address of the source + // that connects to the load balancer. If a client is behind a proxy, this is + // the IP address of the proxy not the IP address of the client. + SourceIPConfig *SourceIPConditionConfig `json:"sourceIPConfig,omitempty"` + + Values []*string `json:"values,omitempty"` +} + +// +kubebuilder:skipversion +type RulePriorityPair struct { + RuleARN *string `json:"ruleARN,omitempty"` +} + +// +kubebuilder:skipversion +type Rule_SDK struct { Actions []*Action `json:"actions,omitempty"` + + Conditions []*RuleCondition `json:"conditions,omitempty"` + + IsDefault *bool `json:"isDefault,omitempty"` + + Priority *string `json:"priority,omitempty"` + + RuleARN *string `json:"ruleARN,omitempty"` } // +kubebuilder:skipversion type SSLPolicy struct { Name *string `json:"name,omitempty"` + + SupportedLoadBalancerTypes []*string `json:"supportedLoadBalancerTypes,omitempty"` +} + +// +kubebuilder:skipversion +type SourceIPConditionConfig struct { + Values []*string `json:"values,omitempty"` } // +kubebuilder:skipversion diff --git a/apis/rds/generator-config.yaml b/apis/rds/generator-config.yaml index 5749532921..1739e0427b 100644 --- a/apis/rds/generator-config.yaml +++ b/apis/rds/generator-config.yaml @@ -34,6 +34,11 @@ resources: from: operation: DescribeDBClusters path: DBClusters.KmsKeyId + Port: + is_read_only: true + from: + operation: DescribeDBClusters + path: DBClusters.Port DBInstanceRoleAssociation: exceptions: errors: diff --git a/apis/rds/v1alpha1/custom_types.go b/apis/rds/v1alpha1/custom_types.go index 12736d0e09..6ea410c612 100644 --- a/apis/rds/v1alpha1/custom_types.go +++ b/apis/rds/v1alpha1/custom_types.go @@ -676,6 +676,74 @@ type CustomDBInstanceParameters struct { // +optional SkipFinalSnapshot bool `json:"skipFinalSnapshot,omitempty"` + // The identifier of the Multi-AZ DB cluster that will act as the source for + // the read replica. Each DB cluster can have up to 15 read replicas. + // + // Constraints: + // + // * Must be the identifier of an existing Multi-AZ DB cluster. + // + // * Can't be specified if the SourceDBInstanceIdentifier parameter is also + // specified. + // + // * The specified DB cluster must have automatic backups enabled, that is, + // its backup retention period must be greater than 0. + // + // * The source DB cluster must be in the same Amazon Web Services Region + // as the read replica. Cross-Region replication isn't supported. + // +immutable + // +crossplane:generate:reference:type=github.com/crossplane-contrib/provider-aws/apis/rds/v1alpha1.DBCluster + // +crossplane:generate:reference:extractor=github.com/crossplane-contrib/provider-aws/apis/rds/v1alpha1.DBCluster() + ReplicateSourceDBClusterID *string `json:"replicateSourceDBClusterID,omitempty"` + + // ReplicateSourceDBClusterIDRef is a reference to a DBCluster used to set + // ReplicateSourceDBClusterID. + // +optional + ReplicateSourceDBClusterIDRef *xpv1.Reference `json:"replicateSourceDBClusterIDRef,omitempty"` + + // ReplicateSourceDBClusterIDSelector selects a reference to a DBCluster used to + // set ReplicateSourceDBClusterID. + // +optional + ReplicateSourceDBClusterIDSelector *xpv1.Selector `json:"replicateSourceDBClusterIDSelector,omitempty"` + + // The identifier of the DB instance that will act as the source for the read + // replica. Each DB instance can have up to 15 read replicas, with the exception of + // Oracle and SQL Server, which can have up to five. + // + // Constraints: + // + // - Must be the identifier of an existing Db2, MariaDB, MySQL, Oracle, + // PostgreSQL, or SQL Server DB instance. + // + // * Can't be specified if the SourceDBClusterIdentifier parameter is also + // specified. + // + // - For the limitations of Oracle read replicas, see [Version and licensing considerations for RDS for Oracle replicas]in the Amazon RDS User + // Guide. + // + // - For the limitations of SQL Server read replicas, see [Read replica limitations with SQL Server]in the Amazon RDS User + // Guide. + // + // - The specified DB instance must have automatic backups enabled, that is, its + // backup retention period must be greater than 0. + // + // [Read replica limitations with SQL Server]: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/SQLServer.ReadReplicas.html#SQLServer.ReadReplicas.Limitations + // [Version and licensing considerations for RDS for Oracle replicas]: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-read-replicas.limitations.html#oracle-read-replicas.limitations.versions-and-licenses + // +immutable + // +crossplane:generate:reference:type=github.com/crossplane-contrib/provider-aws/apis/rds/v1alpha1.DBInstance + // +crossplane:generate:reference:extractor=github.com/crossplane-contrib/provider-aws/apis/rds/v1alpha1.DBInstance() + ReplicateSourceDBInstanceID *string `json:"replicateSourceDBInstanceID,omitempty"` + + // ReplicateSourceDBInstanceIDRef is a reference to a DBInstance used to set + // ReplicateSourceDBInstanceID. + // +optional + ReplicateSourceDBInstanceIDRef *xpv1.Reference `json:"replicateSourceDBInstanceIDRef,omitempty"` + + // ReplicateSourceDBInstanceIDSelector selects a reference to a DBInstance used to + // set ReplicateSourceDBInstanceID. + // +optional + ReplicateSourceDBInstanceIDSelector *xpv1.Selector `json:"replicateSourceDBInstanceIDSelector,omitempty"` + // A list of Amazon EC2 VPC security groups to authorize on this DB instance. // This change is asynchronously applied as soon as possible. // @@ -741,10 +809,25 @@ type CustomDBInstanceParameters struct { // deleted. // +optional DeleteAutomatedBackups *bool `json:"deleteAutomatedBackups,omitempty"` + + // TagIgnorePrefixes defines a list of tag key prefixes that should be ignored + // during tag comparison and updates by the reconciler. + // +optional + TagIgnorePrefixes []string `json:"tagIgnorePrefixes,omitempty"` } // CustomDBInstanceObservation includes the custom status fields of DBInstance. -type CustomDBInstanceObservation struct{} +type CustomDBInstanceObservation struct { + // The database role may be Primary, Replica. + DatabaseRole *string `json:"databaseRole,omitempty"` +} +type CustomDBInstanceObservation struct { + // AWS API calls don't return any field which explicitly indicates the role of database, which would be really convenient. + // DatabaseRole works on the similar principle as the Role field in AWS UI("Aurora and RDS" > "Databases"). + + // The database role may be Standalone, Primary or Replica. + DatabaseRole *string `json:"databaseRole,omitempty"` +} // CustomDBInstanceRoleAssociationParameters are custom parameters for the DBInstanceRoleAssociation type CustomDBInstanceRoleAssociationParameters struct { diff --git a/apis/rds/v1alpha1/zz_db_cluster.go b/apis/rds/v1alpha1/zz_db_cluster.go index 6b4fa60788..be7675ce85 100644 --- a/apis/rds/v1alpha1/zz_db_cluster.go +++ b/apis/rds/v1alpha1/zz_db_cluster.go @@ -749,6 +749,8 @@ type DBClusterObservation struct { // // This setting is only for non-Aurora Multi-AZ DB clusters. PerformanceInsightsEnabled *bool `json:"performanceInsightsEnabled,omitempty"` + // The port that the database engine is listening on. + Port *int64 `json:"port,omitempty"` // Contains one or more identifiers of the read replicas associated with this // DB cluster. ReadReplicaIdentifiers []*string `json:"readReplicaIdentifiers,omitempty"` diff --git a/apis/rds/v1alpha1/zz_generated.deepcopy.go b/apis/rds/v1alpha1/zz_generated.deepcopy.go index b4e061d18f..bdd1c1ef0d 100644 --- a/apis/rds/v1alpha1/zz_generated.deepcopy.go +++ b/apis/rds/v1alpha1/zz_generated.deepcopy.go @@ -606,6 +606,16 @@ func (in *CustomDBEngineVersionAMI) DeepCopy() *CustomDBEngineVersionAMI { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CustomDBInstanceObservation) DeepCopyInto(out *CustomDBInstanceObservation) { *out = *in + if in.DatabaseRole != nil { + in, out := &in.DatabaseRole, &out.DatabaseRole + *out = new(string) + **out = **in + } + if in.DatabaseRole != nil { + in, out := &in.DatabaseRole, &out.DatabaseRole + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomDBInstanceObservation. @@ -676,6 +686,36 @@ func (in *CustomDBInstanceParameters) DeepCopyInto(out *CustomDBInstanceParamete *out = new(v1.Selector) (*in).DeepCopyInto(*out) } + if in.ReplicateSourceDBClusterID != nil { + in, out := &in.ReplicateSourceDBClusterID, &out.ReplicateSourceDBClusterID + *out = new(string) + **out = **in + } + if in.ReplicateSourceDBClusterIDRef != nil { + in, out := &in.ReplicateSourceDBClusterIDRef, &out.ReplicateSourceDBClusterIDRef + *out = new(v1.Reference) + (*in).DeepCopyInto(*out) + } + if in.ReplicateSourceDBClusterIDSelector != nil { + in, out := &in.ReplicateSourceDBClusterIDSelector, &out.ReplicateSourceDBClusterIDSelector + *out = new(v1.Selector) + (*in).DeepCopyInto(*out) + } + if in.ReplicateSourceDBInstanceID != nil { + in, out := &in.ReplicateSourceDBInstanceID, &out.ReplicateSourceDBInstanceID + *out = new(string) + **out = **in + } + if in.ReplicateSourceDBInstanceIDRef != nil { + in, out := &in.ReplicateSourceDBInstanceIDRef, &out.ReplicateSourceDBInstanceIDRef + *out = new(v1.Reference) + (*in).DeepCopyInto(*out) + } + if in.ReplicateSourceDBInstanceIDSelector != nil { + in, out := &in.ReplicateSourceDBInstanceIDSelector, &out.ReplicateSourceDBInstanceIDSelector + *out = new(v1.Selector) + (*in).DeepCopyInto(*out) + } if in.VPCSecurityGroupIDs != nil { in, out := &in.VPCSecurityGroupIDs, &out.VPCSecurityGroupIDs *out = make([]string, len(*in)) @@ -728,6 +768,11 @@ func (in *CustomDBInstanceParameters) DeepCopyInto(out *CustomDBInstanceParamete *out = new(bool) **out = **in } + if in.TagIgnorePrefixes != nil { + in, out := &in.TagIgnorePrefixes, &out.TagIgnorePrefixes + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomDBInstanceParameters. @@ -1585,6 +1630,11 @@ func (in *DBClusterObservation) DeepCopyInto(out *DBClusterObservation) { *out = new(bool) **out = **in } + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(int64) + **out = **in + } if in.ReadReplicaIdentifiers != nil { in, out := &in.ReadReplicaIdentifiers, &out.ReadReplicaIdentifiers *out = make([]*string, len(*in)) @@ -3551,7 +3601,8 @@ func (in *DBInstanceObservation) DeepCopyInto(out *DBInstanceObservation) { } } } - out.CustomDBInstanceObservation = in.CustomDBInstanceObservation + in.CustomDBInstanceObservation.DeepCopyInto(&out.CustomDBInstanceObservation) + in.CustomDBInstanceObservation.DeepCopyInto(&out.CustomDBInstanceObservation) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DBInstanceObservation. diff --git a/apis/s3/v1beta1/bucket_types.go b/apis/s3/v1beta1/bucket_types.go index 655b2ba671..2830a6d71b 100644 --- a/apis/s3/v1beta1/bucket_types.go +++ b/apis/s3/v1beta1/bucket_types.go @@ -64,9 +64,14 @@ type BucketParameters struct { GrantWriteACP *string `json:"grantWriteAcp,omitempty"` // Specifies whether you want S3 Object Lock to be enabled for the new bucket. + // After you enable Object Lock for a bucket, you can't disable Object Lock or suspend Versioning for that bucket // +optional ObjectLockEnabledForBucket *bool `json:"objectLockEnabledForBucket,omitempty"` + // Specifies the Object Lock rule for the bucket. Works only when ObjectLockEnabledForBucket is true. + // +optional + ObjectLockRule *ObjectLockRule `json:"objectLockRule,omitempty"` + // The container element for object ownership for a bucket's ownership controls. // BucketOwnerPreferred - Objects uploaded to the bucket change ownership to the // bucket owner if the objects are uploaded with the bucket-owner-full-control diff --git a/apis/s3/v1beta1/object_lock_configuration_types.go b/apis/s3/v1beta1/object_lock_configuration_types.go new file mode 100644 index 0000000000..992ca61c80 --- /dev/null +++ b/apis/s3/v1beta1/object_lock_configuration_types.go @@ -0,0 +1,45 @@ +/* +Copyright 2025 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. +*/ + +package v1beta1 + +// ObjectLockRule the container element for an Object Lock rule. +type ObjectLockRule struct { + // The container element for optionally specifying the default Object Lock + // retention settings for new objects placed in the specified bucket. + // The DefaultRetention settings require both a mode and a period. + // The DefaultRetention period can be either Days or Years but you must select one + // You cannot specify Days and Years at the same time. + // For more information, see Object Lock(https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html) + DefaultRetention *DefaultRetention `json:"defaultRetention,omitempty"` +} + +// DefaultRetention the container element for the default Object Lock retention settings. +type DefaultRetention struct { + // The number of days that you want to specify for the default retention period. + // Must be used with Mode. + Days *int32 `json:"days,omitempty"` + + // The default Object Lock retention mode you want to apply to new objects placed + // in the specified bucket. Must be used with either Days or Years . + // Valid values are "GOVERNANCE", "COMPLIANCE" + // +kubebuilder:validation:Enum=GOVERNANCE;COMPLIANCE; + Mode string `json:"mode"` + + // The number of years that you want to specify for the default retention period. + // Must be used with Mode . + Years *int32 `json:"years,omitempty"` +} diff --git a/apis/s3/v1beta1/zz_generated.deepcopy.go b/apis/s3/v1beta1/zz_generated.deepcopy.go index 59894fa1a9..c3bdba449f 100644 --- a/apis/s3/v1beta1/zz_generated.deepcopy.go +++ b/apis/s3/v1beta1/zz_generated.deepcopy.go @@ -205,6 +205,11 @@ func (in *BucketParameters) DeepCopyInto(out *BucketParameters) { *out = new(bool) **out = **in } + if in.ObjectLockRule != nil { + in, out := &in.ObjectLockRule, &out.ObjectLockRule + *out = new(ObjectLockRule) + (*in).DeepCopyInto(*out) + } if in.ObjectOwnership != nil { in, out := &in.ObjectOwnership, &out.ObjectOwnership *out = new(string) @@ -423,6 +428,31 @@ func (in *Condition) DeepCopy() *Condition { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultRetention) DeepCopyInto(out *DefaultRetention) { + *out = *in + if in.Days != nil { + in, out := &in.Days, &out.Days + *out = new(int32) + **out = **in + } + if in.Years != nil { + in, out := &in.Years, &out.Years + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultRetention. +func (in *DefaultRetention) DeepCopy() *DefaultRetention { + if in == nil { + return nil + } + out := new(DefaultRetention) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DeleteMarkerReplication) DeepCopyInto(out *DeleteMarkerReplication) { *out = *in @@ -892,6 +922,26 @@ func (in *NotificationConfigurationFilter) DeepCopy() *NotificationConfiguration return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ObjectLockRule) DeepCopyInto(out *ObjectLockRule) { + *out = *in + if in.DefaultRetention != nil { + in, out := &in.DefaultRetention, &out.DefaultRetention + *out = new(DefaultRetention) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectLockRule. +func (in *ObjectLockRule) DeepCopy() *ObjectLockRule { + if in == nil { + return nil + } + out := new(ObjectLockRule) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PaymentConfiguration) DeepCopyInto(out *PaymentConfiguration) { *out = *in diff --git a/examples/ecs/service.yaml b/examples/ecs/service.yaml index a99475e244..ceecf14d8e 100644 --- a/examples/ecs/service.yaml +++ b/examples/ecs/service.yaml @@ -37,3 +37,41 @@ spec: name: example providerConfigRef: name: example +--- +apiVersion: ecs.aws.crossplane.io/v1alpha1 +kind: Service +metadata: + name: nginx-test-ecs + annotations: + task-definition-network-mode: awsvpc +spec: + forProvider: + cluster: arn:aws:ecs:us-east-1:123456789:cluster/crossplane-ecs-controller-test + launchType: EC2 + region: us-east-1 + schedulingStrategy: DAEMON + networkConfiguration: + awsvpcConfiguration: + assignPublicIP: DISABLED + subnets: + - subnet-06338caec7dcf + - subnet-02a8df89fdafa + taskDefinition: arn:aws:ecs:us-east-1:123456789:task-definition/nginx:3 + providerConfigRef: + name: providerconfig-aws +--- +apiVersion: ecs.aws.crossplane.io/v1alpha1 +kind: Service +metadata: + name: filebeat-test + annotations: + task-definition-network-mode: host +spec: + forProvider: + cluster: arn:aws:ecs:us-east-1:123456789:cluster/crossplane-ecs-controller-test + launchType: EC2 + region: us-east-1 + schedulingStrategy: DAEMON + taskDefinition: arn:aws:ecs:us-east-1:123456789:task-definition/pratyush-filebeat:1 + providerConfigRef: + name: providerconfig-aws diff --git a/examples/elbv2/rule.yaml b/examples/elbv2/rule.yaml new file mode 100644 index 0000000000..0c7379ec12 --- /dev/null +++ b/examples/elbv2/rule.yaml @@ -0,0 +1,45 @@ +apiVersion: elbv2.aws.crossplane.io/v1alpha1 +kind: Rule +metadata: + name: rule-test +spec: + providerConfigRef: + name: providerconfig-aws + forProvider: + actions: + - type_: forward + targetGroupARN: 'arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/elbv2-crossplane-test/2024c4ffdf606bd3' + conditions: + - field: path-pattern + pathPatternConfig: + values: + - /static/test/* + - field: host-header + hostHeaderConfig: + values: + - example.com + listenerARN: 'arn:aws:elasticloadbalancing:us-east-1:123456789012:listener/app/crossplane-elbv2-crd-test/8702b45b10788e66/76bafee45f01ca63' + priority: 102 + region: us-east-1 +--- +apiVersion: elbv2.aws.crossplane.io/v1alpha1 +kind: Rule +metadata: + name: rule-sample +spec: + providerConfigRef: + name: providerconfig-aws + forProvider: + actions: + - type_: forward + forwardConfig: + targetGroups: + - targetGroupARN: 'arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/elbv2-crossplane-test/2024c4ffdf606bd3' + conditions: + - field: path-pattern + pathPatternConfig: + values: + - /static/* + listenerARN: 'arn:aws:elasticloadbalancing:us-east-1:123456789012:listener/app/crossplane-elbv2-crd-test/8702b45b10788e66/76bafee45f01ca63' + priority: 101 + region: us-east-1 \ No newline at end of file diff --git a/examples/rds/db-instance-read-replica.yaml b/examples/rds/db-instance-read-replica.yaml new file mode 100644 index 0000000000..e91408762d --- /dev/null +++ b/examples/rds/db-instance-read-replica.yaml @@ -0,0 +1,32 @@ +apiVersion: rds.aws.crossplane.io/v1alpha1 +kind: DBInstance +metadata: + name: standalone-test +spec: + forProvider: + region: eu-central-1 + replicateSourceDBInstanceID: kir-test + engine: mariadb + dbInstanceClass: db.t3.micro + autoMinorVersionUpgrade: true + allowMajorVersionUpgrade: true # unset per default (Note: supported dbInstanceClass and dbParameterGroup with correct dbParameterGroupFamily needed, before majorVersion upgrade possible; applyImmediately matters) + applyImmediately: true + skipFinalSnapshot: true + masterUserPasswordSecretRef: + key: password + name: replica-test + namespace: default + writeConnectionSecretToRef: + name: replica-test-out + namespace: default + providerConfigRef: + name: providerconfig-aws +--- +apiVersion: v1 +kind: Secret +metadata: + name: replica-test + namespace: default +type: Opaque +data: + password: dGVzdFBhc3N3b3JkITEyMw== # testPassword!123 diff --git a/examples/s3/bucket-object-lock.yaml b/examples/s3/bucket-object-lock.yaml new file mode 100644 index 0000000000..145689d30f --- /dev/null +++ b/examples/s3/bucket-object-lock.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: s3.aws.crossplane.io/v1beta1 +kind: Bucket +metadata: + name: object-lock-sample +spec: + forProvider: + locationConstraint: eu-central-2 + objectLockEnabledForBucket: true + objectLockRule: + defaultRetention: + days: 7 + mode: COMPLIANCE + providerConfigRef: + name: provider-aws \ No newline at end of file diff --git a/examples/wafv2/webacl.yaml b/examples/wafv2/webacl.yaml index 7042e04936..8aa2309a11 100644 --- a/examples/wafv2/webacl.yaml +++ b/examples/wafv2/webacl.yaml @@ -29,7 +29,7 @@ spec: } }, "PositionalConstraint": "CONTAINS", - "SearchString": "YmFkQm90", + "SearchString": "badBot", "TextTransformations": [ { "Priority": 0, @@ -47,7 +47,7 @@ spec: } }, "PositionalConstraint": "CONTAINS", - "SearchString": "YmFkQm90", + "SearchString": "badBot", "TextTransformations": [ { "Priority": 1, @@ -72,7 +72,7 @@ spec: singleHeader: name: "User-Agent" positionalConstraint: "CONTAINS" - searchString: "YmFkQm90" + searchString: "badBot" textTransformations: - priority: 1 type_: "NONE" diff --git a/package/crds/elbv2.aws.crossplane.io_rules.yaml b/package/crds/elbv2.aws.crossplane.io_rules.yaml new file mode 100644 index 0000000000..e160f05acb --- /dev/null +++ b/package/crds/elbv2.aws.crossplane.io_rules.yaml @@ -0,0 +1,882 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: rules.elbv2.aws.crossplane.io +spec: + group: elbv2.aws.crossplane.io + names: + categories: + - crossplane + - managed + - aws + kind: Rule + listKind: RuleList + plural: rules + singular: rule + 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: Rule is the Schema for the Rules 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: RuleSpec defines the desired state of Rule + 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: RuleParameters defines the desired state of Rule + properties: + actions: + description: The actions. + items: + properties: + authenticateCognitoConfig: + description: |- + Request parameters to use when integrating with Amazon Cognito to authenticate + users. + properties: + authenticationRequestExtraParams: + additionalProperties: + type: string + type: object + onUnauthenticatedRequest: + type: string + scope: + type: string + sessionCookieName: + type: string + sessionTimeout: + format: int64 + type: integer + userPoolARN: + type: string + userPoolClientID: + type: string + userPoolDomain: + type: string + type: object + authenticateOIDCConfig: + description: |- + Request parameters when using an identity provider (IdP) that is compliant + with OpenID Connect (OIDC) to authenticate users. + properties: + authenticationRequestExtraParams: + additionalProperties: + type: string + type: object + authorizationEndpoint: + type: string + clientID: + type: string + clientSecret: + type: string + issuer: + type: string + onUnauthenticatedRequest: + type: string + scope: + type: string + sessionCookieName: + type: string + sessionTimeout: + format: int64 + type: integer + tokenEndpoint: + type: string + useExistingClientSecret: + type: boolean + userInfoEndpoint: + type: string + type: object + fixedResponseConfig: + description: Information about an action that returns a + custom HTTP response. + properties: + contentType: + type: string + messageBody: + type: string + statusCode: + type: string + type: object + forwardConfig: + description: Information about a forward action. + properties: + targetGroupStickinessConfig: + description: Information about the target group stickiness + for a rule. + properties: + durationSeconds: + format: int64 + type: integer + enabled: + type: boolean + type: object + targetGroups: + items: + properties: + targetGroupARN: + type: string + weight: + format: int64 + type: integer + type: object + type: array + type: object + order: + format: int64 + type: integer + redirectConfig: + description: |- + Information about a redirect action. + + A URI consists of the following components: protocol://hostname:port/path?query. + You must modify at least one of the following components to avoid a redirect + loop: protocol, hostname, port, or path. Any components that you do not modify + retain their original values. + + You can reuse URI components using the following reserved keywords: + + * #{protocol} + + * #{host} + + * #{port} + + * #{path} (the leading "/" is removed) + + * #{query} + + For example, you can change the path to "/new/#{path}", the hostname to "example.#{host}", + or the query to "#{query}&value=xyz". + properties: + host: + type: string + path: + type: string + port: + type: string + protocol: + type: string + query: + type: string + statusCode: + type: string + type: object + targetGroupARN: + type: string + type_: + type: string + type: object + type: array + conditions: + description: The conditions. + items: + properties: + field: + type: string + hostHeaderConfig: + description: Information about a host header condition. + properties: + values: + items: + type: string + type: array + type: object + httpHeaderConfig: + description: |- + Information about an HTTP header condition. + + There is a set of standard HTTP header fields. You can also define custom + HTTP header fields. + properties: + httpHeaderName: + type: string + values: + items: + type: string + type: array + type: object + httpRequestMethodConfig: + description: |- + Information about an HTTP method condition. + + HTTP defines a set of request methods, also referred to as HTTP verbs. For + more information, see the HTTP Method Registry (https://www.iana.org/assignments/http-methods/http-methods.xhtml). + You can also define custom HTTP methods. + properties: + values: + items: + type: string + type: array + type: object + pathPatternConfig: + description: Information about a path pattern condition. + properties: + values: + items: + type: string + type: array + type: object + queryStringConfig: + description: |- + Information about a query string condition. + + The query string component of a URI starts after the first '?' character + and is terminated by either a '#' character or the end of the URI. A typical + query string contains key/value pairs separated by '&' characters. The allowed + characters are specified by RFC 3986. Any character can be percentage encoded. + properties: + values: + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + type: object + sourceIPConfig: + description: |- + Information about a source IP condition. + + You can use this condition to route based on the IP address of the source + that connects to the load balancer. If a client is behind a proxy, this is + the IP address of the proxy not the IP address of the client. + properties: + values: + items: + type: string + type: array + type: object + values: + items: + type: string + type: array + type: object + type: array + listenerARN: + description: The Amazon Resource Name (ARN) of the listener. + type: string + listenerARNRef: + description: Reference to Listener for Listener ARN + 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 + listenerARNSelector: + description: Selector for references to Listener for Listener + ARN + properties: + matchControllerRef: + description: |- + MatchControllerRef ensures an object with the same controller reference + as the selecting object is selected. + type: boolean + matchLabels: + additionalProperties: + type: string + description: MatchLabels ensures an object with matching labels + is selected. + type: object + policy: + description: Policies for selection. + 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 + type: object + priority: + description: The priority for the rule , must be unique for each + rule in the listener + format: int64 + type: integer + region: + description: Region is which region the Rule will be created. + type: string + tags: + description: The tags to assign to the rule. + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + required: + - actions + - conditions + - priority + - 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: RuleStatus defines the observed state of Rule. + properties: + atProvider: + description: RuleObservation defines the observed state of Rule + properties: + rules: + description: Information about the rule. + items: + properties: + actions: + items: + properties: + authenticateCognitoConfig: + description: |- + Request parameters to use when integrating with Amazon Cognito to authenticate + users. + properties: + authenticationRequestExtraParams: + additionalProperties: + type: string + type: object + onUnauthenticatedRequest: + type: string + scope: + type: string + sessionCookieName: + type: string + sessionTimeout: + format: int64 + type: integer + userPoolARN: + type: string + userPoolClientID: + type: string + userPoolDomain: + type: string + type: object + authenticateOIDCConfig: + description: |- + Request parameters when using an identity provider (IdP) that is compliant + with OpenID Connect (OIDC) to authenticate users. + properties: + authenticationRequestExtraParams: + additionalProperties: + type: string + type: object + authorizationEndpoint: + type: string + clientID: + type: string + clientSecret: + type: string + issuer: + type: string + onUnauthenticatedRequest: + type: string + scope: + type: string + sessionCookieName: + type: string + sessionTimeout: + format: int64 + type: integer + tokenEndpoint: + type: string + useExistingClientSecret: + type: boolean + userInfoEndpoint: + type: string + type: object + fixedResponseConfig: + description: Information about an action that returns + a custom HTTP response. + properties: + contentType: + type: string + messageBody: + type: string + statusCode: + type: string + type: object + forwardConfig: + description: Information about a forward action. + properties: + targetGroupStickinessConfig: + description: Information about the target group + stickiness for a rule. + properties: + durationSeconds: + format: int64 + type: integer + enabled: + type: boolean + type: object + targetGroups: + items: + properties: + targetGroupARN: + type: string + weight: + format: int64 + type: integer + type: object + type: array + type: object + order: + format: int64 + type: integer + redirectConfig: + description: |- + Information about a redirect action. + + A URI consists of the following components: protocol://hostname:port/path?query. + You must modify at least one of the following components to avoid a redirect + loop: protocol, hostname, port, or path. Any components that you do not modify + retain their original values. + + You can reuse URI components using the following reserved keywords: + + * #{protocol} + + * #{host} + + * #{port} + + * #{path} (the leading "/" is removed) + + * #{query} + + For example, you can change the path to "/new/#{path}", the hostname to "example.#{host}", + or the query to "#{query}&value=xyz". + properties: + host: + type: string + path: + type: string + port: + type: string + protocol: + type: string + query: + type: string + statusCode: + type: string + type: object + targetGroupARN: + type: string + type_: + type: string + type: object + type: array + conditions: + items: + properties: + field: + type: string + hostHeaderConfig: + description: Information about a host header condition. + properties: + values: + items: + type: string + type: array + type: object + httpHeaderConfig: + description: |- + Information about an HTTP header condition. + + There is a set of standard HTTP header fields. You can also define custom + HTTP header fields. + properties: + httpHeaderName: + type: string + values: + items: + type: string + type: array + type: object + httpRequestMethodConfig: + description: |- + Information about an HTTP method condition. + + HTTP defines a set of request methods, also referred to as HTTP verbs. For + more information, see the HTTP Method Registry (https://www.iana.org/assignments/http-methods/http-methods.xhtml). + You can also define custom HTTP methods. + properties: + values: + items: + type: string + type: array + type: object + pathPatternConfig: + description: Information about a path pattern condition. + properties: + values: + items: + type: string + type: array + type: object + queryStringConfig: + description: |- + Information about a query string condition. + + The query string component of a URI starts after the first '?' character + and is terminated by either a '#' character or the end of the URI. A typical + query string contains key/value pairs separated by '&' characters. The allowed + characters are specified by RFC 3986. Any character can be percentage encoded. + properties: + values: + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + type: object + sourceIPConfig: + description: |- + Information about a source IP condition. + + You can use this condition to route based on the IP address of the source + that connects to the load balancer. If a client is behind a proxy, this is + the IP address of the proxy not the IP address of the client. + properties: + values: + items: + type: string + type: array + type: object + values: + items: + type: string + type: array + type: object + type: array + isDefault: + type: boolean + priority: + type: string + ruleARN: + type: string + type: object + type: array + 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/package/crds/rds.aws.crossplane.io_dbclusters.yaml b/package/crds/rds.aws.crossplane.io_dbclusters.yaml index 7defe05e20..8e77d485ab 100644 --- a/package/crds/rds.aws.crossplane.io_dbclusters.yaml +++ b/package/crds/rds.aws.crossplane.io_dbclusters.yaml @@ -1885,6 +1885,10 @@ spec: This setting is only for non-Aurora Multi-AZ DB clusters. type: boolean + port: + description: The port that the database engine is listening on. + format: int64 + type: integer readReplicaIdentifiers: description: |- Contains one or more identifiers of the read replicas associated with this diff --git a/package/crds/rds.aws.crossplane.io_dbinstances.yaml b/package/crds/rds.aws.crossplane.io_dbinstances.yaml index 0fcbee3742..680f378f39 100644 --- a/package/crds/rds.aws.crossplane.io_dbinstances.yaml +++ b/package/crds/rds.aws.crossplane.io_dbinstances.yaml @@ -1635,6 +1635,206 @@ spec: region: description: Region is which region the DBInstance will be created. type: string + replicateSourceDBClusterID: + description: |- + The identifier of the Multi-AZ DB cluster that will act as the source for + the read replica. Each DB cluster can have up to 15 read replicas. + + Constraints: + + * Must be the identifier of an existing Multi-AZ DB cluster. + + * Can't be specified if the SourceDBInstanceIdentifier parameter is also + specified. + + * The specified DB cluster must have automatic backups enabled, that is, + its backup retention period must be greater than 0. + + * The source DB cluster must be in the same Amazon Web Services Region + as the read replica. Cross-Region replication isn't supported. + type: string + replicateSourceDBClusterIDRef: + description: |- + ReplicateSourceDBClusterIDRef is a reference to a DBCluster used to set + ReplicateSourceDBClusterID. + 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 + replicateSourceDBClusterIDSelector: + description: |- + ReplicateSourceDBClusterIDSelector selects a reference to a DBCluster used to + set ReplicateSourceDBClusterID. + properties: + matchControllerRef: + description: |- + MatchControllerRef ensures an object with the same controller reference + as the selecting object is selected. + type: boolean + matchLabels: + additionalProperties: + type: string + description: MatchLabels ensures an object with matching labels + is selected. + type: object + policy: + description: Policies for selection. + 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 + type: object + replicateSourceDBInstanceID: + description: |- + The identifier of the DB instance that will act as the source for the read + replica. Each DB instance can have up to 15 read replicas, with the exception of + Oracle and SQL Server, which can have up to five. + + Constraints: + + - Must be the identifier of an existing Db2, MariaDB, MySQL, Oracle, + PostgreSQL, or SQL Server DB instance. + + * Can't be specified if the SourceDBClusterIdentifier parameter is also + specified. + + - For the limitations of Oracle read replicas, see [Version and licensing considerations for RDS for Oracle replicas]in the Amazon RDS User + Guide. + + - For the limitations of SQL Server read replicas, see [Read replica limitations with SQL Server]in the Amazon RDS User + Guide. + + - The specified DB instance must have automatic backups enabled, that is, its + backup retention period must be greater than 0. + + [Read replica limitations with SQL Server]: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/SQLServer.ReadReplicas.html#SQLServer.ReadReplicas.Limitations + [Version and licensing considerations for RDS for Oracle replicas]: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-read-replicas.limitations.html#oracle-read-replicas.limitations.versions-and-licenses + type: string + replicateSourceDBInstanceIDRef: + description: |- + ReplicateSourceDBInstanceIDRef is a reference to a DBInstance used to set + ReplicateSourceDBInstanceID. + 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 + replicateSourceDBInstanceIDSelector: + description: |- + ReplicateSourceDBInstanceIDSelector selects a reference to a DBInstance used to + set ReplicateSourceDBInstanceID. + properties: + matchControllerRef: + description: |- + MatchControllerRef ensures an object with the same controller reference + as the selecting object is selected. + type: boolean + matchLabels: + additionalProperties: + type: string + description: MatchLabels ensures an object with matching labels + is selected. + type: object + policy: + description: Policies for selection. + 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 + type: object restoreFrom: description: RestoreFrom specifies the details of the backup to restore when creating a new DBInstance. @@ -1770,6 +1970,11 @@ spec: Default: io1, if the Iops parameter is specified. Otherwise, gp2. type: string + tagIgnorePrefixes: + description: List of tag prefixes to be ignored during reconciliation. + items: + type: string + type: array tags: description: Tags to assign to the DB instance. items: @@ -2157,6 +2362,9 @@ spec: For more information about CoIPs, see Customer-owned IP addresses (https://docs.aws.amazon.com/outposts/latest/userguide/routing.html#ip-addressing) in the Amazon Web Services Outposts User Guide. type: boolean + databaseRole: + description: The database role may be Primary, Replica. + type: string dbClusterIdentifier: description: |- If the DB instance is a member of a DB cluster, indicates the name of the diff --git a/package/crds/s3.aws.crossplane.io_buckets.yaml b/package/crds/s3.aws.crossplane.io_buckets.yaml index a22f9dd83a..eb045b6728 100644 --- a/package/crds/s3.aws.crossplane.io_buckets.yaml +++ b/package/crds/s3.aws.crossplane.io_buckets.yaml @@ -972,9 +972,48 @@ spec: type: array type: object objectLockEnabledForBucket: - description: Specifies whether you want S3 Object Lock to be enabled - for the new bucket. + description: |- + Specifies whether you want S3 Object Lock to be enabled for the new bucket. + After you enable Object Lock for a bucket, you can't disable Object Lock or suspend Versioning for that bucket type: boolean + objectLockRule: + description: Specifies the Object Lock rule for the bucket. Works + only when ObjectLockEnabledForBucket is true. + properties: + defaultRetention: + description: |- + The container element for optionally specifying the default Object Lock + retention settings for new objects placed in the specified bucket. + The DefaultRetention settings require both a mode and a period. + The DefaultRetention period can be either Days or Years but you must select one + You cannot specify Days and Years at the same time. + For more information, see Object Lock(https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html) + properties: + days: + description: |- + The number of days that you want to specify for the default retention period. + Must be used with Mode. + format: int32 + type: integer + mode: + description: |- + The default Object Lock retention mode you want to apply to new objects placed + in the specified bucket. Must be used with either Days or Years . + Valid values are "GOVERNANCE", "COMPLIANCE" + enum: + - GOVERNANCE + - COMPLIANCE + type: string + years: + description: |- + The number of years that you want to specify for the default retention period. + Must be used with Mode . + format: int32 + type: integer + required: + - mode + type: object + type: object objectOwnership: description: |- The container element for object ownership for a bucket's ownership controls. diff --git a/pkg/clients/rds/common.go b/pkg/clients/rds/common.go index c45dc65313..2934a665ab 100644 --- a/pkg/clients/rds/common.go +++ b/pkg/clients/rds/common.go @@ -92,7 +92,7 @@ func GetSecretValue(ctx context.Context, kube client.Client, ref *xpv1.SecretKey // GetDesiredPassword calculates the desired password from cache/masterPasswordSecretRef func GetDesiredPassword(ctx context.Context, kube client.Client, cr svcapitypes.RDSClusterOrInstance) (desiredPassword string, err error) { - cachedPassword, err := getCachedPassword(ctx, kube, cr) + cachedPassword, err := GetCachedPassword(ctx, kube, cr) if err != nil { return "", errors.Wrap(err, errGetCachedPassword) } @@ -120,7 +120,7 @@ func PasswordUpToDate(ctx context.Context, kube client.Client, cr svcapitypes.RD if err != nil { return false, errors.Wrap(err, errGetCachedRestoreInfo) } - cachedPassword, err := getCachedPassword(ctx, kube, cr) + cachedPassword, err := GetCachedPassword(ctx, kube, cr) if err != nil { return false, errors.Wrap(err, errGetCachedPassword) } @@ -157,7 +157,7 @@ func getCachedRestoreInfo(ctx context.Context, kube client.Client, mg resource.M return state, err } -func getCachedPassword(ctx context.Context, kube client.Client, mg resource.Managed) (pw string, err error) { +func GetCachedPassword(ctx context.Context, kube client.Client, mg resource.Managed) (pw string, err error) { secretKeyRef := &xpv1.SecretKeySelector{ SecretReference: getCachingSecretRef(mg), Key: PasswordCacheKey, diff --git a/pkg/clients/rds/common_test.go b/pkg/clients/rds/common_test.go index df4e6d3be1..e884092a78 100644 --- a/pkg/clients/rds/common_test.go +++ b/pkg/clients/rds/common_test.go @@ -636,7 +636,7 @@ func Test_getCachedPassword(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { - got, err := getCachedPassword(context.Background(), tc.args.kube, tc.args.cr) + got, err := GetCachedPassword(context.Background(), tc.args.kube, tc.args.cr) if diff := cmp.Diff(tc.want.value, got); diff != "" { t.Errorf("\n%s\ngetCachedPassword(...): -want, +got:\n", diff) diff --git a/pkg/clients/rds/dbinstance.go b/pkg/clients/rds/dbinstance.go index bb09d244b4..75a31e3dd7 100644 --- a/pkg/clients/rds/dbinstance.go +++ b/pkg/clients/rds/dbinstance.go @@ -200,3 +200,154 @@ func GenerateRestoreDBInstanceToPointInTimeInput(name string, p *v1alpha1.DBInst } return c } + +// GenerateCreateDBInstanceReadReplicaInput returns a create input. +func GenerateCreateDBInstanceReadReplicaInput(cr *v1alpha1.DBInstance) *svcsdk.CreateDBInstanceReadReplicaInput { + res := &svcsdk.CreateDBInstanceReadReplicaInput{} + + if cr.Spec.ForProvider.AllocatedStorage != nil { + res.SetAllocatedStorage(*cr.Spec.ForProvider.AllocatedStorage) + } + if cr.Spec.ForProvider.AutoMinorVersionUpgrade != nil { + res.SetAutoMinorVersionUpgrade(*cr.Spec.ForProvider.AutoMinorVersionUpgrade) + } + if cr.Spec.ForProvider.AvailabilityZone != nil { + res.SetAvailabilityZone(*cr.Spec.ForProvider.AvailabilityZone) + } + if cr.Spec.ForProvider.CopyTagsToSnapshot != nil { + res.SetCopyTagsToSnapshot(*cr.Spec.ForProvider.CopyTagsToSnapshot) + } + if cr.Spec.ForProvider.CustomIAMInstanceProfile != nil { + res.SetCustomIamInstanceProfile(*cr.Spec.ForProvider.CustomIAMInstanceProfile) + } + if cr.Spec.ForProvider.DBInstanceClass != nil { + res.SetDBInstanceClass(*cr.Spec.ForProvider.DBInstanceClass) + } + if cr.Spec.ForProvider.DBParameterGroupName != nil { + res.SetDBParameterGroupName(*cr.Spec.ForProvider.DBParameterGroupName) + } + if cr.Spec.ForProvider.DBSubnetGroupName != nil { + res.SetDBSubnetGroupName(*cr.Spec.ForProvider.DBSubnetGroupName) + } + if cr.Spec.ForProvider.DedicatedLogVolume != nil { + res.SetDedicatedLogVolume(*cr.Spec.ForProvider.DedicatedLogVolume) + } + if cr.Spec.ForProvider.DeletionProtection != nil { + res.SetDeletionProtection(*cr.Spec.ForProvider.DeletionProtection) + } + if cr.Spec.ForProvider.Domain != nil { + res.SetDomain(*cr.Spec.ForProvider.Domain) + } + if cr.Spec.ForProvider.DomainAuthSecretARN != nil { + res.SetDomainAuthSecretArn(*cr.Spec.ForProvider.DomainAuthSecretARN) + } + if cr.Spec.ForProvider.DomainDNSIPs != nil { + res.SetDomainDnsIps(cr.Spec.ForProvider.DomainDNSIPs) + } + if cr.Spec.ForProvider.DomainFqdn != nil { + res.SetDomainFqdn(*cr.Spec.ForProvider.DomainFqdn) + } + if cr.Spec.ForProvider.DomainIAMRoleName != nil { + res.SetDomainIAMRoleName(*cr.Spec.ForProvider.DomainIAMRoleName) + } + if cr.Spec.ForProvider.DomainOu != nil { + res.SetDomainOu(*cr.Spec.ForProvider.DomainOu) + } + if cr.Spec.ForProvider.EnableCloudwatchLogsExports != nil { + res.SetEnableCloudwatchLogsExports(cr.Spec.ForProvider.EnableCloudwatchLogsExports) + } + if cr.Spec.ForProvider.EnableCustomerOwnedIP != nil { + res.SetEnableCustomerOwnedIp(*cr.Spec.ForProvider.EnableCustomerOwnedIP) + } + if cr.Spec.ForProvider.EnableIAMDatabaseAuthentication != nil { + res.SetEnableIAMDatabaseAuthentication(*cr.Spec.ForProvider.EnableIAMDatabaseAuthentication) + } + if cr.Spec.ForProvider.EnablePerformanceInsights != nil { + res.SetEnablePerformanceInsights(*cr.Spec.ForProvider.EnablePerformanceInsights) + } + if cr.Spec.ForProvider.IOPS != nil { + res.SetIops(*cr.Spec.ForProvider.IOPS) + } + if cr.Spec.ForProvider.KMSKeyID != nil { + res.SetKmsKeyId(*cr.Spec.ForProvider.KMSKeyID) + + } + if cr.Spec.ForProvider.MaxAllocatedStorage != nil { + res.SetMaxAllocatedStorage(*cr.Spec.ForProvider.MaxAllocatedStorage) + } + if cr.Spec.ForProvider.MonitoringInterval != nil { + res.SetMonitoringInterval(*cr.Spec.ForProvider.MonitoringInterval) + } + if cr.Spec.ForProvider.MonitoringRoleARN != nil { + res.SetMonitoringRoleArn(*cr.Spec.ForProvider.MonitoringRoleARN) + } + if cr.Spec.ForProvider.MultiAZ != nil { + res.SetMultiAZ(*cr.Spec.ForProvider.MultiAZ) + } + if cr.Spec.ForProvider.NetworkType != nil { + res.SetNetworkType(*cr.Spec.ForProvider.NetworkType) + } + if cr.Spec.ForProvider.OptionGroupName != nil { + res.SetOptionGroupName(*cr.Spec.ForProvider.OptionGroupName) + } + if cr.Spec.ForProvider.PerformanceInsightsKMSKeyID != nil { + res.SetPerformanceInsightsKMSKeyId(*cr.Spec.ForProvider.PerformanceInsightsKMSKeyID) + } + if cr.Spec.ForProvider.PerformanceInsightsRetentionPeriod != nil { + res.SetPerformanceInsightsRetentionPeriod(*cr.Spec.ForProvider.PerformanceInsightsRetentionPeriod) + } + if cr.Spec.ForProvider.Port != nil { + res.SetPort(*cr.Spec.ForProvider.Port) + } + if cr.Spec.ForProvider.ProcessorFeatures != nil { + var processorFeatures []*svcsdk.ProcessorFeature + for _, pf := range cr.Spec.ForProvider.ProcessorFeatures { + pfeature := &svcsdk.ProcessorFeature{} + if pf.Name != nil { + pfeature.SetName(*pf.Name) + } + if pf.Value != nil { + pfeature.SetValue(*pf.Value) + } + processorFeatures = append(processorFeatures, pfeature) + } + res.SetProcessorFeatures(processorFeatures) + } + if cr.Spec.ForProvider.PubliclyAccessible != nil { + res.SetPubliclyAccessible(*cr.Spec.ForProvider.PubliclyAccessible) + } + if cr.Spec.ForProvider.ReplicateSourceDBClusterID != nil { + res.SetSourceDBClusterIdentifier(*cr.Spec.ForProvider.ReplicateSourceDBClusterID) + } + if cr.Spec.ForProvider.ReplicateSourceDBInstanceID != nil { + res.SetSourceDBInstanceIdentifier(*cr.Spec.ForProvider.ReplicateSourceDBInstanceID) + } + if cr.Spec.ForProvider.StorageThroughput != nil { + res.SetStorageThroughput(*cr.Spec.ForProvider.StorageThroughput) + } + if cr.Spec.ForProvider.StorageType != nil { + res.SetStorageType(*cr.Spec.ForProvider.StorageType) + } + if cr.Spec.ForProvider.Tags != nil { + var tags []*svcsdk.Tag + for _, t := range cr.Spec.ForProvider.Tags { + tag := &svcsdk.Tag{} + if t.Key != nil { + tag.SetKey(*t.Key) + } + if t.Value != nil { + tag.SetValue(*t.Value) + } + tags = append(tags, tag) + } + res.SetTags(tags) + } + if cr.Spec.ForProvider.VPCSecurityGroupIDs != nil { + var vpcSecurityGroupIDs []*string + for _, v := range cr.Spec.ForProvider.VPCSecurityGroupIDs { + vpcSecurityGroupIDs = append(vpcSecurityGroupIDs, &v) + } + res.SetVpcSecurityGroupIds(vpcSecurityGroupIDs) + } + return res +} diff --git a/pkg/clients/rds/fake/fake.go b/pkg/clients/rds/fake/fake.go new file mode 100644 index 0000000000..e15a3d2bce --- /dev/null +++ b/pkg/clients/rds/fake/fake.go @@ -0,0 +1,42 @@ +package fake + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws/request" + svcsdk "github.com/aws/aws-sdk-go/service/rds" + "github.com/aws/aws-sdk-go/service/rds/rdsiface" +) + +// MockRDSClient is a type that implements of some methods for RDSAPI interface +type MockRDSClient struct { + rdsiface.RDSAPI + MockCreateDBInstanceReadReplicaWithContext func( + ctx context.Context, + input *svcsdk.CreateDBInstanceReadReplicaInput, + optFns ...request.Option, + ) (*svcsdk.CreateDBInstanceReadReplicaOutput, error) + MockCreateDBInstanceWithContext func( + ctx context.Context, + input *svcsdk.CreateDBInstanceInput, + optFns ...request.Option, + ) (*svcsdk.CreateDBInstanceOutput, error) +} + +// CreateDBInstanceReadReplicaWithContext mocks CreateDBInstanceReadReplicaWithContext method for aws-sdk client +func (m *MockRDSClient) CreateDBInstanceReadReplicaWithContext( + ctx context.Context, + input *svcsdk.CreateDBInstanceReadReplicaInput, + optFns ...request.Option, +) (*svcsdk.CreateDBInstanceReadReplicaOutput, error) { + return m.MockCreateDBInstanceReadReplicaWithContext(ctx, input, optFns...) +} + +// CreateDBInstanceWithContext mocks CreateDBInstanceWithContext method for aws-sdk client +func (m *MockRDSClient) CreateDBInstanceWithContext( + ctx context.Context, + input *svcsdk.CreateDBInstanceInput, + optFns ...request.Option, +) (*svcsdk.CreateDBInstanceOutput, error) { + return m.MockCreateDBInstanceWithContext(ctx, input, optFns...) +} diff --git a/pkg/clients/s3/bucket.go b/pkg/clients/s3/bucket.go index f0a6955729..5fd8707eb3 100644 --- a/pkg/clients/s3/bucket.go +++ b/pkg/clients/s3/bucket.go @@ -46,6 +46,8 @@ var ( LifecycleNotFoundErrCode = "NoSuchLifecycleConfiguration" // SSENotFoundErrCode is the error code sent by AWS when the SSE config does not exist SSENotFoundErrCode = "ServerSideEncryptionConfigurationNotFoundError" + // ObjectLockConfigurationErrCode is the error code by AWS when Object Lock configuration does not exist for a bucket. + ObjectLockConfigurationErrCode = "ObjectLockConfigurationNotFoundError" // TaggingNotFoundErrCode is the error code sent by AWS when the tagging does not exist TaggingNotFoundErrCode = "NoSuchTagSet" // WebsiteNotFoundErrCode is the error code sent by AWS when the website config does not exist @@ -115,6 +117,9 @@ type BucketClient interface { PutBucketOwnershipControls(ctx context.Context, input *s3.PutBucketOwnershipControlsInput, opts ...func(*s3.Options)) (*s3.PutBucketOwnershipControlsOutput, error) DeleteBucketOwnershipControls(ctx context.Context, input *s3.DeleteBucketOwnershipControlsInput, opts ...func(*s3.Options)) (*s3.DeleteBucketOwnershipControlsOutput, error) + GetObjectLockConfiguration(ctx context.Context, input *s3.GetObjectLockConfigurationInput, opts ...func(*s3.Options)) (*s3.GetObjectLockConfigurationOutput, error) + PutObjectLockConfiguration(ctx context.Context, input *s3.PutObjectLockConfigurationInput, opts ...func(*s3.Options)) (*s3.PutObjectLockConfigurationOutput, error) + BucketPolicyClient } @@ -203,6 +208,11 @@ func WebsiteConfigurationNotFound(err error) bool { return errors.As(err, &awsErr) && awsErr.ErrorCode() == WebsiteNotFoundErrCode } +func ObjectLockConfigurationNotFound(err error) bool { + var awsErr smithy.APIError + return errors.As(err, &awsErr) && awsErr.ErrorCode() == ObjectLockConfigurationErrCode +} + // MethodNotSupported is parses the aws Error and validates if the method is allowed for a request func MethodNotSupported(err error) bool { var awsErr smithy.APIError diff --git a/pkg/clients/s3/fake/bucket.go b/pkg/clients/s3/fake/bucket.go index 373d16caaf..015c0d8352 100644 --- a/pkg/clients/s3/fake/bucket.go +++ b/pkg/clients/s3/fake/bucket.go @@ -86,6 +86,9 @@ type MockBucketClient struct { MockPutBucketOwnershipControls func(ctx context.Context, input *s3.PutBucketOwnershipControlsInput, opts []func(*s3.Options)) (*s3.PutBucketOwnershipControlsOutput, error) MockDeleteBucketOwnershipControls func(ctx context.Context, input *s3.DeleteBucketOwnershipControlsInput, opts []func(*s3.Options)) (*s3.DeleteBucketOwnershipControlsOutput, error) + MockGetObjectLockConfiguration func(ctx context.Context, input *s3.GetObjectLockConfigurationInput, opts []func(*s3.Options)) (*s3.GetObjectLockConfigurationOutput, error) + MockPutObjectLockConfiguration func(ctx context.Context, input *s3.PutObjectLockConfigurationInput, opts []func(*s3.Options)) (*s3.PutObjectLockConfigurationOutput, error) + MockBucketPolicyClient } @@ -293,3 +296,13 @@ func (m MockBucketClient) PutBucketOwnershipControls(ctx context.Context, input func (m MockBucketClient) DeleteBucketOwnershipControls(ctx context.Context, input *s3.DeleteBucketOwnershipControlsInput, opts ...func(*s3.Options)) (*s3.DeleteBucketOwnershipControlsOutput, error) { return m.MockDeleteBucketOwnershipControls(ctx, input, opts) } + +// GetObjectLockConfiguration is the fake method call to invoke the internal mock method +func (m MockBucketClient) GetObjectLockConfiguration(ctx context.Context, input *s3.GetObjectLockConfigurationInput, opts ...func(*s3.Options)) (*s3.GetObjectLockConfigurationOutput, error) { + return m.MockGetObjectLockConfiguration(ctx, input, opts) +} + +// PutObjectLockConfiguration is the fake method call to invoke the internal mock method +func (m MockBucketClient) PutObjectLockConfiguration(ctx context.Context, input *s3.PutObjectLockConfigurationInput, opts ...func(*s3.Options)) (*s3.PutObjectLockConfigurationOutput, error) { + return m.MockPutObjectLockConfiguration(ctx, input, opts) +} diff --git a/pkg/controller/ecs/service/conversions.go b/pkg/controller/ecs/service/conversions.go index 77061826ab..6d2aee0c10 100644 --- a/pkg/controller/ecs/service/conversions.go +++ b/pkg/controller/ecs/service/conversions.go @@ -7,7 +7,7 @@ import ( ) // GenerateServiceCustom returns the current state in the form of *svcapitypes.Service with custom prarameters set -func GenerateServiceCustom(resp *svcsdk.DescribeServicesOutput) *svcapitypes.Service { +func GenerateServiceCustom(resp *svcsdk.DescribeServicesOutput) *svcapitypes.Service { //nolint:gocyclo if len(resp.Services) != 1 { return nil } @@ -42,5 +42,47 @@ func GenerateServiceCustom(resp *svcsdk.DescribeServicesOutput) *svcapitypes.Ser params.CustomServiceParameters.TaskDefinition = out.TaskDefinition } + // Get ServiceConnectConfiguration from last deployment + if len(out.Deployments) > 0 { + current := out.Deployments[0] + if current != nil && current.ServiceConnectConfiguration != nil { + params.ServiceConnectConfiguration = &svcapitypes.ServiceConnectConfiguration{ + Enabled: current.ServiceConnectConfiguration.Enabled, + Namespace: current.ServiceConnectConfiguration.Namespace, + } + + if current.ServiceConnectConfiguration.LogConfiguration != nil { + params.ServiceConnectConfiguration.LogConfiguration = &svcapitypes.LogConfiguration{ + LogDriver: current.ServiceConnectConfiguration.LogConfiguration.LogDriver, + Options: current.ServiceConnectConfiguration.LogConfiguration.Options, + } + + for _, so := range params.ServiceConnectConfiguration.LogConfiguration.SecretOptions { + params.ServiceConnectConfiguration.LogConfiguration.SecretOptions = append(params.ServiceConnectConfiguration.LogConfiguration.SecretOptions, &svcapitypes.Secret{ + Name: so.Name, + ValueFrom: so.ValueFrom, + }) + } + } + + for _, s := range current.ServiceConnectConfiguration.Services { + service := &svcapitypes.ServiceConnectService{ + DiscoveryName: s.DiscoveryName, + IngressPortOverride: s.IngressPortOverride, + PortName: s.PortName, + } + + for _, ca := range s.ClientAliases { + service.ClientAliases = append(service.ClientAliases, &svcapitypes.ServiceConnectClientAlias{ + DNSName: ca.DnsName, + Port: ca.Port, + }) + } + + params.ServiceConnectConfiguration.Services = append(params.ServiceConnectConfiguration.Services, service) + } + } + } + return service } diff --git a/pkg/controller/ecs/service/setup.go b/pkg/controller/ecs/service/setup.go index c105f2f692..98ff437f16 100644 --- a/pkg/controller/ecs/service/setup.go +++ b/pkg/controller/ecs/service/setup.go @@ -253,17 +253,19 @@ func preUpdate(context context.Context, cr *svcapitypes.Service, obj *svcsdk.Upd } func (e *custom) postUpdate(context context.Context, cr *svcapitypes.Service, obj *svcsdk.UpdateServiceOutput, upd managed.ExternalUpdate, err error) (managed.ExternalUpdate, error) { - arn := obj.Service.ServiceArn + if obj != nil && obj.Service != nil { + arn := obj.Service.ServiceArn - if arn != nil { - if len(e.cache.RemoveTags) > 0 { - if _, err := e.client.UntagResourceWithContext(context, &svcsdk.UntagResourceInput{ResourceArn: arn, TagKeys: e.cache.RemoveTags}); err != nil { - return managed.ExternalUpdate{}, errors.Wrap(err, "UntagResource failed") + if arn != nil { + if len(e.cache.RemoveTags) > 0 { + if _, err := e.client.UntagResourceWithContext(context, &svcsdk.UntagResourceInput{ResourceArn: arn, TagKeys: e.cache.RemoveTags}); err != nil { + return managed.ExternalUpdate{}, errors.Wrap(err, "UntagResource failed") + } } - } - if len(e.cache.AddTags) > 0 { - if _, err := e.client.TagResourceWithContext(context, &svcsdk.TagResourceInput{ResourceArn: arn, Tags: e.cache.AddTags}); err != nil { - return managed.ExternalUpdate{}, errors.Wrap(err, "TagResource failed") + if len(e.cache.AddTags) > 0 { + if _, err := e.client.TagResourceWithContext(context, &svcsdk.TagResourceInput{ResourceArn: arn, Tags: e.cache.AddTags}); err != nil { + return managed.ExternalUpdate{}, errors.Wrap(err, "TagResource failed") + } } } } @@ -535,7 +537,7 @@ func generateNetworkConfiguration(cr *svcapitypes.Service) *svcsdk.NetworkConfig networkConfiguration := &svcsdk.NetworkConfiguration{} if cr.Spec.ForProvider.NetworkConfiguration == nil { - return networkConfiguration + return nil } if cr.Spec.ForProvider.NetworkConfiguration.AWSvpcConfiguration != nil { diff --git a/pkg/controller/elbv2/rule/setup.go b/pkg/controller/elbv2/rule/setup.go new file mode 100644 index 0000000000..0296a7c860 --- /dev/null +++ b/pkg/controller/elbv2/rule/setup.go @@ -0,0 +1,181 @@ +// Package rule provides controllers for managing ELBv2 listener rules. +package rule + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + svcsdk "github.com/aws/aws-sdk-go/service/elbv2" + 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" + "github.com/pkg/errors" + ctrl "sigs.k8s.io/controller-runtime" + + svcapitypes "github.com/crossplane-contrib/provider-aws/apis/elbv2/v1alpha1" + "github.com/crossplane-contrib/provider-aws/apis/v1alpha1" + "github.com/crossplane-contrib/provider-aws/pkg/features" + custommanaged "github.com/crossplane-contrib/provider-aws/pkg/utils/reconciler/managed" +) + +// SetupRule adds a controller that reconciles Rule. +func SetupRule(mgr ctrl.Manager, o controller.Options) error { + name := managed.ControllerName(svcapitypes.RuleGroupKind) + + opts := []option{ + func(e *external) { + e.preObserve = preObserve + e.postObserve = postObserve + e.preCreate = preCreate + e.postCreate = postCreate + e.preDelete = preDelete + e.preUpdate = preUpdate + e.isUpToDate = isUpToDate + }, + } + + 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.WithCriticalAnnotationUpdater(custommanaged.NewRetryingCriticalAnnotationUpdater(mgr.GetClient())), + managed.WithTypedExternalConnector(&connector{kube: mgr.GetClient(), opts: opts}), + managed.WithInitializers(), + 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.RuleGroupVersionKind), + reconcilerOpts...) + + return ctrl.NewControllerManagedBy(mgr). + Named(name). + WithOptions(o.ForControllerRuntime()). + WithEventFilter(resource.DesiredStateChanged()). + For(&svcapitypes.Rule{}). + Complete(r) +} + +func preObserve(_ context.Context, cr *svcapitypes.Rule, obj *svcsdk.DescribeRulesInput) error { + obj.RuleArns = append(obj.RuleArns, aws.String(meta.GetExternalName(cr))) + return nil +} + +func postObserve(_ context.Context, cr *svcapitypes.Rule, resp *svcsdk.DescribeRulesOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) { + if err != nil { + return managed.ExternalObservation{}, err + } + + cr.SetConditions(xpv1.Available()) + + if len(resp.Rules) > 0 { + syncRuleToStatus(cr, resp.Rules[0]) + } + + return obs, nil +} + +func syncRuleToStatus(cr *svcapitypes.Rule, rule *svcsdk.Rule) { + if rule.RuleArn == nil { + return + } + + if cr.Status.AtProvider.Rules == nil { + cr.Status.AtProvider.Rules = []*svcapitypes.Rule_SDK{} + } + + for _, existingRule := range cr.Status.AtProvider.Rules { + if existingRule.RuleARN != nil && *existingRule.RuleARN == *rule.RuleArn { + return + } + } + + newRule := &svcapitypes.Rule_SDK{ + RuleARN: rule.RuleArn, + } + + if rule.Priority != nil { + newRule.Priority = rule.Priority + } + if rule.IsDefault != nil { + newRule.IsDefault = rule.IsDefault + } + + cr.Status.AtProvider.Rules = append(cr.Status.AtProvider.Rules, newRule) +} + +func preCreate(_ context.Context, cr *svcapitypes.Rule, obs *svcsdk.CreateRuleInput) error { + obs.ListenerArn = cr.Spec.ForProvider.ListenerARN + obs.Priority = cr.Spec.ForProvider.Priority + + if obs.Conditions != nil { + for _, condition := range obs.Conditions { + if condition.Field == nil || *condition.Field == "" { + condition.Field = inferConditionField(condition) + } + } + } + + return nil +} + +func inferConditionField(condition *svcsdk.RuleCondition) *string { + switch { + case condition.PathPatternConfig != nil: + return aws.String("path-pattern") + case condition.HostHeaderConfig != nil: + return aws.String("host-header") + case condition.HttpHeaderConfig != nil: + return aws.String("http-header") + case condition.HttpRequestMethodConfig != nil: + return aws.String("http-request-method") + case condition.QueryStringConfig != nil: + return aws.String("query-string") + case condition.SourceIpConfig != nil: + return aws.String("source-ip") + default: + return nil + } +} + +func postCreate(_ context.Context, cr *svcapitypes.Rule, resp *svcsdk.CreateRuleOutput, cre managed.ExternalCreation, err error) (managed.ExternalCreation, error) { + if err != nil { + return managed.ExternalCreation{}, err + } + meta.SetExternalName(cr, aws.StringValue(resp.Rules[0].RuleArn)) + return cre, nil +} + +func preDelete(_ context.Context, cr *svcapitypes.Rule, obj *svcsdk.DeleteRuleInput) (bool, error) { + if meta.GetExternalName(cr) == "" { + return true, nil + } + obj.RuleArn = aws.String(meta.GetExternalName(cr)) + return false, nil +} + +func preUpdate(_ context.Context, cr *svcapitypes.Rule, obj *svcsdk.ModifyRuleInput) error { + if meta.GetExternalName(cr) == "" { + return errors.New("rule ARN is not set") + } + obj.RuleArn = aws.String(meta.GetExternalName(cr)) + return nil +} + +func isUpToDate(_ context.Context, _ *svcapitypes.Rule, _ *svcsdk.DescribeRulesOutput) (bool, string, error) { + // TODO: Implement isUpToDate , need to compare actions and conditions correctly + return true, "listener rule is up to date", nil +} diff --git a/pkg/controller/elbv2/rule/zz_controller.go b/pkg/controller/elbv2/rule/zz_controller.go new file mode 100644 index 0000000000..ae2cb55e4b --- /dev/null +++ b/pkg/controller/elbv2/rule/zz_controller.go @@ -0,0 +1,505 @@ +/* +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 rule + +import ( + "context" + + svcapi "github.com/aws/aws-sdk-go/service/elbv2" + svcsdk "github.com/aws/aws-sdk-go/service/elbv2" + svcsdkapi "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/google/go-cmp/cmp" + "github.com/pkg/errors" + "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/elbv2/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 Rule resource" + + errCreateSession = "cannot create a new session" + errCreate = "cannot create Rule in AWS" + errUpdate = "cannot update Rule in AWS" + errDescribe = "failed to describe Rule" + errDelete = "failed to delete Rule" +) + +type connector struct { + kube client.Client + opts []option +} + +func (c *connector) Connect(ctx context.Context, cr *svcapitypes.Rule) (managed.TypedExternalClient[*svcapitypes.Rule], error) { + sess, err := connectaws.GetConfigV1(ctx, c.kube, cr, 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, cr *svcapitypes.Rule) (managed.ExternalObservation, error) { + if meta.GetExternalName(cr) == "" { + return managed.ExternalObservation{ + ResourceExists: false, + }, nil + } + input := GenerateDescribeRulesInput(cr) + if err := e.preObserve(ctx, cr, input); err != nil { + return managed.ExternalObservation{}, errors.Wrap(err, "pre-observe failed") + } + resp, err := e.client.DescribeRulesWithContext(ctx, input) + if err != nil { + return managed.ExternalObservation{ResourceExists: false}, errorutils.Wrap(cpresource.Ignore(IsNotFound, err), errDescribe) + } + resp = e.filterList(cr, resp) + if len(resp.Rules) == 0 { + return managed.ExternalObservation{ResourceExists: false}, nil + } + currentSpec := cr.Spec.ForProvider.DeepCopy() + if err := e.lateInitialize(&cr.Spec.ForProvider, resp); err != nil { + return managed.ExternalObservation{}, errors.Wrap(err, "late-init failed") + } + GenerateRule(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, cr *svcapitypes.Rule) (managed.ExternalCreation, error) { + cr.Status.SetConditions(xpv1.Creating()) + input := GenerateCreateRuleInput(cr) + if err := e.preCreate(ctx, cr, input); err != nil { + return managed.ExternalCreation{}, errors.Wrap(err, "pre-create failed") + } + resp, err := e.client.CreateRuleWithContext(ctx, input) + if err != nil { + return managed.ExternalCreation{}, errorutils.Wrap(err, errCreate) + } + + if resp.Rules != nil { + f0 := []*svcapitypes.Rule_SDK{} + for _, f0iter := range resp.Rules { + f0elem := &svcapitypes.Rule_SDK{} + if f0iter.Actions != nil { + f0elemf0 := []*svcapitypes.Action{} + for _, f0elemf0iter := range f0iter.Actions { + f0elemf0elem := &svcapitypes.Action{} + if f0elemf0iter.AuthenticateCognitoConfig != nil { + f0elemf0elemf0 := &svcapitypes.AuthenticateCognitoActionConfig{} + if f0elemf0iter.AuthenticateCognitoConfig.AuthenticationRequestExtraParams != nil { + f0elemf0elemf0f0 := map[string]*string{} + for f0elemf0elemf0f0key, f0elemf0elemf0f0valiter := range f0elemf0iter.AuthenticateCognitoConfig.AuthenticationRequestExtraParams { + var f0elemf0elemf0f0val string + f0elemf0elemf0f0val = *f0elemf0elemf0f0valiter + f0elemf0elemf0f0[f0elemf0elemf0f0key] = &f0elemf0elemf0f0val + } + f0elemf0elemf0.AuthenticationRequestExtraParams = f0elemf0elemf0f0 + } + if f0elemf0iter.AuthenticateCognitoConfig.OnUnauthenticatedRequest != nil { + f0elemf0elemf0.OnUnauthenticatedRequest = f0elemf0iter.AuthenticateCognitoConfig.OnUnauthenticatedRequest + } + if f0elemf0iter.AuthenticateCognitoConfig.Scope != nil { + f0elemf0elemf0.Scope = f0elemf0iter.AuthenticateCognitoConfig.Scope + } + if f0elemf0iter.AuthenticateCognitoConfig.SessionCookieName != nil { + f0elemf0elemf0.SessionCookieName = f0elemf0iter.AuthenticateCognitoConfig.SessionCookieName + } + if f0elemf0iter.AuthenticateCognitoConfig.SessionTimeout != nil { + f0elemf0elemf0.SessionTimeout = f0elemf0iter.AuthenticateCognitoConfig.SessionTimeout + } + if f0elemf0iter.AuthenticateCognitoConfig.UserPoolArn != nil { + f0elemf0elemf0.UserPoolARN = f0elemf0iter.AuthenticateCognitoConfig.UserPoolArn + } + if f0elemf0iter.AuthenticateCognitoConfig.UserPoolClientId != nil { + f0elemf0elemf0.UserPoolClientID = f0elemf0iter.AuthenticateCognitoConfig.UserPoolClientId + } + if f0elemf0iter.AuthenticateCognitoConfig.UserPoolDomain != nil { + f0elemf0elemf0.UserPoolDomain = f0elemf0iter.AuthenticateCognitoConfig.UserPoolDomain + } + f0elemf0elem.AuthenticateCognitoConfig = f0elemf0elemf0 + } + if f0elemf0iter.AuthenticateOidcConfig != nil { + f0elemf0elemf1 := &svcapitypes.AuthenticateOIDCActionConfig{} + if f0elemf0iter.AuthenticateOidcConfig.AuthenticationRequestExtraParams != nil { + f0elemf0elemf1f0 := map[string]*string{} + for f0elemf0elemf1f0key, f0elemf0elemf1f0valiter := range f0elemf0iter.AuthenticateOidcConfig.AuthenticationRequestExtraParams { + var f0elemf0elemf1f0val string + f0elemf0elemf1f0val = *f0elemf0elemf1f0valiter + f0elemf0elemf1f0[f0elemf0elemf1f0key] = &f0elemf0elemf1f0val + } + f0elemf0elemf1.AuthenticationRequestExtraParams = f0elemf0elemf1f0 + } + if f0elemf0iter.AuthenticateOidcConfig.AuthorizationEndpoint != nil { + f0elemf0elemf1.AuthorizationEndpoint = f0elemf0iter.AuthenticateOidcConfig.AuthorizationEndpoint + } + if f0elemf0iter.AuthenticateOidcConfig.ClientId != nil { + f0elemf0elemf1.ClientID = f0elemf0iter.AuthenticateOidcConfig.ClientId + } + if f0elemf0iter.AuthenticateOidcConfig.ClientSecret != nil { + f0elemf0elemf1.ClientSecret = f0elemf0iter.AuthenticateOidcConfig.ClientSecret + } + if f0elemf0iter.AuthenticateOidcConfig.Issuer != nil { + f0elemf0elemf1.Issuer = f0elemf0iter.AuthenticateOidcConfig.Issuer + } + if f0elemf0iter.AuthenticateOidcConfig.OnUnauthenticatedRequest != nil { + f0elemf0elemf1.OnUnauthenticatedRequest = f0elemf0iter.AuthenticateOidcConfig.OnUnauthenticatedRequest + } + if f0elemf0iter.AuthenticateOidcConfig.Scope != nil { + f0elemf0elemf1.Scope = f0elemf0iter.AuthenticateOidcConfig.Scope + } + if f0elemf0iter.AuthenticateOidcConfig.SessionCookieName != nil { + f0elemf0elemf1.SessionCookieName = f0elemf0iter.AuthenticateOidcConfig.SessionCookieName + } + if f0elemf0iter.AuthenticateOidcConfig.SessionTimeout != nil { + f0elemf0elemf1.SessionTimeout = f0elemf0iter.AuthenticateOidcConfig.SessionTimeout + } + if f0elemf0iter.AuthenticateOidcConfig.TokenEndpoint != nil { + f0elemf0elemf1.TokenEndpoint = f0elemf0iter.AuthenticateOidcConfig.TokenEndpoint + } + if f0elemf0iter.AuthenticateOidcConfig.UseExistingClientSecret != nil { + f0elemf0elemf1.UseExistingClientSecret = f0elemf0iter.AuthenticateOidcConfig.UseExistingClientSecret + } + if f0elemf0iter.AuthenticateOidcConfig.UserInfoEndpoint != nil { + f0elemf0elemf1.UserInfoEndpoint = f0elemf0iter.AuthenticateOidcConfig.UserInfoEndpoint + } + f0elemf0elem.AuthenticateOIDCConfig = f0elemf0elemf1 + } + if f0elemf0iter.FixedResponseConfig != nil { + f0elemf0elemf2 := &svcapitypes.FixedResponseActionConfig{} + if f0elemf0iter.FixedResponseConfig.ContentType != nil { + f0elemf0elemf2.ContentType = f0elemf0iter.FixedResponseConfig.ContentType + } + if f0elemf0iter.FixedResponseConfig.MessageBody != nil { + f0elemf0elemf2.MessageBody = f0elemf0iter.FixedResponseConfig.MessageBody + } + if f0elemf0iter.FixedResponseConfig.StatusCode != nil { + f0elemf0elemf2.StatusCode = f0elemf0iter.FixedResponseConfig.StatusCode + } + f0elemf0elem.FixedResponseConfig = f0elemf0elemf2 + } + if f0elemf0iter.ForwardConfig != nil { + f0elemf0elemf3 := &svcapitypes.ForwardActionConfig{} + if f0elemf0iter.ForwardConfig.TargetGroupStickinessConfig != nil { + f0elemf0elemf3f0 := &svcapitypes.TargetGroupStickinessConfig{} + if f0elemf0iter.ForwardConfig.TargetGroupStickinessConfig.DurationSeconds != nil { + f0elemf0elemf3f0.DurationSeconds = f0elemf0iter.ForwardConfig.TargetGroupStickinessConfig.DurationSeconds + } + if f0elemf0iter.ForwardConfig.TargetGroupStickinessConfig.Enabled != nil { + f0elemf0elemf3f0.Enabled = f0elemf0iter.ForwardConfig.TargetGroupStickinessConfig.Enabled + } + f0elemf0elemf3.TargetGroupStickinessConfig = f0elemf0elemf3f0 + } + if f0elemf0iter.ForwardConfig.TargetGroups != nil { + f0elemf0elemf3f1 := []*svcapitypes.TargetGroupTuple{} + for _, f0elemf0elemf3f1iter := range f0elemf0iter.ForwardConfig.TargetGroups { + f0elemf0elemf3f1elem := &svcapitypes.TargetGroupTuple{} + if f0elemf0elemf3f1iter.TargetGroupArn != nil { + f0elemf0elemf3f1elem.TargetGroupARN = f0elemf0elemf3f1iter.TargetGroupArn + } + if f0elemf0elemf3f1iter.Weight != nil { + f0elemf0elemf3f1elem.Weight = f0elemf0elemf3f1iter.Weight + } + f0elemf0elemf3f1 = append(f0elemf0elemf3f1, f0elemf0elemf3f1elem) + } + f0elemf0elemf3.TargetGroups = f0elemf0elemf3f1 + } + f0elemf0elem.ForwardConfig = f0elemf0elemf3 + } + if f0elemf0iter.Order != nil { + f0elemf0elem.Order = f0elemf0iter.Order + } + if f0elemf0iter.RedirectConfig != nil { + f0elemf0elemf5 := &svcapitypes.RedirectActionConfig{} + if f0elemf0iter.RedirectConfig.Host != nil { + f0elemf0elemf5.Host = f0elemf0iter.RedirectConfig.Host + } + if f0elemf0iter.RedirectConfig.Path != nil { + f0elemf0elemf5.Path = f0elemf0iter.RedirectConfig.Path + } + if f0elemf0iter.RedirectConfig.Port != nil { + f0elemf0elemf5.Port = f0elemf0iter.RedirectConfig.Port + } + if f0elemf0iter.RedirectConfig.Protocol != nil { + f0elemf0elemf5.Protocol = f0elemf0iter.RedirectConfig.Protocol + } + if f0elemf0iter.RedirectConfig.Query != nil { + f0elemf0elemf5.Query = f0elemf0iter.RedirectConfig.Query + } + if f0elemf0iter.RedirectConfig.StatusCode != nil { + f0elemf0elemf5.StatusCode = f0elemf0iter.RedirectConfig.StatusCode + } + f0elemf0elem.RedirectConfig = f0elemf0elemf5 + } + if f0elemf0iter.TargetGroupArn != nil { + f0elemf0elem.TargetGroupARN = f0elemf0iter.TargetGroupArn + } + if f0elemf0iter.Type != nil { + f0elemf0elem.Type = f0elemf0iter.Type + } + f0elemf0 = append(f0elemf0, f0elemf0elem) + } + f0elem.Actions = f0elemf0 + } + if f0iter.Conditions != nil { + f0elemf1 := []*svcapitypes.RuleCondition{} + for _, f0elemf1iter := range f0iter.Conditions { + f0elemf1elem := &svcapitypes.RuleCondition{} + if f0elemf1iter.Field != nil { + f0elemf1elem.Field = f0elemf1iter.Field + } + if f0elemf1iter.HostHeaderConfig != nil { + f0elemf1elemf1 := &svcapitypes.HostHeaderConditionConfig{} + if f0elemf1iter.HostHeaderConfig.Values != nil { + f0elemf1elemf1f0 := []*string{} + for _, f0elemf1elemf1f0iter := range f0elemf1iter.HostHeaderConfig.Values { + var f0elemf1elemf1f0elem string + f0elemf1elemf1f0elem = *f0elemf1elemf1f0iter + f0elemf1elemf1f0 = append(f0elemf1elemf1f0, &f0elemf1elemf1f0elem) + } + f0elemf1elemf1.Values = f0elemf1elemf1f0 + } + f0elemf1elem.HostHeaderConfig = f0elemf1elemf1 + } + if f0elemf1iter.HttpHeaderConfig != nil { + f0elemf1elemf2 := &svcapitypes.HTTPHeaderConditionConfig{} + if f0elemf1iter.HttpHeaderConfig.HttpHeaderName != nil { + f0elemf1elemf2.HTTPHeaderName = f0elemf1iter.HttpHeaderConfig.HttpHeaderName + } + if f0elemf1iter.HttpHeaderConfig.Values != nil { + f0elemf1elemf2f1 := []*string{} + for _, f0elemf1elemf2f1iter := range f0elemf1iter.HttpHeaderConfig.Values { + var f0elemf1elemf2f1elem string + f0elemf1elemf2f1elem = *f0elemf1elemf2f1iter + f0elemf1elemf2f1 = append(f0elemf1elemf2f1, &f0elemf1elemf2f1elem) + } + f0elemf1elemf2.Values = f0elemf1elemf2f1 + } + f0elemf1elem.HTTPHeaderConfig = f0elemf1elemf2 + } + if f0elemf1iter.HttpRequestMethodConfig != nil { + f0elemf1elemf3 := &svcapitypes.HTTPRequestMethodConditionConfig{} + if f0elemf1iter.HttpRequestMethodConfig.Values != nil { + f0elemf1elemf3f0 := []*string{} + for _, f0elemf1elemf3f0iter := range f0elemf1iter.HttpRequestMethodConfig.Values { + var f0elemf1elemf3f0elem string + f0elemf1elemf3f0elem = *f0elemf1elemf3f0iter + f0elemf1elemf3f0 = append(f0elemf1elemf3f0, &f0elemf1elemf3f0elem) + } + f0elemf1elemf3.Values = f0elemf1elemf3f0 + } + f0elemf1elem.HTTPRequestMethodConfig = f0elemf1elemf3 + } + if f0elemf1iter.PathPatternConfig != nil { + f0elemf1elemf4 := &svcapitypes.PathPatternConditionConfig{} + if f0elemf1iter.PathPatternConfig.Values != nil { + f0elemf1elemf4f0 := []*string{} + for _, f0elemf1elemf4f0iter := range f0elemf1iter.PathPatternConfig.Values { + var f0elemf1elemf4f0elem string + f0elemf1elemf4f0elem = *f0elemf1elemf4f0iter + f0elemf1elemf4f0 = append(f0elemf1elemf4f0, &f0elemf1elemf4f0elem) + } + f0elemf1elemf4.Values = f0elemf1elemf4f0 + } + f0elemf1elem.PathPatternConfig = f0elemf1elemf4 + } + if f0elemf1iter.QueryStringConfig != nil { + f0elemf1elemf5 := &svcapitypes.QueryStringConditionConfig{} + if f0elemf1iter.QueryStringConfig.Values != nil { + f0elemf1elemf5f0 := []*svcapitypes.QueryStringKeyValuePair{} + for _, f0elemf1elemf5f0iter := range f0elemf1iter.QueryStringConfig.Values { + f0elemf1elemf5f0elem := &svcapitypes.QueryStringKeyValuePair{} + if f0elemf1elemf5f0iter.Key != nil { + f0elemf1elemf5f0elem.Key = f0elemf1elemf5f0iter.Key + } + if f0elemf1elemf5f0iter.Value != nil { + f0elemf1elemf5f0elem.Value = f0elemf1elemf5f0iter.Value + } + f0elemf1elemf5f0 = append(f0elemf1elemf5f0, f0elemf1elemf5f0elem) + } + f0elemf1elemf5.Values = f0elemf1elemf5f0 + } + f0elemf1elem.QueryStringConfig = f0elemf1elemf5 + } + if f0elemf1iter.SourceIpConfig != nil { + f0elemf1elemf6 := &svcapitypes.SourceIPConditionConfig{} + if f0elemf1iter.SourceIpConfig.Values != nil { + f0elemf1elemf6f0 := []*string{} + for _, f0elemf1elemf6f0iter := range f0elemf1iter.SourceIpConfig.Values { + var f0elemf1elemf6f0elem string + f0elemf1elemf6f0elem = *f0elemf1elemf6f0iter + f0elemf1elemf6f0 = append(f0elemf1elemf6f0, &f0elemf1elemf6f0elem) + } + f0elemf1elemf6.Values = f0elemf1elemf6f0 + } + f0elemf1elem.SourceIPConfig = f0elemf1elemf6 + } + if f0elemf1iter.Values != nil { + f0elemf1elemf7 := []*string{} + for _, f0elemf1elemf7iter := range f0elemf1iter.Values { + var f0elemf1elemf7elem string + f0elemf1elemf7elem = *f0elemf1elemf7iter + f0elemf1elemf7 = append(f0elemf1elemf7, &f0elemf1elemf7elem) + } + f0elemf1elem.Values = f0elemf1elemf7 + } + f0elemf1 = append(f0elemf1, f0elemf1elem) + } + f0elem.Conditions = f0elemf1 + } + if f0iter.IsDefault != nil { + f0elem.IsDefault = f0iter.IsDefault + } + if f0iter.Priority != nil { + f0elem.Priority = f0iter.Priority + } + if f0iter.RuleArn != nil { + f0elem.RuleARN = f0iter.RuleArn + } + f0 = append(f0, f0elem) + } + cr.Status.AtProvider.Rules = f0 + } else { + cr.Status.AtProvider.Rules = nil + } + + return e.postCreate(ctx, cr, resp, managed.ExternalCreation{}, err) +} + +func (e *external) Update(ctx context.Context, cr *svcapitypes.Rule) (managed.ExternalUpdate, error) { + input := GenerateModifyRuleInput(cr) + if err := e.preUpdate(ctx, cr, input); err != nil { + return managed.ExternalUpdate{}, errors.Wrap(err, "pre-update failed") + } + resp, err := e.client.ModifyRuleWithContext(ctx, input) + return e.postUpdate(ctx, cr, resp, managed.ExternalUpdate{}, errorutils.Wrap(err, errUpdate)) +} + +func (e *external) Delete(ctx context.Context, cr *svcapitypes.Rule) (managed.ExternalDelete, error) { + cr.Status.SetConditions(xpv1.Deleting()) + input := GenerateDeleteRuleInput(cr) + ignore, err := e.preDelete(ctx, cr, input) + if err != nil { + return managed.ExternalDelete{}, errors.Wrap(err, "pre-delete failed") + } + if ignore { + return managed.ExternalDelete{}, nil + } + resp, err := e.client.DeleteRuleWithContext(ctx, input) + return e.postDelete(ctx, cr, resp, errorutils.Wrap(cpresource.Ignore(IsNotFound, err), errDelete)) +} + +func (e *external) Disconnect(ctx context.Context) error { + // Unimplemented, required by newer versions of crossplane-runtime + return nil +} + +type option func(*external) + +func newExternal(kube client.Client, client svcsdkapi.ELBV2API, opts []option) *external { + e := &external{ + kube: kube, + client: client, + preObserve: nopPreObserve, + postObserve: nopPostObserve, + lateInitialize: nopLateInitialize, + isUpToDate: alwaysUpToDate, + filterList: nopFilterList, + preCreate: nopPreCreate, + postCreate: nopPostCreate, + preDelete: nopPreDelete, + postDelete: nopPostDelete, + preUpdate: nopPreUpdate, + postUpdate: nopPostUpdate, + } + for _, f := range opts { + f(e) + } + return e +} + +type external struct { + kube client.Client + client svcsdkapi.ELBV2API + preObserve func(context.Context, *svcapitypes.Rule, *svcsdk.DescribeRulesInput) error + postObserve func(context.Context, *svcapitypes.Rule, *svcsdk.DescribeRulesOutput, managed.ExternalObservation, error) (managed.ExternalObservation, error) + filterList func(*svcapitypes.Rule, *svcsdk.DescribeRulesOutput) *svcsdk.DescribeRulesOutput + lateInitialize func(*svcapitypes.RuleParameters, *svcsdk.DescribeRulesOutput) error + isUpToDate func(context.Context, *svcapitypes.Rule, *svcsdk.DescribeRulesOutput) (bool, string, error) + preCreate func(context.Context, *svcapitypes.Rule, *svcsdk.CreateRuleInput) error + postCreate func(context.Context, *svcapitypes.Rule, *svcsdk.CreateRuleOutput, managed.ExternalCreation, error) (managed.ExternalCreation, error) + preDelete func(context.Context, *svcapitypes.Rule, *svcsdk.DeleteRuleInput) (bool, error) + postDelete func(context.Context, *svcapitypes.Rule, *svcsdk.DeleteRuleOutput, error) (managed.ExternalDelete, error) + preUpdate func(context.Context, *svcapitypes.Rule, *svcsdk.ModifyRuleInput) error + postUpdate func(context.Context, *svcapitypes.Rule, *svcsdk.ModifyRuleOutput, managed.ExternalUpdate, error) (managed.ExternalUpdate, error) +} + +func nopPreObserve(context.Context, *svcapitypes.Rule, *svcsdk.DescribeRulesInput) error { + return nil +} +func nopPostObserve(_ context.Context, _ *svcapitypes.Rule, _ *svcsdk.DescribeRulesOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) { + return obs, err +} +func nopFilterList(_ *svcapitypes.Rule, list *svcsdk.DescribeRulesOutput) *svcsdk.DescribeRulesOutput { + return list +} + +func nopLateInitialize(*svcapitypes.RuleParameters, *svcsdk.DescribeRulesOutput) error { + return nil +} +func alwaysUpToDate(context.Context, *svcapitypes.Rule, *svcsdk.DescribeRulesOutput) (bool, string, error) { + return true, "", nil +} + +func nopPreCreate(context.Context, *svcapitypes.Rule, *svcsdk.CreateRuleInput) error { + return nil +} +func nopPostCreate(_ context.Context, _ *svcapitypes.Rule, _ *svcsdk.CreateRuleOutput, cre managed.ExternalCreation, err error) (managed.ExternalCreation, error) { + return cre, err +} +func nopPreDelete(context.Context, *svcapitypes.Rule, *svcsdk.DeleteRuleInput) (bool, error) { + return false, nil +} +func nopPostDelete(_ context.Context, _ *svcapitypes.Rule, _ *svcsdk.DeleteRuleOutput, err error) (managed.ExternalDelete, error) { + return managed.ExternalDelete{}, err +} +func nopPreUpdate(context.Context, *svcapitypes.Rule, *svcsdk.ModifyRuleInput) error { + return nil +} +func nopPostUpdate(_ context.Context, _ *svcapitypes.Rule, _ *svcsdk.ModifyRuleOutput, upd managed.ExternalUpdate, err error) (managed.ExternalUpdate, error) { + return upd, err +} diff --git a/pkg/controller/elbv2/rule/zz_conversions.go b/pkg/controller/elbv2/rule/zz_conversions.go new file mode 100644 index 0000000000..c48eb27aed --- /dev/null +++ b/pkg/controller/elbv2/rule/zz_conversions.go @@ -0,0 +1,898 @@ +/* +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 rule + +import ( + "github.com/aws/aws-sdk-go/aws/awserr" + svcsdk "github.com/aws/aws-sdk-go/service/elbv2" + + svcapitypes "github.com/crossplane-contrib/provider-aws/apis/elbv2/v1alpha1" +) + +// NOTE(muvaf): We return pointers in case the function needs to start with an +// empty object, hence need to return a new pointer. + +// GenerateDescribeRulesInput returns input for read +// operation. +func GenerateDescribeRulesInput(cr *svcapitypes.Rule) *svcsdk.DescribeRulesInput { + res := &svcsdk.DescribeRulesInput{} + + return res +} + +// GenerateRule returns the current state in the form of *svcapitypes.Rule. +func GenerateRule(resp *svcsdk.DescribeRulesOutput) *svcapitypes.Rule { + cr := &svcapitypes.Rule{} + + found := false + for _, elem := range resp.Rules { + if elem.Actions != nil { + f0 := []*svcapitypes.Action{} + for _, f0iter := range elem.Actions { + f0elem := &svcapitypes.Action{} + if f0iter.AuthenticateCognitoConfig != nil { + f0elemf0 := &svcapitypes.AuthenticateCognitoActionConfig{} + if f0iter.AuthenticateCognitoConfig.AuthenticationRequestExtraParams != nil { + f0elemf0f0 := map[string]*string{} + for f0elemf0f0key, f0elemf0f0valiter := range f0iter.AuthenticateCognitoConfig.AuthenticationRequestExtraParams { + var f0elemf0f0val string + f0elemf0f0val = *f0elemf0f0valiter + f0elemf0f0[f0elemf0f0key] = &f0elemf0f0val + } + f0elemf0.AuthenticationRequestExtraParams = f0elemf0f0 + } + if f0iter.AuthenticateCognitoConfig.OnUnauthenticatedRequest != nil { + f0elemf0.OnUnauthenticatedRequest = f0iter.AuthenticateCognitoConfig.OnUnauthenticatedRequest + } + if f0iter.AuthenticateCognitoConfig.Scope != nil { + f0elemf0.Scope = f0iter.AuthenticateCognitoConfig.Scope + } + if f0iter.AuthenticateCognitoConfig.SessionCookieName != nil { + f0elemf0.SessionCookieName = f0iter.AuthenticateCognitoConfig.SessionCookieName + } + if f0iter.AuthenticateCognitoConfig.SessionTimeout != nil { + f0elemf0.SessionTimeout = f0iter.AuthenticateCognitoConfig.SessionTimeout + } + if f0iter.AuthenticateCognitoConfig.UserPoolArn != nil { + f0elemf0.UserPoolARN = f0iter.AuthenticateCognitoConfig.UserPoolArn + } + if f0iter.AuthenticateCognitoConfig.UserPoolClientId != nil { + f0elemf0.UserPoolClientID = f0iter.AuthenticateCognitoConfig.UserPoolClientId + } + if f0iter.AuthenticateCognitoConfig.UserPoolDomain != nil { + f0elemf0.UserPoolDomain = f0iter.AuthenticateCognitoConfig.UserPoolDomain + } + f0elem.AuthenticateCognitoConfig = f0elemf0 + } + if f0iter.AuthenticateOidcConfig != nil { + f0elemf1 := &svcapitypes.AuthenticateOIDCActionConfig{} + if f0iter.AuthenticateOidcConfig.AuthenticationRequestExtraParams != nil { + f0elemf1f0 := map[string]*string{} + for f0elemf1f0key, f0elemf1f0valiter := range f0iter.AuthenticateOidcConfig.AuthenticationRequestExtraParams { + var f0elemf1f0val string + f0elemf1f0val = *f0elemf1f0valiter + f0elemf1f0[f0elemf1f0key] = &f0elemf1f0val + } + f0elemf1.AuthenticationRequestExtraParams = f0elemf1f0 + } + if f0iter.AuthenticateOidcConfig.AuthorizationEndpoint != nil { + f0elemf1.AuthorizationEndpoint = f0iter.AuthenticateOidcConfig.AuthorizationEndpoint + } + if f0iter.AuthenticateOidcConfig.ClientId != nil { + f0elemf1.ClientID = f0iter.AuthenticateOidcConfig.ClientId + } + if f0iter.AuthenticateOidcConfig.ClientSecret != nil { + f0elemf1.ClientSecret = f0iter.AuthenticateOidcConfig.ClientSecret + } + if f0iter.AuthenticateOidcConfig.Issuer != nil { + f0elemf1.Issuer = f0iter.AuthenticateOidcConfig.Issuer + } + if f0iter.AuthenticateOidcConfig.OnUnauthenticatedRequest != nil { + f0elemf1.OnUnauthenticatedRequest = f0iter.AuthenticateOidcConfig.OnUnauthenticatedRequest + } + if f0iter.AuthenticateOidcConfig.Scope != nil { + f0elemf1.Scope = f0iter.AuthenticateOidcConfig.Scope + } + if f0iter.AuthenticateOidcConfig.SessionCookieName != nil { + f0elemf1.SessionCookieName = f0iter.AuthenticateOidcConfig.SessionCookieName + } + if f0iter.AuthenticateOidcConfig.SessionTimeout != nil { + f0elemf1.SessionTimeout = f0iter.AuthenticateOidcConfig.SessionTimeout + } + if f0iter.AuthenticateOidcConfig.TokenEndpoint != nil { + f0elemf1.TokenEndpoint = f0iter.AuthenticateOidcConfig.TokenEndpoint + } + if f0iter.AuthenticateOidcConfig.UseExistingClientSecret != nil { + f0elemf1.UseExistingClientSecret = f0iter.AuthenticateOidcConfig.UseExistingClientSecret + } + if f0iter.AuthenticateOidcConfig.UserInfoEndpoint != nil { + f0elemf1.UserInfoEndpoint = f0iter.AuthenticateOidcConfig.UserInfoEndpoint + } + f0elem.AuthenticateOIDCConfig = f0elemf1 + } + if f0iter.FixedResponseConfig != nil { + f0elemf2 := &svcapitypes.FixedResponseActionConfig{} + if f0iter.FixedResponseConfig.ContentType != nil { + f0elemf2.ContentType = f0iter.FixedResponseConfig.ContentType + } + if f0iter.FixedResponseConfig.MessageBody != nil { + f0elemf2.MessageBody = f0iter.FixedResponseConfig.MessageBody + } + if f0iter.FixedResponseConfig.StatusCode != nil { + f0elemf2.StatusCode = f0iter.FixedResponseConfig.StatusCode + } + f0elem.FixedResponseConfig = f0elemf2 + } + if f0iter.ForwardConfig != nil { + f0elemf3 := &svcapitypes.ForwardActionConfig{} + if f0iter.ForwardConfig.TargetGroupStickinessConfig != nil { + f0elemf3f0 := &svcapitypes.TargetGroupStickinessConfig{} + if f0iter.ForwardConfig.TargetGroupStickinessConfig.DurationSeconds != nil { + f0elemf3f0.DurationSeconds = f0iter.ForwardConfig.TargetGroupStickinessConfig.DurationSeconds + } + if f0iter.ForwardConfig.TargetGroupStickinessConfig.Enabled != nil { + f0elemf3f0.Enabled = f0iter.ForwardConfig.TargetGroupStickinessConfig.Enabled + } + f0elemf3.TargetGroupStickinessConfig = f0elemf3f0 + } + if f0iter.ForwardConfig.TargetGroups != nil { + f0elemf3f1 := []*svcapitypes.TargetGroupTuple{} + for _, f0elemf3f1iter := range f0iter.ForwardConfig.TargetGroups { + f0elemf3f1elem := &svcapitypes.TargetGroupTuple{} + if f0elemf3f1iter.TargetGroupArn != nil { + f0elemf3f1elem.TargetGroupARN = f0elemf3f1iter.TargetGroupArn + } + if f0elemf3f1iter.Weight != nil { + f0elemf3f1elem.Weight = f0elemf3f1iter.Weight + } + f0elemf3f1 = append(f0elemf3f1, f0elemf3f1elem) + } + f0elemf3.TargetGroups = f0elemf3f1 + } + f0elem.ForwardConfig = f0elemf3 + } + if f0iter.Order != nil { + f0elem.Order = f0iter.Order + } + if f0iter.RedirectConfig != nil { + f0elemf5 := &svcapitypes.RedirectActionConfig{} + if f0iter.RedirectConfig.Host != nil { + f0elemf5.Host = f0iter.RedirectConfig.Host + } + if f0iter.RedirectConfig.Path != nil { + f0elemf5.Path = f0iter.RedirectConfig.Path + } + if f0iter.RedirectConfig.Port != nil { + f0elemf5.Port = f0iter.RedirectConfig.Port + } + if f0iter.RedirectConfig.Protocol != nil { + f0elemf5.Protocol = f0iter.RedirectConfig.Protocol + } + if f0iter.RedirectConfig.Query != nil { + f0elemf5.Query = f0iter.RedirectConfig.Query + } + if f0iter.RedirectConfig.StatusCode != nil { + f0elemf5.StatusCode = f0iter.RedirectConfig.StatusCode + } + f0elem.RedirectConfig = f0elemf5 + } + if f0iter.TargetGroupArn != nil { + f0elem.TargetGroupARN = f0iter.TargetGroupArn + } + if f0iter.Type != nil { + f0elem.Type = f0iter.Type + } + f0 = append(f0, f0elem) + } + cr.Spec.ForProvider.Actions = f0 + } else { + cr.Spec.ForProvider.Actions = nil + } + if elem.Conditions != nil { + f1 := []*svcapitypes.RuleCondition{} + for _, f1iter := range elem.Conditions { + f1elem := &svcapitypes.RuleCondition{} + if f1iter.Field != nil { + f1elem.Field = f1iter.Field + } + if f1iter.HostHeaderConfig != nil { + f1elemf1 := &svcapitypes.HostHeaderConditionConfig{} + if f1iter.HostHeaderConfig.Values != nil { + f1elemf1f0 := []*string{} + for _, f1elemf1f0iter := range f1iter.HostHeaderConfig.Values { + var f1elemf1f0elem string + f1elemf1f0elem = *f1elemf1f0iter + f1elemf1f0 = append(f1elemf1f0, &f1elemf1f0elem) + } + f1elemf1.Values = f1elemf1f0 + } + f1elem.HostHeaderConfig = f1elemf1 + } + if f1iter.HttpHeaderConfig != nil { + f1elemf2 := &svcapitypes.HTTPHeaderConditionConfig{} + if f1iter.HttpHeaderConfig.HttpHeaderName != nil { + f1elemf2.HTTPHeaderName = f1iter.HttpHeaderConfig.HttpHeaderName + } + if f1iter.HttpHeaderConfig.Values != nil { + f1elemf2f1 := []*string{} + for _, f1elemf2f1iter := range f1iter.HttpHeaderConfig.Values { + var f1elemf2f1elem string + f1elemf2f1elem = *f1elemf2f1iter + f1elemf2f1 = append(f1elemf2f1, &f1elemf2f1elem) + } + f1elemf2.Values = f1elemf2f1 + } + f1elem.HTTPHeaderConfig = f1elemf2 + } + if f1iter.HttpRequestMethodConfig != nil { + f1elemf3 := &svcapitypes.HTTPRequestMethodConditionConfig{} + if f1iter.HttpRequestMethodConfig.Values != nil { + f1elemf3f0 := []*string{} + for _, f1elemf3f0iter := range f1iter.HttpRequestMethodConfig.Values { + var f1elemf3f0elem string + f1elemf3f0elem = *f1elemf3f0iter + f1elemf3f0 = append(f1elemf3f0, &f1elemf3f0elem) + } + f1elemf3.Values = f1elemf3f0 + } + f1elem.HTTPRequestMethodConfig = f1elemf3 + } + if f1iter.PathPatternConfig != nil { + f1elemf4 := &svcapitypes.PathPatternConditionConfig{} + if f1iter.PathPatternConfig.Values != nil { + f1elemf4f0 := []*string{} + for _, f1elemf4f0iter := range f1iter.PathPatternConfig.Values { + var f1elemf4f0elem string + f1elemf4f0elem = *f1elemf4f0iter + f1elemf4f0 = append(f1elemf4f0, &f1elemf4f0elem) + } + f1elemf4.Values = f1elemf4f0 + } + f1elem.PathPatternConfig = f1elemf4 + } + if f1iter.QueryStringConfig != nil { + f1elemf5 := &svcapitypes.QueryStringConditionConfig{} + if f1iter.QueryStringConfig.Values != nil { + f1elemf5f0 := []*svcapitypes.QueryStringKeyValuePair{} + for _, f1elemf5f0iter := range f1iter.QueryStringConfig.Values { + f1elemf5f0elem := &svcapitypes.QueryStringKeyValuePair{} + if f1elemf5f0iter.Key != nil { + f1elemf5f0elem.Key = f1elemf5f0iter.Key + } + if f1elemf5f0iter.Value != nil { + f1elemf5f0elem.Value = f1elemf5f0iter.Value + } + f1elemf5f0 = append(f1elemf5f0, f1elemf5f0elem) + } + f1elemf5.Values = f1elemf5f0 + } + f1elem.QueryStringConfig = f1elemf5 + } + if f1iter.SourceIpConfig != nil { + f1elemf6 := &svcapitypes.SourceIPConditionConfig{} + if f1iter.SourceIpConfig.Values != nil { + f1elemf6f0 := []*string{} + for _, f1elemf6f0iter := range f1iter.SourceIpConfig.Values { + var f1elemf6f0elem string + f1elemf6f0elem = *f1elemf6f0iter + f1elemf6f0 = append(f1elemf6f0, &f1elemf6f0elem) + } + f1elemf6.Values = f1elemf6f0 + } + f1elem.SourceIPConfig = f1elemf6 + } + if f1iter.Values != nil { + f1elemf7 := []*string{} + for _, f1elemf7iter := range f1iter.Values { + var f1elemf7elem string + f1elemf7elem = *f1elemf7iter + f1elemf7 = append(f1elemf7, &f1elemf7elem) + } + f1elem.Values = f1elemf7 + } + f1 = append(f1, f1elem) + } + cr.Spec.ForProvider.Conditions = f1 + } else { + cr.Spec.ForProvider.Conditions = nil + } + found = true + break + } + if !found { + _ = found + } + + return cr +} + +// GenerateCreateRuleInput returns a create input. +func GenerateCreateRuleInput(cr *svcapitypes.Rule) *svcsdk.CreateRuleInput { + res := &svcsdk.CreateRuleInput{} + + if cr.Spec.ForProvider.Actions != nil { + f0 := []*svcsdk.Action{} + for _, f0iter := range cr.Spec.ForProvider.Actions { + f0elem := &svcsdk.Action{} + if f0iter.AuthenticateCognitoConfig != nil { + f0elemf0 := &svcsdk.AuthenticateCognitoActionConfig{} + if f0iter.AuthenticateCognitoConfig.AuthenticationRequestExtraParams != nil { + f0elemf0f0 := map[string]*string{} + for f0elemf0f0key, f0elemf0f0valiter := range f0iter.AuthenticateCognitoConfig.AuthenticationRequestExtraParams { + var f0elemf0f0val string + f0elemf0f0val = *f0elemf0f0valiter + f0elemf0f0[f0elemf0f0key] = &f0elemf0f0val + } + f0elemf0.SetAuthenticationRequestExtraParams(f0elemf0f0) + } + if f0iter.AuthenticateCognitoConfig.OnUnauthenticatedRequest != nil { + f0elemf0.SetOnUnauthenticatedRequest(*f0iter.AuthenticateCognitoConfig.OnUnauthenticatedRequest) + } + if f0iter.AuthenticateCognitoConfig.Scope != nil { + f0elemf0.SetScope(*f0iter.AuthenticateCognitoConfig.Scope) + } + if f0iter.AuthenticateCognitoConfig.SessionCookieName != nil { + f0elemf0.SetSessionCookieName(*f0iter.AuthenticateCognitoConfig.SessionCookieName) + } + if f0iter.AuthenticateCognitoConfig.SessionTimeout != nil { + f0elemf0.SetSessionTimeout(*f0iter.AuthenticateCognitoConfig.SessionTimeout) + } + if f0iter.AuthenticateCognitoConfig.UserPoolARN != nil { + f0elemf0.SetUserPoolArn(*f0iter.AuthenticateCognitoConfig.UserPoolARN) + } + if f0iter.AuthenticateCognitoConfig.UserPoolClientID != nil { + f0elemf0.SetUserPoolClientId(*f0iter.AuthenticateCognitoConfig.UserPoolClientID) + } + if f0iter.AuthenticateCognitoConfig.UserPoolDomain != nil { + f0elemf0.SetUserPoolDomain(*f0iter.AuthenticateCognitoConfig.UserPoolDomain) + } + f0elem.SetAuthenticateCognitoConfig(f0elemf0) + } + if f0iter.AuthenticateOIDCConfig != nil { + f0elemf1 := &svcsdk.AuthenticateOidcActionConfig{} + if f0iter.AuthenticateOIDCConfig.AuthenticationRequestExtraParams != nil { + f0elemf1f0 := map[string]*string{} + for f0elemf1f0key, f0elemf1f0valiter := range f0iter.AuthenticateOIDCConfig.AuthenticationRequestExtraParams { + var f0elemf1f0val string + f0elemf1f0val = *f0elemf1f0valiter + f0elemf1f0[f0elemf1f0key] = &f0elemf1f0val + } + f0elemf1.SetAuthenticationRequestExtraParams(f0elemf1f0) + } + if f0iter.AuthenticateOIDCConfig.AuthorizationEndpoint != nil { + f0elemf1.SetAuthorizationEndpoint(*f0iter.AuthenticateOIDCConfig.AuthorizationEndpoint) + } + if f0iter.AuthenticateOIDCConfig.ClientID != nil { + f0elemf1.SetClientId(*f0iter.AuthenticateOIDCConfig.ClientID) + } + if f0iter.AuthenticateOIDCConfig.ClientSecret != nil { + f0elemf1.SetClientSecret(*f0iter.AuthenticateOIDCConfig.ClientSecret) + } + if f0iter.AuthenticateOIDCConfig.Issuer != nil { + f0elemf1.SetIssuer(*f0iter.AuthenticateOIDCConfig.Issuer) + } + if f0iter.AuthenticateOIDCConfig.OnUnauthenticatedRequest != nil { + f0elemf1.SetOnUnauthenticatedRequest(*f0iter.AuthenticateOIDCConfig.OnUnauthenticatedRequest) + } + if f0iter.AuthenticateOIDCConfig.Scope != nil { + f0elemf1.SetScope(*f0iter.AuthenticateOIDCConfig.Scope) + } + if f0iter.AuthenticateOIDCConfig.SessionCookieName != nil { + f0elemf1.SetSessionCookieName(*f0iter.AuthenticateOIDCConfig.SessionCookieName) + } + if f0iter.AuthenticateOIDCConfig.SessionTimeout != nil { + f0elemf1.SetSessionTimeout(*f0iter.AuthenticateOIDCConfig.SessionTimeout) + } + if f0iter.AuthenticateOIDCConfig.TokenEndpoint != nil { + f0elemf1.SetTokenEndpoint(*f0iter.AuthenticateOIDCConfig.TokenEndpoint) + } + if f0iter.AuthenticateOIDCConfig.UseExistingClientSecret != nil { + f0elemf1.SetUseExistingClientSecret(*f0iter.AuthenticateOIDCConfig.UseExistingClientSecret) + } + if f0iter.AuthenticateOIDCConfig.UserInfoEndpoint != nil { + f0elemf1.SetUserInfoEndpoint(*f0iter.AuthenticateOIDCConfig.UserInfoEndpoint) + } + f0elem.SetAuthenticateOidcConfig(f0elemf1) + } + if f0iter.FixedResponseConfig != nil { + f0elemf2 := &svcsdk.FixedResponseActionConfig{} + if f0iter.FixedResponseConfig.ContentType != nil { + f0elemf2.SetContentType(*f0iter.FixedResponseConfig.ContentType) + } + if f0iter.FixedResponseConfig.MessageBody != nil { + f0elemf2.SetMessageBody(*f0iter.FixedResponseConfig.MessageBody) + } + if f0iter.FixedResponseConfig.StatusCode != nil { + f0elemf2.SetStatusCode(*f0iter.FixedResponseConfig.StatusCode) + } + f0elem.SetFixedResponseConfig(f0elemf2) + } + if f0iter.ForwardConfig != nil { + f0elemf3 := &svcsdk.ForwardActionConfig{} + if f0iter.ForwardConfig.TargetGroupStickinessConfig != nil { + f0elemf3f0 := &svcsdk.TargetGroupStickinessConfig{} + if f0iter.ForwardConfig.TargetGroupStickinessConfig.DurationSeconds != nil { + f0elemf3f0.SetDurationSeconds(*f0iter.ForwardConfig.TargetGroupStickinessConfig.DurationSeconds) + } + if f0iter.ForwardConfig.TargetGroupStickinessConfig.Enabled != nil { + f0elemf3f0.SetEnabled(*f0iter.ForwardConfig.TargetGroupStickinessConfig.Enabled) + } + f0elemf3.SetTargetGroupStickinessConfig(f0elemf3f0) + } + if f0iter.ForwardConfig.TargetGroups != nil { + f0elemf3f1 := []*svcsdk.TargetGroupTuple{} + for _, f0elemf3f1iter := range f0iter.ForwardConfig.TargetGroups { + f0elemf3f1elem := &svcsdk.TargetGroupTuple{} + if f0elemf3f1iter.TargetGroupARN != nil { + f0elemf3f1elem.SetTargetGroupArn(*f0elemf3f1iter.TargetGroupARN) + } + if f0elemf3f1iter.Weight != nil { + f0elemf3f1elem.SetWeight(*f0elemf3f1iter.Weight) + } + f0elemf3f1 = append(f0elemf3f1, f0elemf3f1elem) + } + f0elemf3.SetTargetGroups(f0elemf3f1) + } + f0elem.SetForwardConfig(f0elemf3) + } + if f0iter.Order != nil { + f0elem.SetOrder(*f0iter.Order) + } + if f0iter.RedirectConfig != nil { + f0elemf5 := &svcsdk.RedirectActionConfig{} + if f0iter.RedirectConfig.Host != nil { + f0elemf5.SetHost(*f0iter.RedirectConfig.Host) + } + if f0iter.RedirectConfig.Path != nil { + f0elemf5.SetPath(*f0iter.RedirectConfig.Path) + } + if f0iter.RedirectConfig.Port != nil { + f0elemf5.SetPort(*f0iter.RedirectConfig.Port) + } + if f0iter.RedirectConfig.Protocol != nil { + f0elemf5.SetProtocol(*f0iter.RedirectConfig.Protocol) + } + if f0iter.RedirectConfig.Query != nil { + f0elemf5.SetQuery(*f0iter.RedirectConfig.Query) + } + if f0iter.RedirectConfig.StatusCode != nil { + f0elemf5.SetStatusCode(*f0iter.RedirectConfig.StatusCode) + } + f0elem.SetRedirectConfig(f0elemf5) + } + if f0iter.TargetGroupARN != nil { + f0elem.SetTargetGroupArn(*f0iter.TargetGroupARN) + } + if f0iter.Type != nil { + f0elem.SetType(*f0iter.Type) + } + f0 = append(f0, f0elem) + } + res.SetActions(f0) + } + if cr.Spec.ForProvider.Conditions != nil { + f1 := []*svcsdk.RuleCondition{} + for _, f1iter := range cr.Spec.ForProvider.Conditions { + f1elem := &svcsdk.RuleCondition{} + if f1iter.Field != nil { + f1elem.SetField(*f1iter.Field) + } + if f1iter.HostHeaderConfig != nil { + f1elemf1 := &svcsdk.HostHeaderConditionConfig{} + if f1iter.HostHeaderConfig.Values != nil { + f1elemf1f0 := []*string{} + for _, f1elemf1f0iter := range f1iter.HostHeaderConfig.Values { + var f1elemf1f0elem string + f1elemf1f0elem = *f1elemf1f0iter + f1elemf1f0 = append(f1elemf1f0, &f1elemf1f0elem) + } + f1elemf1.SetValues(f1elemf1f0) + } + f1elem.SetHostHeaderConfig(f1elemf1) + } + if f1iter.HTTPHeaderConfig != nil { + f1elemf2 := &svcsdk.HttpHeaderConditionConfig{} + if f1iter.HTTPHeaderConfig.HTTPHeaderName != nil { + f1elemf2.SetHttpHeaderName(*f1iter.HTTPHeaderConfig.HTTPHeaderName) + } + if f1iter.HTTPHeaderConfig.Values != nil { + f1elemf2f1 := []*string{} + for _, f1elemf2f1iter := range f1iter.HTTPHeaderConfig.Values { + var f1elemf2f1elem string + f1elemf2f1elem = *f1elemf2f1iter + f1elemf2f1 = append(f1elemf2f1, &f1elemf2f1elem) + } + f1elemf2.SetValues(f1elemf2f1) + } + f1elem.SetHttpHeaderConfig(f1elemf2) + } + if f1iter.HTTPRequestMethodConfig != nil { + f1elemf3 := &svcsdk.HttpRequestMethodConditionConfig{} + if f1iter.HTTPRequestMethodConfig.Values != nil { + f1elemf3f0 := []*string{} + for _, f1elemf3f0iter := range f1iter.HTTPRequestMethodConfig.Values { + var f1elemf3f0elem string + f1elemf3f0elem = *f1elemf3f0iter + f1elemf3f0 = append(f1elemf3f0, &f1elemf3f0elem) + } + f1elemf3.SetValues(f1elemf3f0) + } + f1elem.SetHttpRequestMethodConfig(f1elemf3) + } + if f1iter.PathPatternConfig != nil { + f1elemf4 := &svcsdk.PathPatternConditionConfig{} + if f1iter.PathPatternConfig.Values != nil { + f1elemf4f0 := []*string{} + for _, f1elemf4f0iter := range f1iter.PathPatternConfig.Values { + var f1elemf4f0elem string + f1elemf4f0elem = *f1elemf4f0iter + f1elemf4f0 = append(f1elemf4f0, &f1elemf4f0elem) + } + f1elemf4.SetValues(f1elemf4f0) + } + f1elem.SetPathPatternConfig(f1elemf4) + } + if f1iter.QueryStringConfig != nil { + f1elemf5 := &svcsdk.QueryStringConditionConfig{} + if f1iter.QueryStringConfig.Values != nil { + f1elemf5f0 := []*svcsdk.QueryStringKeyValuePair{} + for _, f1elemf5f0iter := range f1iter.QueryStringConfig.Values { + f1elemf5f0elem := &svcsdk.QueryStringKeyValuePair{} + if f1elemf5f0iter.Key != nil { + f1elemf5f0elem.SetKey(*f1elemf5f0iter.Key) + } + if f1elemf5f0iter.Value != nil { + f1elemf5f0elem.SetValue(*f1elemf5f0iter.Value) + } + f1elemf5f0 = append(f1elemf5f0, f1elemf5f0elem) + } + f1elemf5.SetValues(f1elemf5f0) + } + f1elem.SetQueryStringConfig(f1elemf5) + } + if f1iter.SourceIPConfig != nil { + f1elemf6 := &svcsdk.SourceIpConditionConfig{} + if f1iter.SourceIPConfig.Values != nil { + f1elemf6f0 := []*string{} + for _, f1elemf6f0iter := range f1iter.SourceIPConfig.Values { + var f1elemf6f0elem string + f1elemf6f0elem = *f1elemf6f0iter + f1elemf6f0 = append(f1elemf6f0, &f1elemf6f0elem) + } + f1elemf6.SetValues(f1elemf6f0) + } + f1elem.SetSourceIpConfig(f1elemf6) + } + if f1iter.Values != nil { + f1elemf7 := []*string{} + for _, f1elemf7iter := range f1iter.Values { + var f1elemf7elem string + f1elemf7elem = *f1elemf7iter + f1elemf7 = append(f1elemf7, &f1elemf7elem) + } + f1elem.SetValues(f1elemf7) + } + f1 = append(f1, f1elem) + } + res.SetConditions(f1) + } + if cr.Spec.ForProvider.Tags != nil { + f2 := []*svcsdk.Tag{} + for _, f2iter := range cr.Spec.ForProvider.Tags { + f2elem := &svcsdk.Tag{} + if f2iter.Key != nil { + f2elem.SetKey(*f2iter.Key) + } + if f2iter.Value != nil { + f2elem.SetValue(*f2iter.Value) + } + f2 = append(f2, f2elem) + } + res.SetTags(f2) + } + + return res +} + +// GenerateModifyRuleInput returns an update input. +func GenerateModifyRuleInput(cr *svcapitypes.Rule) *svcsdk.ModifyRuleInput { + res := &svcsdk.ModifyRuleInput{} + + if cr.Spec.ForProvider.Actions != nil { + f0 := []*svcsdk.Action{} + for _, f0iter := range cr.Spec.ForProvider.Actions { + f0elem := &svcsdk.Action{} + if f0iter.AuthenticateCognitoConfig != nil { + f0elemf0 := &svcsdk.AuthenticateCognitoActionConfig{} + if f0iter.AuthenticateCognitoConfig.AuthenticationRequestExtraParams != nil { + f0elemf0f0 := map[string]*string{} + for f0elemf0f0key, f0elemf0f0valiter := range f0iter.AuthenticateCognitoConfig.AuthenticationRequestExtraParams { + var f0elemf0f0val string + f0elemf0f0val = *f0elemf0f0valiter + f0elemf0f0[f0elemf0f0key] = &f0elemf0f0val + } + f0elemf0.SetAuthenticationRequestExtraParams(f0elemf0f0) + } + if f0iter.AuthenticateCognitoConfig.OnUnauthenticatedRequest != nil { + f0elemf0.SetOnUnauthenticatedRequest(*f0iter.AuthenticateCognitoConfig.OnUnauthenticatedRequest) + } + if f0iter.AuthenticateCognitoConfig.Scope != nil { + f0elemf0.SetScope(*f0iter.AuthenticateCognitoConfig.Scope) + } + if f0iter.AuthenticateCognitoConfig.SessionCookieName != nil { + f0elemf0.SetSessionCookieName(*f0iter.AuthenticateCognitoConfig.SessionCookieName) + } + if f0iter.AuthenticateCognitoConfig.SessionTimeout != nil { + f0elemf0.SetSessionTimeout(*f0iter.AuthenticateCognitoConfig.SessionTimeout) + } + if f0iter.AuthenticateCognitoConfig.UserPoolARN != nil { + f0elemf0.SetUserPoolArn(*f0iter.AuthenticateCognitoConfig.UserPoolARN) + } + if f0iter.AuthenticateCognitoConfig.UserPoolClientID != nil { + f0elemf0.SetUserPoolClientId(*f0iter.AuthenticateCognitoConfig.UserPoolClientID) + } + if f0iter.AuthenticateCognitoConfig.UserPoolDomain != nil { + f0elemf0.SetUserPoolDomain(*f0iter.AuthenticateCognitoConfig.UserPoolDomain) + } + f0elem.SetAuthenticateCognitoConfig(f0elemf0) + } + if f0iter.AuthenticateOIDCConfig != nil { + f0elemf1 := &svcsdk.AuthenticateOidcActionConfig{} + if f0iter.AuthenticateOIDCConfig.AuthenticationRequestExtraParams != nil { + f0elemf1f0 := map[string]*string{} + for f0elemf1f0key, f0elemf1f0valiter := range f0iter.AuthenticateOIDCConfig.AuthenticationRequestExtraParams { + var f0elemf1f0val string + f0elemf1f0val = *f0elemf1f0valiter + f0elemf1f0[f0elemf1f0key] = &f0elemf1f0val + } + f0elemf1.SetAuthenticationRequestExtraParams(f0elemf1f0) + } + if f0iter.AuthenticateOIDCConfig.AuthorizationEndpoint != nil { + f0elemf1.SetAuthorizationEndpoint(*f0iter.AuthenticateOIDCConfig.AuthorizationEndpoint) + } + if f0iter.AuthenticateOIDCConfig.ClientID != nil { + f0elemf1.SetClientId(*f0iter.AuthenticateOIDCConfig.ClientID) + } + if f0iter.AuthenticateOIDCConfig.ClientSecret != nil { + f0elemf1.SetClientSecret(*f0iter.AuthenticateOIDCConfig.ClientSecret) + } + if f0iter.AuthenticateOIDCConfig.Issuer != nil { + f0elemf1.SetIssuer(*f0iter.AuthenticateOIDCConfig.Issuer) + } + if f0iter.AuthenticateOIDCConfig.OnUnauthenticatedRequest != nil { + f0elemf1.SetOnUnauthenticatedRequest(*f0iter.AuthenticateOIDCConfig.OnUnauthenticatedRequest) + } + if f0iter.AuthenticateOIDCConfig.Scope != nil { + f0elemf1.SetScope(*f0iter.AuthenticateOIDCConfig.Scope) + } + if f0iter.AuthenticateOIDCConfig.SessionCookieName != nil { + f0elemf1.SetSessionCookieName(*f0iter.AuthenticateOIDCConfig.SessionCookieName) + } + if f0iter.AuthenticateOIDCConfig.SessionTimeout != nil { + f0elemf1.SetSessionTimeout(*f0iter.AuthenticateOIDCConfig.SessionTimeout) + } + if f0iter.AuthenticateOIDCConfig.TokenEndpoint != nil { + f0elemf1.SetTokenEndpoint(*f0iter.AuthenticateOIDCConfig.TokenEndpoint) + } + if f0iter.AuthenticateOIDCConfig.UseExistingClientSecret != nil { + f0elemf1.SetUseExistingClientSecret(*f0iter.AuthenticateOIDCConfig.UseExistingClientSecret) + } + if f0iter.AuthenticateOIDCConfig.UserInfoEndpoint != nil { + f0elemf1.SetUserInfoEndpoint(*f0iter.AuthenticateOIDCConfig.UserInfoEndpoint) + } + f0elem.SetAuthenticateOidcConfig(f0elemf1) + } + if f0iter.FixedResponseConfig != nil { + f0elemf2 := &svcsdk.FixedResponseActionConfig{} + if f0iter.FixedResponseConfig.ContentType != nil { + f0elemf2.SetContentType(*f0iter.FixedResponseConfig.ContentType) + } + if f0iter.FixedResponseConfig.MessageBody != nil { + f0elemf2.SetMessageBody(*f0iter.FixedResponseConfig.MessageBody) + } + if f0iter.FixedResponseConfig.StatusCode != nil { + f0elemf2.SetStatusCode(*f0iter.FixedResponseConfig.StatusCode) + } + f0elem.SetFixedResponseConfig(f0elemf2) + } + if f0iter.ForwardConfig != nil { + f0elemf3 := &svcsdk.ForwardActionConfig{} + if f0iter.ForwardConfig.TargetGroupStickinessConfig != nil { + f0elemf3f0 := &svcsdk.TargetGroupStickinessConfig{} + if f0iter.ForwardConfig.TargetGroupStickinessConfig.DurationSeconds != nil { + f0elemf3f0.SetDurationSeconds(*f0iter.ForwardConfig.TargetGroupStickinessConfig.DurationSeconds) + } + if f0iter.ForwardConfig.TargetGroupStickinessConfig.Enabled != nil { + f0elemf3f0.SetEnabled(*f0iter.ForwardConfig.TargetGroupStickinessConfig.Enabled) + } + f0elemf3.SetTargetGroupStickinessConfig(f0elemf3f0) + } + if f0iter.ForwardConfig.TargetGroups != nil { + f0elemf3f1 := []*svcsdk.TargetGroupTuple{} + for _, f0elemf3f1iter := range f0iter.ForwardConfig.TargetGroups { + f0elemf3f1elem := &svcsdk.TargetGroupTuple{} + if f0elemf3f1iter.TargetGroupARN != nil { + f0elemf3f1elem.SetTargetGroupArn(*f0elemf3f1iter.TargetGroupARN) + } + if f0elemf3f1iter.Weight != nil { + f0elemf3f1elem.SetWeight(*f0elemf3f1iter.Weight) + } + f0elemf3f1 = append(f0elemf3f1, f0elemf3f1elem) + } + f0elemf3.SetTargetGroups(f0elemf3f1) + } + f0elem.SetForwardConfig(f0elemf3) + } + if f0iter.Order != nil { + f0elem.SetOrder(*f0iter.Order) + } + if f0iter.RedirectConfig != nil { + f0elemf5 := &svcsdk.RedirectActionConfig{} + if f0iter.RedirectConfig.Host != nil { + f0elemf5.SetHost(*f0iter.RedirectConfig.Host) + } + if f0iter.RedirectConfig.Path != nil { + f0elemf5.SetPath(*f0iter.RedirectConfig.Path) + } + if f0iter.RedirectConfig.Port != nil { + f0elemf5.SetPort(*f0iter.RedirectConfig.Port) + } + if f0iter.RedirectConfig.Protocol != nil { + f0elemf5.SetProtocol(*f0iter.RedirectConfig.Protocol) + } + if f0iter.RedirectConfig.Query != nil { + f0elemf5.SetQuery(*f0iter.RedirectConfig.Query) + } + if f0iter.RedirectConfig.StatusCode != nil { + f0elemf5.SetStatusCode(*f0iter.RedirectConfig.StatusCode) + } + f0elem.SetRedirectConfig(f0elemf5) + } + if f0iter.TargetGroupARN != nil { + f0elem.SetTargetGroupArn(*f0iter.TargetGroupARN) + } + if f0iter.Type != nil { + f0elem.SetType(*f0iter.Type) + } + f0 = append(f0, f0elem) + } + res.SetActions(f0) + } + if cr.Spec.ForProvider.Conditions != nil { + f1 := []*svcsdk.RuleCondition{} + for _, f1iter := range cr.Spec.ForProvider.Conditions { + f1elem := &svcsdk.RuleCondition{} + if f1iter.Field != nil { + f1elem.SetField(*f1iter.Field) + } + if f1iter.HostHeaderConfig != nil { + f1elemf1 := &svcsdk.HostHeaderConditionConfig{} + if f1iter.HostHeaderConfig.Values != nil { + f1elemf1f0 := []*string{} + for _, f1elemf1f0iter := range f1iter.HostHeaderConfig.Values { + var f1elemf1f0elem string + f1elemf1f0elem = *f1elemf1f0iter + f1elemf1f0 = append(f1elemf1f0, &f1elemf1f0elem) + } + f1elemf1.SetValues(f1elemf1f0) + } + f1elem.SetHostHeaderConfig(f1elemf1) + } + if f1iter.HTTPHeaderConfig != nil { + f1elemf2 := &svcsdk.HttpHeaderConditionConfig{} + if f1iter.HTTPHeaderConfig.HTTPHeaderName != nil { + f1elemf2.SetHttpHeaderName(*f1iter.HTTPHeaderConfig.HTTPHeaderName) + } + if f1iter.HTTPHeaderConfig.Values != nil { + f1elemf2f1 := []*string{} + for _, f1elemf2f1iter := range f1iter.HTTPHeaderConfig.Values { + var f1elemf2f1elem string + f1elemf2f1elem = *f1elemf2f1iter + f1elemf2f1 = append(f1elemf2f1, &f1elemf2f1elem) + } + f1elemf2.SetValues(f1elemf2f1) + } + f1elem.SetHttpHeaderConfig(f1elemf2) + } + if f1iter.HTTPRequestMethodConfig != nil { + f1elemf3 := &svcsdk.HttpRequestMethodConditionConfig{} + if f1iter.HTTPRequestMethodConfig.Values != nil { + f1elemf3f0 := []*string{} + for _, f1elemf3f0iter := range f1iter.HTTPRequestMethodConfig.Values { + var f1elemf3f0elem string + f1elemf3f0elem = *f1elemf3f0iter + f1elemf3f0 = append(f1elemf3f0, &f1elemf3f0elem) + } + f1elemf3.SetValues(f1elemf3f0) + } + f1elem.SetHttpRequestMethodConfig(f1elemf3) + } + if f1iter.PathPatternConfig != nil { + f1elemf4 := &svcsdk.PathPatternConditionConfig{} + if f1iter.PathPatternConfig.Values != nil { + f1elemf4f0 := []*string{} + for _, f1elemf4f0iter := range f1iter.PathPatternConfig.Values { + var f1elemf4f0elem string + f1elemf4f0elem = *f1elemf4f0iter + f1elemf4f0 = append(f1elemf4f0, &f1elemf4f0elem) + } + f1elemf4.SetValues(f1elemf4f0) + } + f1elem.SetPathPatternConfig(f1elemf4) + } + if f1iter.QueryStringConfig != nil { + f1elemf5 := &svcsdk.QueryStringConditionConfig{} + if f1iter.QueryStringConfig.Values != nil { + f1elemf5f0 := []*svcsdk.QueryStringKeyValuePair{} + for _, f1elemf5f0iter := range f1iter.QueryStringConfig.Values { + f1elemf5f0elem := &svcsdk.QueryStringKeyValuePair{} + if f1elemf5f0iter.Key != nil { + f1elemf5f0elem.SetKey(*f1elemf5f0iter.Key) + } + if f1elemf5f0iter.Value != nil { + f1elemf5f0elem.SetValue(*f1elemf5f0iter.Value) + } + f1elemf5f0 = append(f1elemf5f0, f1elemf5f0elem) + } + f1elemf5.SetValues(f1elemf5f0) + } + f1elem.SetQueryStringConfig(f1elemf5) + } + if f1iter.SourceIPConfig != nil { + f1elemf6 := &svcsdk.SourceIpConditionConfig{} + if f1iter.SourceIPConfig.Values != nil { + f1elemf6f0 := []*string{} + for _, f1elemf6f0iter := range f1iter.SourceIPConfig.Values { + var f1elemf6f0elem string + f1elemf6f0elem = *f1elemf6f0iter + f1elemf6f0 = append(f1elemf6f0, &f1elemf6f0elem) + } + f1elemf6.SetValues(f1elemf6f0) + } + f1elem.SetSourceIpConfig(f1elemf6) + } + if f1iter.Values != nil { + f1elemf7 := []*string{} + for _, f1elemf7iter := range f1iter.Values { + var f1elemf7elem string + f1elemf7elem = *f1elemf7iter + f1elemf7 = append(f1elemf7, &f1elemf7elem) + } + f1elem.SetValues(f1elemf7) + } + f1 = append(f1, f1elem) + } + res.SetConditions(f1) + } + + return res +} + +// GenerateDeleteRuleInput returns a deletion input. +func GenerateDeleteRuleInput(cr *svcapitypes.Rule) *svcsdk.DeleteRuleInput { + res := &svcsdk.DeleteRuleInput{} + + 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() == "RuleNotFound" +} diff --git a/pkg/controller/elbv2/setup.go b/pkg/controller/elbv2/setup.go index cef8942b24..46827061a0 100644 --- a/pkg/controller/elbv2/setup.go +++ b/pkg/controller/elbv2/setup.go @@ -22,6 +22,7 @@ import ( "github.com/crossplane-contrib/provider-aws/pkg/controller/elbv2/listener" "github.com/crossplane-contrib/provider-aws/pkg/controller/elbv2/loadbalancer" + "github.com/crossplane-contrib/provider-aws/pkg/controller/elbv2/rule" "github.com/crossplane-contrib/provider-aws/pkg/controller/elbv2/target" "github.com/crossplane-contrib/provider-aws/pkg/controller/elbv2/targetgroup" "github.com/crossplane-contrib/provider-aws/pkg/utils/setup" @@ -34,6 +35,7 @@ func Setup(mgr ctrl.Manager, o controller.Options) error { listener.SetupListener, loadbalancer.SetupLoadBalancer, target.SetupTarget, + rule.SetupRule, targetgroup.SetupTargetGroup, ) } diff --git a/pkg/controller/rds/dbcluster/setup.go b/pkg/controller/rds/dbcluster/setup.go index 7afa72ee40..73242c4059 100644 --- a/pkg/controller/rds/dbcluster/setup.go +++ b/pkg/controller/rds/dbcluster/setup.go @@ -108,6 +108,7 @@ func (e *custom) postObserve(ctx context.Context, cr *svcapitypes.DBCluster, res } cr.Status.AtProvider.KMSKeyID = resp.DBClusters[0].KmsKeyId + cr.Status.AtProvider.Port = resp.DBClusters[0].Port switch pointer.StringValue(resp.DBClusters[0].Status) { case "available", "storage-optimization", "backing-up": @@ -125,14 +126,10 @@ func (e *custom) postObserve(ctx context.Context, cr *svcapitypes.DBCluster, res obs.ConnectionDetails = managed.ConnectionDetails{ xpv1.ResourceCredentialsSecretEndpointKey: []byte(pointer.StringValue(cr.Status.AtProvider.Endpoint)), xpv1.ResourceCredentialsSecretUserKey: []byte(pointer.StringValue(cr.Spec.ForProvider.MasterUsername)), - xpv1.ResourceCredentialsSecretPortKey: []byte(strconv.FormatInt(pointer.Int64Value(cr.Spec.ForProvider.Port), 10)), + xpv1.ResourceCredentialsSecretPortKey: []byte(strconv.FormatInt(pointer.Int64Value(cr.Status.AtProvider.Port), 10)), "readerEndpoint": []byte(pointer.StringValue(cr.Status.AtProvider.ReaderEndpoint)), } - if pointer.Int64Value(cr.Spec.ForProvider.Port) > 0 { - obs.ConnectionDetails[xpv1.ResourceCredentialsSecretPortKey] = []byte(strconv.FormatInt(pointer.Int64Value(cr.Spec.ForProvider.Port), 10)) - } - pw, err := dbinstance.GetDesiredPassword(ctx, e.kube, cr) if err != nil { return obs, errors.Wrap(err, dbinstance.ErrGetCachedPassword) diff --git a/pkg/controller/rds/dbinstance/setup.go b/pkg/controller/rds/dbinstance/setup.go index fa1e27e61d..40055b08a4 100644 --- a/pkg/controller/rds/dbinstance/setup.go +++ b/pkg/controller/rds/dbinstance/setup.go @@ -5,11 +5,15 @@ import ( "encoding/json" "fmt" "log" + "regexp" "sort" "strconv" "strings" "time" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws" svcsdk "github.com/aws/aws-sdk-go/service/rds" svcsdkapi "github.com/aws/aws-sdk-go/service/rds/rdsiface" xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" @@ -31,6 +35,9 @@ import ( dbinstance "github.com/crossplane-contrib/provider-aws/pkg/clients/rds" "github.com/crossplane-contrib/provider-aws/pkg/controller/rds/utils" "github.com/crossplane-contrib/provider-aws/pkg/features" + connectaws "github.com/crossplane-contrib/provider-aws/pkg/utils/connect/aws" + connectaws "github.com/crossplane-contrib/provider-aws/pkg/utils/connect/aws" + connectaws "github.com/crossplane-contrib/provider-aws/pkg/utils/connect/aws" errorutils "github.com/crossplane-contrib/provider-aws/pkg/utils/errors" "github.com/crossplane-contrib/provider-aws/pkg/utils/jsonpatch" "github.com/crossplane-contrib/provider-aws/pkg/utils/pointer" @@ -39,6 +46,9 @@ import ( // error constants const ( + errCreateReadReplica = "cannot creat DB instance read replica" + errCreateReadReplica = "cannot creat DB instance read replica" + errCreateReadReplica = "cannot creat DB instance read replica" errS3RestoreFailed = "cannot restore DB instance from S3 backup" errSnapshotRestoreFailed = "cannot restore DB instance from snapshot" errPointInTimeRestoreFailed = "cannot restore DB instance from point in time" @@ -53,6 +63,18 @@ const ( backupWindowFormat = "15:04" ) +// database roles +const ( + databaseRolePrimary = "Primary" + databaseRoleReadReplica = "Replica" +) + +// database roles +const ( + databaseRolePrimary = "Primary" + databaseRoleReadReplica = "Replica" +) + // other const ( statusDeleting = "deleting" @@ -61,21 +83,6 @@ const ( // SetupDBInstance adds a controller that reconciles DBInstance func SetupDBInstance(mgr ctrl.Manager, o controller.Options) error { name := managed.ControllerName(svcapitypes.DBInstanceGroupKind) - opts := []option{ - func(e *external) { - c := &custom{client: e.client, kube: e.kube, external: e} - e.lateInitialize = lateInitialize - e.isUpToDate = c.isUpToDate - e.preObserve = preObserve - e.postObserve = c.postObserve - e.preCreate = c.preCreate - e.preDelete = c.preDelete - e.postDelete = c.postDelete - e.filterList = filterList - e.preUpdate = c.preUpdate - e.postUpdate = c.postUpdate - }, - } cps := []managed.ConnectionPublisher{managed.NewAPISecretPublisher(mgr.GetClient(), mgr.GetScheme())} if o.Features.Enabled(features.EnableAlphaExternalSecretStores) { @@ -84,7 +91,9 @@ func SetupDBInstance(mgr ctrl.Manager, o controller.Options) error { reconcilerOpts := []managed.ReconcilerOption{ managed.WithCriticalAnnotationUpdater(custommanaged.NewRetryingCriticalAnnotationUpdater(mgr.GetClient())), - managed.WithTypedExternalConnector(&connector{kube: mgr.GetClient(), opts: opts}), + managed.WithTypedExternalConnector(&customConnector{kube: mgr.GetClient()}), + managed.WithTypedExternalConnector(&customConnector{kube: mgr.GetClient()}), + managed.WithTypedExternalConnector(&customConnector{kube: mgr.GetClient()}), managed.WithPollInterval(o.PollInterval), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), @@ -107,23 +116,86 @@ func SetupDBInstance(mgr ctrl.Manager, o controller.Options) error { Complete(r) } -type custom struct { - kube client.Client - client svcsdkapi.RDSAPI - external *external +type customConnector struct { + kube client.Client +} - cache struct { - addTags []*svcsdk.Tag - removeTags []*string +type customExternal struct { + external + shared *shared +} + +type shared struct { + external + cache *cache +} + +type cache struct { + addTags []*svcsdk.Tag + removeTags []*string + desiredPassword string +} + +func newCustomExternal(kube client.Client, client svcsdkapi.RDSAPI) *customExternal { + s := &shared{cache: &cache{}} + e := external{ + kube: kube, + client: client, + preObserve: preObserve, + isUpToDate: s.isUpToDate, + postObserve: s.postObserve, + preUpdate: s.preUpdate, + postUpdate: s.postUpdate, + preCreate: s.preCreate, + postCreate: nopPostCreate, + preDelete: s.preDelete, + postDelete: s.postDelete, + filterList: filterList, + lateInitialize: lateInitialize, + } + s.external = e + return &customExternal{ + external: e, + shared: s, } } +func (c *customConnector) Connect(ctx context.Context, cr *svcapitypes.DBInstance) (managed.TypedExternalClient[*svcapitypes.DBInstance], error) { + sess, err := connectaws.GetConfigV1(ctx, c.kube, cr, cr.Spec.ForProvider.Region) + if err != nil { + return nil, errors.Wrap(err, errCreateSession) + } + return newCustomExternal(c.kube, svcsdk.New(sess)), nil +} + +func (c *customExternal) Create(ctx context.Context, cr *svcapitypes.DBInstance) (managed.ExternalCreation, error) { + if cr.Spec.ForProvider.ReplicateSourceDBInstanceID != nil || cr.Spec.ForProvider.ReplicateSourceDBClusterID != nil { + cr.Status.SetConditions(xpv1.Creating()) + cr.Status.AtProvider.DatabaseRole = aws.String(databaseRoleReadReplica) + + createDBInstanceReadReplicaInput := dbinstance.GenerateCreateDBInstanceReadReplicaInput(cr) + createDBInstanceReadReplicaInput.DBInstanceIdentifier = pointer.ToOrNilIfZeroValue(meta.GetExternalName(cr)) + + _, err := c.client.CreateDBInstanceReadReplicaWithContext(ctx, createDBInstanceReadReplicaInput) + if err != nil { + return managed.ExternalCreation{}, errors.Wrap(err, errCreateReadReplica) + } + return managed.ExternalCreation{}, nil + } + cr.Status.AtProvider.DatabaseRole = aws.String(databaseRolePrimary) + return c.external.Create(ctx, cr) +} + func preObserve(_ context.Context, cr *svcapitypes.DBInstance, obj *svcsdk.DescribeDBInstancesInput) error { obj.DBInstanceIdentifier = pointer.ToOrNilIfZeroValue(meta.GetExternalName(cr)) return nil } -func (e *custom) preCreate(ctx context.Context, cr *svcapitypes.DBInstance, obj *svcsdk.CreateDBInstanceInput) (err error) { //nolint:gocyclo +func (s *shared) preCreate(ctx context.Context, cr *svcapitypes.DBInstance, obj *svcsdk.CreateDBInstanceInput) (err error) { //nolint:gocyclo + // If the DBInstance is going to be created as a read replica, we do not need to set the MasterUserPassword and the others + if cr.Spec.ForProvider.ReplicateSourceDBInstanceID != nil || cr.Spec.ForProvider.ReplicateSourceDBClusterID != nil { + return nil + } restoreFrom := cr.Spec.ForProvider.RestoreFrom autogenerate := cr.Spec.ForProvider.AutogeneratePassword masterUserPasswordSecretRef := cr.Spec.ForProvider.MasterUserPasswordSecretRef @@ -139,7 +211,9 @@ func (e *custom) preCreate(ctx context.Context, cr *svcapitypes.DBInstance, obj pw, err = password.Generate() case masterUserPasswordSecretRef != nil && autogenerate, masterUserPasswordSecretRef != nil && !autogenerate: - pw, err = dbinstance.GetSecretValue(ctx, e.kube, masterUserPasswordSecretRef) + pw, err = dbinstance.GetSecretValue(ctx, s.kube, masterUserPasswordSecretRef) + pw, err = dbinstance.GetSecretValue(ctx, s.kube, masterUserPasswordSecretRef) + pw, err = dbinstance.GetSecretValue(ctx, s.kube, masterUserPasswordSecretRef) } if err != nil { return errors.Wrap(err, dbinstance.ErrNoRetrievePasswordOrGenerate) @@ -174,18 +248,24 @@ func (e *custom) preCreate(ctx context.Context, cr *svcapitypes.DBInstance, obj switch *restoreFrom.Source { case "S3": - _, err := e.client.RestoreDBInstanceFromS3WithContext(ctx, dbinstance.GenerateRestoreDBInstanceFromS3Input(meta.GetExternalName(cr), pw, &cr.Spec.ForProvider)) + _, err := s.client.RestoreDBInstanceFromS3WithContext(ctx, dbinstance.GenerateRestoreDBInstanceFromS3Input(meta.GetExternalName(cr), pw, &cr.Spec.ForProvider)) + _, err := s.client.RestoreDBInstanceFromS3WithContext(ctx, dbinstance.GenerateRestoreDBInstanceFromS3Input(meta.GetExternalName(cr), pw, &cr.Spec.ForProvider)) + _, err := s.client.RestoreDBInstanceFromS3WithContext(ctx, dbinstance.GenerateRestoreDBInstanceFromS3Input(meta.GetExternalName(cr), pw, &cr.Spec.ForProvider)) if err != nil { return errorutils.Wrap(err, errS3RestoreFailed) } case "Snapshot": - _, err := e.client.RestoreDBInstanceFromDBSnapshotWithContext(ctx, dbinstance.GenerateRestoreDBInstanceFromSnapshotInput(meta.GetExternalName(cr), &cr.Spec.ForProvider)) + _, err := s.client.RestoreDBInstanceFromDBSnapshotWithContext(ctx, dbinstance.GenerateRestoreDBInstanceFromSnapshotInput(meta.GetExternalName(cr), &cr.Spec.ForProvider)) + _, err := s.client.RestoreDBInstanceFromDBSnapshotWithContext(ctx, dbinstance.GenerateRestoreDBInstanceFromSnapshotInput(meta.GetExternalName(cr), &cr.Spec.ForProvider)) + _, err := s.client.RestoreDBInstanceFromDBSnapshotWithContext(ctx, dbinstance.GenerateRestoreDBInstanceFromSnapshotInput(meta.GetExternalName(cr), &cr.Spec.ForProvider)) if err != nil { return errorutils.Wrap(err, errSnapshotRestoreFailed) } case "PointInTime": - _, err := e.client.RestoreDBInstanceToPointInTimeWithContext(ctx, dbinstance.GenerateRestoreDBInstanceToPointInTimeInput(meta.GetExternalName(cr), &cr.Spec.ForProvider)) + _, err := s.client.RestoreDBInstanceToPointInTimeWithContext(ctx, dbinstance.GenerateRestoreDBInstanceToPointInTimeInput(meta.GetExternalName(cr), &cr.Spec.ForProvider)) + _, err := s.client.RestoreDBInstanceToPointInTimeWithContext(ctx, dbinstance.GenerateRestoreDBInstanceToPointInTimeInput(meta.GetExternalName(cr), &cr.Spec.ForProvider)) + _, err := s.client.RestoreDBInstanceToPointInTimeWithContext(ctx, dbinstance.GenerateRestoreDBInstanceToPointInTimeInput(meta.GetExternalName(cr), &cr.Spec.ForProvider)) if err != nil { return errorutils.Wrap(err, errPointInTimeRestoreFailed) } @@ -198,7 +278,9 @@ func (e *custom) preCreate(ctx context.Context, cr *svcapitypes.DBInstance, obj obj.EngineVersion = cr.Spec.ForProvider.EngineVersion } - if _, err = dbinstance.Cache(ctx, e.kube, cr, passwordRestoreInfo); err != nil { + if _, err = dbinstance.Cache(ctx, s.kube, cr, passwordRestoreInfo); err != nil { + if _, err = dbinstance.Cache(ctx, s.kube, cr, passwordRestoreInfo); err != nil { + if _, err = dbinstance.Cache(ctx, s.kube, cr, passwordRestoreInfo); err != nil { return errors.Wrap(err, dbinstance.ErrCachePassword) } @@ -213,18 +295,20 @@ func (e *custom) preCreate(ctx context.Context, cr *svcapitypes.DBInstance, obj return nil } -func (e *custom) updateConnectionDetails(ctx context.Context, cr *svcapitypes.DBInstance, details managed.ConnectionDetails) (managed.ConnectionDetails, error) { +func (s *shared) updateConnectionDetails(ctx context.Context, cr *svcapitypes.DBInstance, details managed.ConnectionDetails) (managed.ConnectionDetails, error) { if details == nil { details = managed.ConnectionDetails{} } details[xpv1.ResourceCredentialsSecretUserKey] = []byte(pointer.StringValue(cr.Spec.ForProvider.MasterUsername)) - - pw, err := dbinstance.GetDesiredPassword(ctx, e.kube, cr) - if err != nil { - return details, errors.Wrap(err, dbinstance.ErrGetCachedPassword) + if s.cache.desiredPassword == "" { + pw, err := dbinstance.GetDesiredPassword(ctx, s.kube, cr) + if err != nil && pointer.StringValue(cr.Status.AtProvider.DatabaseRole) != databaseRoleReadReplica { + return details, errors.Wrap(err, dbinstance.ErrGetCachedPassword) + } + s.cache.desiredPassword = pw } - details[xpv1.ResourceCredentialsSecretPasswordKey] = []byte(pw) + details[xpv1.ResourceCredentialsSecretPasswordKey] = []byte(s.cache.desiredPassword) if cr.Status.AtProvider.Endpoint == nil { return details, nil @@ -239,15 +323,12 @@ func (e *custom) updateConnectionDetails(ctx context.Context, cr *svcapitypes.DB return details, nil } -func (e *custom) preUpdate(ctx context.Context, cr *svcapitypes.DBInstance, obj *svcsdk.ModifyDBInstanceInput) (err error) { +func (s *shared) preUpdate(ctx context.Context, cr *svcapitypes.DBInstance, obj *svcsdk.ModifyDBInstanceInput) (err error) { obj.DBInstanceIdentifier = pointer.ToOrNilIfZeroValue(meta.GetExternalName(cr)) obj.ApplyImmediately = cr.Spec.ForProvider.ApplyImmediately - - desiredPassword, err := dbinstance.GetDesiredPassword(ctx, e.kube, cr) - if err != nil { - return errors.Wrap(err, dbinstance.ErrRetrievePasswordForUpdate) - } - obj.MasterUserPassword = pointer.ToOrNilIfZeroValue(desiredPassword) + obj.MasterUserPassword = pointer.ToOrNilIfZeroValue(s.cache.desiredPassword) + obj.MasterUserPassword = pointer.ToOrNilIfZeroValue(s.cache.desiredPassword) + obj.MasterUserPassword = pointer.ToOrNilIfZeroValue(s.cache.desiredPassword) // VpcSecurityGroupIds cannot be set on an instance that belongs to a DBCluster if cr.Status.AtProvider.DBClusterIdentifier == nil { @@ -271,7 +352,9 @@ func (e *custom) preUpdate(ctx context.Context, cr *svcapitypes.DBInstance, obj input := GenerateDescribeDBInstancesInput(cr) - out, err := e.client.DescribeDBInstancesWithContext(ctx, input) + out, err := s.client.DescribeDBInstancesWithContext(ctx, input) + out, err := s.client.DescribeDBInstancesWithContext(ctx, input) + out, err := s.client.DescribeDBInstancesWithContext(ctx, input) if err != nil { return errors.Wrap(err, dbinstance.ErrDescribe) } @@ -282,40 +365,47 @@ func (e *custom) preUpdate(ctx context.Context, cr *svcapitypes.DBInstance, obj return nil } -func (e *custom) postUpdate(ctx context.Context, cr *svcapitypes.DBInstance, out *svcsdk.ModifyDBInstanceOutput, upd managed.ExternalUpdate, err error) (managed.ExternalUpdate, error) { +func (s *shared) postUpdate(ctx context.Context, cr *svcapitypes.DBInstance, out *svcsdk.ModifyDBInstanceOutput, upd managed.ExternalUpdate, err error) (managed.ExternalUpdate, error) { if err != nil { return upd, err } - desiredPassword, err := dbinstance.GetDesiredPassword(ctx, e.kube, cr) - if err != nil { - return upd, errors.Wrap(err, dbinstance.ErrRetrievePasswordForUpdate) - } + upd.ConnectionDetails, err = s.updateConnectionDetails(ctx, cr, upd.ConnectionDetails) - _, err = dbinstance.Cache(ctx, e.kube, cr, map[string]string{ - dbinstance.PasswordCacheKey: desiredPassword, + _, err = dbinstance.Cache(ctx, s.kube, cr, map[string]string{ + dbinstance.PasswordCacheKey: s.cache.desiredPassword, dbinstance.RestoreFlagCacheKay: "", // reset restore flag }) if err != nil { return upd, errors.Wrap(err, dbinstance.ErrCachePassword) } - upd.ConnectionDetails, err = e.updateConnectionDetails(ctx, cr, upd.ConnectionDetails) - // Update tags if necessary - if len(e.cache.addTags) > 0 { - _, err := e.client.AddTagsToResourceWithContext(ctx, &svcsdk.AddTagsToResourceInput{ + if len(s.cache.addTags) > 0 { + _, err := s.client.AddTagsToResourceWithContext(ctx, &svcsdk.AddTagsToResourceInput{ + if len(s.cache.addTags) > 0 { + _, err := s.client.AddTagsToResourceWithContext(ctx, &svcsdk.AddTagsToResourceInput{ + if len(s.cache.addTags) > 0 { + _, err := s.client.AddTagsToResourceWithContext(ctx, &svcsdk.AddTagsToResourceInput{ ResourceName: out.DBInstance.DBInstanceArn, - Tags: e.cache.addTags, + Tags: s.cache.addTags, + Tags: s.cache.addTags, + Tags: s.cache.addTags, }) if err != nil { return upd, errors.Wrap(err, errAddTags) } } - if len(e.cache.removeTags) > 0 { - _, err := e.client.RemoveTagsFromResourceWithContext(ctx, &svcsdk.RemoveTagsFromResourceInput{ + if len(s.cache.removeTags) > 0 { + _, err := s.client.RemoveTagsFromResourceWithContext(ctx, &svcsdk.RemoveTagsFromResourceInput{ + if len(s.cache.removeTags) > 0 { + _, err := s.client.RemoveTagsFromResourceWithContext(ctx, &svcsdk.RemoveTagsFromResourceInput{ + if len(s.cache.removeTags) > 0 { + _, err := s.client.RemoveTagsFromResourceWithContext(ctx, &svcsdk.RemoveTagsFromResourceInput{ ResourceName: out.DBInstance.DBInstanceArn, - TagKeys: e.cache.removeTags, + TagKeys: s.cache.removeTags, + TagKeys: s.cache.removeTags, + TagKeys: s.cache.removeTags, }) if err != nil { return upd, errors.Wrap(err, errRemoveTags) @@ -325,28 +415,32 @@ func (e *custom) postUpdate(ctx context.Context, cr *svcapitypes.DBInstance, out return upd, err } -func (e *custom) preDelete(ctx context.Context, cr *svcapitypes.DBInstance, obj *svcsdk.DeleteDBInstanceInput) (bool, error) { +func (s *shared) preDelete(ctx context.Context, cr *svcapitypes.DBInstance, obj *svcsdk.DeleteDBInstanceInput) (bool, error) { obj.DBInstanceIdentifier = pointer.ToOrNilIfZeroValue(meta.GetExternalName(cr)) obj.FinalDBSnapshotIdentifier = pointer.ToOrNilIfZeroValue(cr.Spec.ForProvider.FinalDBSnapshotIdentifier) obj.SkipFinalSnapshot = pointer.ToOrNilIfZeroValue(cr.Spec.ForProvider.SkipFinalSnapshot) obj.DeleteAutomatedBackups = cr.Spec.ForProvider.DeleteAutomatedBackups - _, _ = e.external.Update(ctx, cr) + _, _ = s.external.Update(ctx, cr) + _, _ = s.external.Update(ctx, cr) + _, _ = s.external.Update(ctx, cr) if *cr.Status.AtProvider.DBInstanceStatus == statusDeleting { return true, nil } return false, nil } -func (e *custom) postDelete(ctx context.Context, cr *svcapitypes.DBInstance, obj *svcsdk.DeleteDBInstanceOutput, err error) (managed.ExternalDelete, error) { +func (s *shared) postDelete(ctx context.Context, cr *svcapitypes.DBInstance, obj *svcsdk.DeleteDBInstanceOutput, err error) (managed.ExternalDelete, error) { if err != nil { return managed.ExternalDelete{}, err } - return managed.ExternalDelete{}, dbinstance.DeleteCache(ctx, e.kube, cr) + return managed.ExternalDelete{}, dbinstance.DeleteCache(ctx, s.kube, cr) + return managed.ExternalDelete{}, dbinstance.DeleteCache(ctx, s.kube, cr) + return managed.ExternalDelete{}, dbinstance.DeleteCache(ctx, s.kube, cr) } -func (e *custom) postObserve(ctx context.Context, cr *svcapitypes.DBInstance, resp *svcsdk.DescribeDBInstancesOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) { +func (s *shared) postObserve(ctx context.Context, cr *svcapitypes.DBInstance, resp *svcsdk.DescribeDBInstancesOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) { if err != nil { return obs, err } @@ -368,7 +462,9 @@ func (e *custom) postObserve(ctx context.Context, cr *svcapitypes.DBInstance, re cr.SetConditions(xpv1.Unavailable().WithMessage("DB Instance is " + pointer.StringValue(resp.DBInstances[0].DBInstanceStatus))) } - obs.ConnectionDetails, err = e.updateConnectionDetails(ctx, cr, obs.ConnectionDetails) + obs.ConnectionDetails, err = s.updateConnectionDetails(ctx, cr, obs.ConnectionDetails) + obs.ConnectionDetails, err = s.updateConnectionDetails(ctx, cr, obs.ConnectionDetails) + obs.ConnectionDetails, err = s.updateConnectionDetails(ctx, cr, obs.ConnectionDetails) return obs, err } @@ -462,7 +558,7 @@ func lateInitialize(in *svcapitypes.DBInstanceParameters, out *svcsdk.DescribeDB return nil } -func (e *custom) isUpToDate(ctx context.Context, cr *svcapitypes.DBInstance, out *svcsdk.DescribeDBInstancesOutput) (upToDate bool, diff string, err error) { //nolint:gocyclo +func (s *shared) isUpToDate(ctx context.Context, cr *svcapitypes.DBInstance, out *svcsdk.DescribeDBInstancesOutput) (upToDate bool, diff string, err error) { //nolint:gocyclo db := out.DBInstances[0] patch, err := createPatch(out, &cr.Spec.ForProvider) @@ -480,12 +576,32 @@ func (e *custom) isUpToDate(ctx context.Context, cr *svcapitypes.DBInstance, out return true, "", nil } - passwordUpToDate, err := dbinstance.PasswordUpToDate(ctx, e.kube, cr) + if db.ReadReplicaSourceDBClusterIdentifier != nil || db.ReadReplicaSourceDBInstanceIdentifier != nil { + cr.Status.AtProvider.DatabaseRole = aws.String(databaseRoleReadReplica) + } else { + cr.Status.AtProvider.DatabaseRole = aws.String(databaseRolePrimary) + } + + autogenerate := cr.Spec.ForProvider.AutogeneratePassword + masterUserPasswordSecretRef := cr.Spec.ForProvider.MasterUserPasswordSecretRef + cachedMasterPasswordExist := true + _, err = dbinstance.GetCachedPassword(ctx, s.kube, cr) if err != nil { - return false, "", errors.Wrap(err, dbinstance.ErrNoPasswordUpToDate) + cachedMasterPasswordExist = false } - if !passwordUpToDate { - return false, "", nil + + // If the instance is a read replica and the desiredPassword was not generated before, and it is not assumed to be + // generated(by autogenerate or masterUserPassw:539ordSecretRef), we don't check the password. + if !(pointer.StringValue(cr.Status.AtProvider.DatabaseRole) == databaseRoleReadReplica && + !autogenerate && masterUserPasswordSecretRef == nil && !cachedMasterPasswordExist) { + + passwordUpToDate, err := dbinstance.PasswordUpToDate(ctx, s.kube, cr) + if err != nil { + return false, "", errors.Wrap(err, dbinstance.ErrNoPasswordUpToDate) + } + if !passwordUpToDate { + return false, "", nil + } } // (PocketMobsters): AWS reformats our preferred time windows for backups and maintenance, @@ -499,7 +615,9 @@ func (e *custom) isUpToDate(ctx context.Context, cr *svcapitypes.DBInstance, out return false, "", err } - // Depending on whether the instance was created as gp2 or modified from another type (e.g. gp3) to gp2, + // Depending on whether the instance was created as gp2 or modified from another type (s.g. gp3) to gp2, + // Depending on whether the instance was created as gp2 or modified from another type (s.g. gp3) to gp2, + // Depending on whether the instance was created as gp2 or modified from another type (s.g. gp3) to gp2, // AWS provides different responses for IOPS/StorageThroughput (either 0 or nil). // Therefore, we consider both 0 and nil to be equivalent. iopsChanged := !(pointer.Int64Value(cr.Spec.ForProvider.IOPS) == pointer.Int64Value(db.Iops)) @@ -531,10 +649,25 @@ func (e *custom) isUpToDate(ctx context.Context, cr *svcapitypes.DBInstance, out cmpopts.IgnoreFields(svcapitypes.CustomDBInstanceParameters{}, "RestoreFrom"), cmpopts.IgnoreFields(svcapitypes.CustomDBInstanceParameters{}, "VPCSecurityGroupIDs"), cmpopts.IgnoreFields(svcapitypes.CustomDBInstanceParameters{}, "DeleteAutomatedBackups"), + cmpopts.IgnoreFields(svcapitypes.CustomDBInstanceParameters{}, "ReplicateSourceDBInstanceID", "ReplicateSourceDBClusterID"), + cmpopts.IgnoreFields(svcapitypes.CustomDBInstanceParameters{}, "TagIgnorePrefixes"), ) - e.cache.addTags, e.cache.removeTags = utils.DiffTags(cr.Spec.ForProvider.Tags, db.TagList) - tagsChanged := len(e.cache.addTags) != 0 || len(e.cache.removeTags) != 0 + ignore := append([]string{"aws:"}, cr.Spec.ForProvider.TagIgnorePrefixes...) + var observedTags []*svcsdk.Tag + if db.TagList != nil { + for _, tag := range db.TagList { // index discarded with _ + if utils.ShouldIgnore(pointer.StringValue(tag.Key), ignore) { + continue + } + observedTags = append(observedTags, &svcsdk.Tag{ + Key: tag.Key, + Value: tag.Value, + }) + } + } + s.cache.addTags, s.cache.removeTags = utils.DiffTags(cr.Spec.ForProvider.Tags, observedTags) + tagsChanged := len(s.cache.addTags) != 0 || len(s.cache.removeTags) != 0 if diff == "" && !maintenanceWindowChanged && !backupWindowChanged && !iopsChanged && !storageThroughputChanged && !versionChanged && !vpcSGsChanged && !dbParameterGroupChanged && !optionGroupChanged && !tagsChanged { return true, diff, nil @@ -575,7 +708,9 @@ func (e *custom) isUpToDate(ctx context.Context, cr *svcapitypes.DBInstance, out diff += fmt.Sprintf("\ndesired optionGroupName: %s \nobserved optionGroupName: %s ", pointer.StringValue(cr.Spec.ForProvider.OptionGroupName), pointer.StringValue(db.OptionGroupMemberships[0].OptionGroupName)) } if tagsChanged { - diff += fmt.Sprintf("\nadd %d tag(s) and remove %d tag(s)", len(e.cache.addTags), len(e.cache.removeTags)) + diff += fmt.Sprintf("\nadd %d tag(s) and remove %d tag(s)", len(s.cache.addTags), len(s.cache.removeTags)) + diff += fmt.Sprintf("\nadd %d tag(s) and remove %d tag(s)", len(s.cache.addTags), len(s.cache.removeTags)) + diff += fmt.Sprintf("\nadd %d tag(s) and remove %d tag(s)", len(s.cache.addTags), len(s.cache.removeTags)) } log.Println(diff) @@ -644,28 +779,48 @@ func createPatch(out *svcsdk.DescribeDBInstancesOutput, target *svcapitypes.DBIn return patch, nil } +func parseTimeWindowSpan(span, format string) (string, time.Time, error) { + // Regex: optional day, always HH:MM + re := regexp.MustCompile(`^\s*([A-Za-z]+:)?(\d{2}:\d{2})\s*$`) + matches := re.FindStringSubmatch(span) + if len(matches) != 3 { + return "", time.Time{}, errors.New("invalid time format, expected '[day:]HH:MM'") + } + day := "" + if matches[1] != "" { + day = strings.ToLower(strings.TrimSuffix(matches[1], ":")) + } + t, err := time.Parse(format, strings.TrimSpace(span)) + if err != nil { + return day, time.Time{}, err + } + return day, t, nil +} + func compareTimeRanges(format string, expectedWindow *string, actualWindow *string) (bool, error) { if pointer.StringValue(expectedWindow) == "" { - // no window to set, don't bother return false, nil } if pointer.StringValue(actualWindow) == "" { - // expected is set but actual is not, so we should set it return true, nil } - // all windows here have a "-" in between two values in the expected format, so just split leftSpans := strings.Split(*expectedWindow, "-") rightSpans := strings.Split(*actualWindow, "-") + + if len(leftSpans) != 2 || len(rightSpans) != 2 { + return false, errors.New("invalid time window format") + } + for i := range leftSpans { - left, err := time.Parse(format, leftSpans[i]) + dayA, timeA, err := parseTimeWindowSpan(leftSpans[i], format) if err != nil { return false, err } - right, err := time.Parse(format, rightSpans[i]) + dayB, timeB, err := parseTimeWindowSpan(rightSpans[i], format) if err != nil { return false, err } - if left != right { + if dayA != dayB || !timeA.Equal(timeB) { return true, nil } } diff --git a/pkg/controller/rds/dbinstance/setup_test.go b/pkg/controller/rds/dbinstance/setup_test.go new file mode 100644 index 0000000000..c20e32ab24 --- /dev/null +++ b/pkg/controller/rds/dbinstance/setup_test.go @@ -0,0 +1,268 @@ +package dbinstance + +import ( + "context" + "github.com/aws/aws-sdk-go/aws/request" + svcsdk "github.com/aws/aws-sdk-go/service/rds" + "github.com/crossplane/crossplane-runtime/pkg/test" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "sigs.k8s.io/controller-runtime/pkg/client" + + svcapitypes "github.com/crossplane-contrib/provider-aws/apis/rds/v1alpha1" + "github.com/crossplane-contrib/provider-aws/pkg/clients/rds/fake" +) + +func TestCreate(t *testing.T) { + type args struct { + cr *svcapitypes.DBInstance + kube client.Client + awsRDSClient fake.MockRDSClient + } + + type want struct { + statusAtProvider *svcapitypes.CustomDBInstanceObservation + err error + } + + cases := map[string]struct { + args + want + }{ + "CreateReadReplica": { + args: args{ + cr: &svcapitypes.DBInstance{ + Spec: svcapitypes.DBInstanceSpec{ + ForProvider: svcapitypes.DBInstanceParameters{ + CustomDBInstanceParameters: svcapitypes.CustomDBInstanceParameters{ + ReplicateSourceDBInstanceID: aws.String("source-db-instance-id"), + }, + }, + }, + }, + kube: test.NewMockClient(), + awsRDSClient: fake.MockRDSClient{ + MockCreateDBInstanceReadReplicaWithContext: func(ctx context.Context, input *svcsdk.CreateDBInstanceReadReplicaInput, optFns ...request.Option) (*svcsdk.CreateDBInstanceReadReplicaOutput, error) { + return &svcsdk.CreateDBInstanceReadReplicaOutput{}, nil + }, + MockCreateDBInstanceWithContext: func(ctx context.Context, input *svcsdk.CreateDBInstanceInput, optFns ...request.Option) (*svcsdk.CreateDBInstanceOutput, error) { + return &svcsdk.CreateDBInstanceOutput{}, nil + }, + }, + }, + want: want{ + statusAtProvider: &svcapitypes.CustomDBInstanceObservation{ + DatabaseRole: aws.String(databaseRoleReadReplica), + }, + }, + }, + "CreateStandaloneInstance": { + args: args{ + cr: &svcapitypes.DBInstance{ + Spec: svcapitypes.DBInstanceSpec{ + ForProvider: svcapitypes.DBInstanceParameters{ + CustomDBInstanceParameters: svcapitypes.CustomDBInstanceParameters{ + AutogeneratePassword: true, + }, + }, + }, + Status: svcapitypes.DBInstanceStatus{ + AtProvider: svcapitypes.DBInstanceObservation{}, + }, + }, + kube: test.NewMockClient(), + awsRDSClient: fake.MockRDSClient{ + MockCreateDBInstanceWithContext: func(ctx context.Context, input *svcsdk.CreateDBInstanceInput, optFns ...request.Option) (*svcsdk.CreateDBInstanceOutput, error) { + return &svcsdk.CreateDBInstanceOutput{DBInstance: &svcsdk.DBInstance{}}, nil + }, + MockCreateDBInstanceReadReplicaWithContext: func(ctx context.Context, input *svcsdk.CreateDBInstanceReadReplicaInput, optFns ...request.Option) (*svcsdk.CreateDBInstanceReadReplicaOutput, error) { + return &svcsdk.CreateDBInstanceReadReplicaOutput{}, nil + }, + }, + }, + want: want{ + statusAtProvider: &svcapitypes.CustomDBInstanceObservation{ + DatabaseRole: aws.String(databaseRolePrimary), + }, + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + cr := tc.args.cr + + // Create a new DBInstance + ce := newCustomExternal(tc.kube, &tc.awsRDSClient) + _, err := ce.Create(context.TODO(), cr) + if diff := cmp.Diff(tc.want.err, err, cmpopts.EquateErrors()); diff != "" { + t.Errorf("r: -want, +got error: \n%s", diff) + } + if diff := cmp.Diff(tc.want.statusAtProvider.DatabaseRole, cr.Status.AtProvider.DatabaseRole); diff != "" { + t.Errorf("r: -want, +got: \n%s", diff) + } + }) + } +} + +func TestIsUpToDate(t *testing.T) { + type args struct { + kube client.Client + cr *svcapitypes.DBInstance + out *svcsdk.DescribeDBInstancesOutput + } + + type want struct { + upToDate bool + err error + statusAtProvider *svcapitypes.CustomDBInstanceObservation + } + + cases := map[string]struct { + args + want + }{ + "UpToDateReadReplicaWithReplicatedMasterCredentials": { + args: args{ + cr: &svcapitypes.DBInstance{ + Spec: svcapitypes.DBInstanceSpec{ + ForProvider: svcapitypes.DBInstanceParameters{ + DeletionProtection: aws.Bool(true), + }, + }, + }, + out: &svcsdk.DescribeDBInstancesOutput{ + DBInstances: []*svcsdk.DBInstance{ + { + DeletionProtection: aws.Bool(true), + ReadReplicaSourceDBClusterIdentifier: aws.String("source-db-instance-id"), + }, + }, + }, + kube: &test.MockClient{ + MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { + return errors.New("not found") + }, + }, + }, + want: want{ + upToDate: true, + err: nil, + statusAtProvider: &svcapitypes.CustomDBInstanceObservation{ + DatabaseRole: aws.String(databaseRoleReadReplica), + }, + }, + }, + "databaseRolePrimary": { + args: args{ + cr: &svcapitypes.DBInstance{ + Spec: svcapitypes.DBInstanceSpec{ + ForProvider: svcapitypes.DBInstanceParameters{ + DeletionProtection: aws.Bool(true), + }, + }, + }, + out: &svcsdk.DescribeDBInstancesOutput{ + DBInstances: []*svcsdk.DBInstance{ + { + DeletionProtection: aws.Bool(true), + ReadReplicaDBInstanceIdentifiers: []*string{aws.String("db-read-replica-id")}, + }, + }, + }, + kube: test.NewMockClient(), + }, + want: want{ + upToDate: true, + err: nil, + statusAtProvider: &svcapitypes.CustomDBInstanceObservation{ + DatabaseRole: aws.String(databaseRolePrimary), + }, + }, + }, + "UpToDateStandaloneInstance": { + args: args{ + cr: &svcapitypes.DBInstance{ + Spec: svcapitypes.DBInstanceSpec{ + ForProvider: svcapitypes.DBInstanceParameters{ + DeletionProtection: aws.Bool(true), + }, + }, + }, + out: &svcsdk.DescribeDBInstancesOutput{ + DBInstances: []*svcsdk.DBInstance{ + { + DeletionProtection: aws.Bool(true), + }, + }, + }, + kube: test.NewMockClient(), + }, + want: want{ + upToDate: true, + err: nil, + statusAtProvider: &svcapitypes.CustomDBInstanceObservation{ + DatabaseRole: aws.String(databaseRoleStandalone), + }, + }, + }, + "IgnoresTagswithTagIgnorePrefixes": { + args: args{ + cr: &svcapitypes.DBInstance{ + Spec: svcapitypes.DBInstanceSpec{ + ForProvider: svcapitypes.DBInstanceParameters{ + CustomDBInstanceParameters: svcapitypes.CustomDBInstanceParameters{ + TagIgnorePrefixes: []string{"aws:", "c7n:"}, + }, + Tags: []*svcapitypes.Tag{ + {Key: aws.String("env"), Value: aws.String("prod")}, + }, + DeletionProtection: aws.Bool(true), + }, + }, + }, + out: &svcsdk.DescribeDBInstancesOutput{ + DBInstances: []*svcsdk.DBInstance{ + { + DeletionProtection: aws.Bool(true), + TagList: []*svcsdk.Tag{ + {Key: aws.String("aws:createdBy"), Value: aws.String("terraform")}, + {Key: aws.String("c7n:policy"), Value: aws.String("auto")}, + {Key: aws.String("env"), Value: aws.String("prod")}, + }, + }, + }, + }, + kube: test.NewMockClient(), + }, + want: want{ + upToDate: true, + err: nil, + statusAtProvider: &svcapitypes.CustomDBInstanceObservation{ + DatabaseRole: aws.String(databaseRoleStandalone), + }, + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + cr := tc.args.cr + ce := newCustomExternal(tc.kube, nil) + upToDate, _, err := ce.isUpToDate(context.TODO(), cr, tc.args.out) + + if diff := cmp.Diff(tc.want.err, err); diff != "" { + t.Errorf("r: -want, +got error: \n%s", diff) + } + if diff := cmp.Diff(tc.want.upToDate, upToDate); diff != "" { + t.Errorf("r: -want, +got: \n%s", diff) + } + if diff := cmp.Diff(tc.want.statusAtProvider.DatabaseRole, cr.Status.AtProvider.DatabaseRole); diff != "" { + t.Errorf("r: -want, +got: \n%s", diff) + } + }) + } +} diff --git a/pkg/controller/rds/utils/tags.go b/pkg/controller/rds/utils/tags.go index f3da92849a..c0e7160b3a 100644 --- a/pkg/controller/rds/utils/tags.go +++ b/pkg/controller/rds/utils/tags.go @@ -19,6 +19,7 @@ package utils import ( "context" "sort" + "strings" svcsdk "github.com/aws/aws-sdk-go/service/rds" "github.com/aws/aws-sdk-go/service/rds/rdsiface" @@ -35,6 +36,16 @@ const ( errCreateTags = "cannot create tags" ) +// ShouldIgnore returns true if `key` starts with any supplied prefix. +func ShouldIgnore(key string, prefixes []string) bool { + for _, p := range prefixes { + if strings.HasPrefix(key, p) { + return true + } + } + return false +} + // AreTagsUpToDate for spec and resourceName func AreTagsUpToDate(ctx context.Context, client rdsiface.RDSAPI, spec []*svcapitypes.Tag, resourceName *string) (bool, []*svcsdk.Tag, []*string, error) { current, err := ListTagsForResource(ctx, client, resourceName) diff --git a/pkg/controller/s3/bucket/bucket_test.go b/pkg/controller/s3/bucket/bucket_test.go index bc1cb28ddb..f1dac76283 100644 --- a/pkg/controller/s3/bucket/bucket_test.go +++ b/pkg/controller/s3/bucket/bucket_test.go @@ -291,7 +291,7 @@ func TestCreate(t *testing.T) { args want }{ - "VaildInput": { + "ValidInput": { args: args{ kube: &test.MockClient{ MockUpdate: test.NewMockUpdateFn(nil), diff --git a/pkg/controller/s3/bucket/object_lock_config.go b/pkg/controller/s3/bucket/object_lock_config.go new file mode 100644 index 0000000000..57c248e3fa --- /dev/null +++ b/pkg/controller/s3/bucket/object_lock_config.go @@ -0,0 +1,146 @@ +/* +Copyright 2025 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. +*/ + +package bucket + +import ( + "context" + "errors" + + "github.com/aws/aws-sdk-go-v2/aws" + awss3 "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane-runtime/pkg/meta" + "github.com/crossplane/crossplane-runtime/pkg/resource" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/crossplane-contrib/provider-aws/apis/s3/v1beta1" + "github.com/crossplane-contrib/provider-aws/pkg/clients/s3" + errorutils "github.com/crossplane-contrib/provider-aws/pkg/utils/errors" + "github.com/crossplane-contrib/provider-aws/pkg/utils/pointer" +) + +const ( + errMsgObjectLockIsNotDisableable = "after you enable object lock for a bucket, you can't disable object lock that bucket" + errObjectLockConfigurationGetFailed = "cannot get object lock configuration" + errObjectLockConfigurationPutFailed = "cannot put object lock configuration" +) + +type objectLockConfigurationCache struct { + objectLockConfiguration *types.ObjectLockConfiguration +} + +// ObjectLockConfigurationClient is the client for API methods and reconciling the ObjectLockConfiguration +type ObjectLockConfigurationClient struct { + client s3.BucketClient + cache objectLockConfigurationCache +} + +// NewObjectLockConfigurationClient creates the client for Object Lock Configuration +func NewObjectLockConfigurationClient(client s3.BucketClient) *ObjectLockConfigurationClient { + return &ObjectLockConfigurationClient{client: client} +} + +// Observe checks if the resource exists and if it matches the local configuration +func (in *ObjectLockConfigurationClient) Observe(ctx context.Context, cr *v1beta1.Bucket) (ResourceStatus, error) { + response, err := in.client.GetObjectLockConfiguration(ctx, &awss3.GetObjectLockConfigurationInput{ + Bucket: pointer.ToOrNilIfZeroValue(meta.GetExternalName(cr)), + }) + if err != nil { + if s3.ObjectLockConfigurationNotFound(err) && (cr.Spec.ForProvider.ObjectLockEnabledForBucket == nil || !*cr.Spec.ForProvider.ObjectLockEnabledForBucket) { + return Updated, nil + } + return NeedsUpdate, errorutils.Wrap(resource.Ignore(s3.ObjectLockConfigurationNotFound, err), errObjectLockConfigurationGetFailed) + } + objectLockConfiguration := &types.ObjectLockConfiguration{ + ObjectLockEnabled: "Disabled", + } + if response != nil && response.ObjectLockConfiguration != nil { + objectLockConfiguration = response.ObjectLockConfiguration + } + in.cache.objectLockConfiguration = objectLockConfiguration + return isUpToDate(&cr.Spec.ForProvider, objectLockConfiguration) +} + +// isUpToDate compares the local configuration with the remote configuration and determines if an update is needed +func isUpToDate(cr *v1beta1.BucketParameters, resp *types.ObjectLockConfiguration) (ResourceStatus, error) { + cmpOpts := []cmp.Option{cmpopts.IgnoreFields(types.ObjectLockConfiguration{}, "noSmithyDocumentSerde", + "Rule.noSmithyDocumentSerde", "Rule.DefaultRetention.noSmithyDocumentSerde")} + if !cmp.Equal(*GenerateAWSObjectLockConfiguration(cr), *resp, cmpOpts...) { + return NeedsUpdate, nil + } + return Updated, nil +} + +// CreateOrUpdate updates or creates the Object Lock configuration on AWS side +func (in *ObjectLockConfigurationClient) CreateOrUpdate(ctx context.Context, cr *v1beta1.Bucket) error { + if in.cache.objectLockConfiguration != nil { + if in.cache.objectLockConfiguration.ObjectLockEnabled == "Enabled" && !*cr.Spec.ForProvider.ObjectLockEnabledForBucket { + err := errorutils.Wrap(errors.New(errMsgObjectLockIsNotDisableable), errObjectLockConfigurationPutFailed) + cr.SetConditions(xpv1.ReconcileError(errors.New(errMsgObjectLockIsNotDisableable))) + return err + } + } + input := &awss3.PutObjectLockConfigurationInput{ + Bucket: aws.String(meta.GetExternalName(cr)), + ObjectLockConfiguration: GenerateAWSObjectLockConfiguration(&cr.Spec.ForProvider), + } + _, err := in.client.PutObjectLockConfiguration(ctx, input) + if err != nil { + cr.SetConditions(xpv1.ReconcileError(err)) + return errorutils.Wrap(err, errObjectLockConfigurationPutFailed) + } + return nil +} + +// Delete does nothing because after you enable Object Lock for a bucket, you can't disable it anymore +func (in *ObjectLockConfigurationClient) Delete(_ context.Context, _ *v1beta1.Bucket) error { + return nil +} + +// LateInitialize is not needed, because if something is not specified in the current state, it should be deleted on aws side +func (in *ObjectLockConfigurationClient) LateInitialize(_ context.Context, _ *v1beta1.Bucket) error { + return nil +} + +// SubresourceExists checks if the subresource exists +func (in *ObjectLockConfigurationClient) SubresourceExists(bucket *v1beta1.Bucket) bool { + return bucket.Spec.ForProvider.ObjectLockEnabledForBucket != nil +} + +// GenerateAWSObjectLockConfiguration generates the AWS S3 Object Lock Configuration +func GenerateAWSObjectLockConfiguration(in *v1beta1.BucketParameters) *types.ObjectLockConfiguration { + objectLockConfiguration := &types.ObjectLockConfiguration{ + ObjectLockEnabled: "Disabled", + } + if in.ObjectLockEnabledForBucket != nil { + if *in.ObjectLockEnabledForBucket { + objectLockConfiguration.ObjectLockEnabled = "Enabled" + } + } + if in.ObjectLockRule != nil { + objectLockConfiguration.Rule = &types.ObjectLockRule{ + DefaultRetention: &types.DefaultRetention{ + Days: in.ObjectLockRule.DefaultRetention.Days, + Mode: types.ObjectLockRetentionMode(in.ObjectLockRule.DefaultRetention.Mode), + Years: in.ObjectLockRule.DefaultRetention.Years, + }, + } + } + return objectLockConfiguration +} diff --git a/pkg/controller/s3/bucket/object_lock_config_test.go b/pkg/controller/s3/bucket/object_lock_config_test.go new file mode 100644 index 0000000000..108b2a4948 --- /dev/null +++ b/pkg/controller/s3/bucket/object_lock_config_test.go @@ -0,0 +1,235 @@ +/* +Copyright 2025 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. +*/ + +package bucket + +import ( + "context" + "testing" + + awss3 "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/smithy-go" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane-runtime/pkg/resource" + "github.com/crossplane/crossplane-runtime/pkg/test" + "github.com/google/go-cmp/cmp" + "github.com/pkg/errors" + + "github.com/crossplane-contrib/provider-aws/apis/s3/v1beta1" + clients3 "github.com/crossplane-contrib/provider-aws/pkg/clients/s3" + "github.com/crossplane-contrib/provider-aws/pkg/clients/s3/fake" + s3Testing "github.com/crossplane-contrib/provider-aws/pkg/controller/s3/testing" + errorutils "github.com/crossplane-contrib/provider-aws/pkg/utils/errors" +) + +func TestObjectLockConfigObserve(t *testing.T) { + type args struct { + cl *ObjectLockConfigurationClient + cr *v1beta1.Bucket + } + + type want struct { + status ResourceStatus + err error + } + + cases := map[string]struct { + args + want + }{ + "ObjectLockIsNotSet": { + args: args{ + cr: s3Testing.Bucket(), + cl: NewObjectLockConfigurationClient(fake.MockBucketClient{ + MockGetObjectLockConfiguration: func(ctx context.Context, input *awss3.GetObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.GetObjectLockConfigurationOutput, error) { + return nil, &smithy.GenericAPIError{Code: clients3.ObjectLockConfigurationErrCode} + }, + }), + }, + want: want{ + status: Updated, + err: nil, + }, + }, + "ObjectLockExplicitlyFalse": { + args: args{ + cr: s3Testing.Bucket(s3Testing.WithObjectLockEnabledForBucket(false)), + cl: NewObjectLockConfigurationClient(fake.MockBucketClient{ + MockGetObjectLockConfiguration: func(ctx context.Context, input *awss3.GetObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.GetObjectLockConfigurationOutput, error) { + return nil, &smithy.GenericAPIError{Code: clients3.ObjectLockConfigurationErrCode} + }, + }), + }, + want: want{ + status: Updated, + err: nil, + }, + }, + "ObjectLockSetToFalseButWasEnabledBefore": { + args: args{ + cr: s3Testing.Bucket(s3Testing.WithObjectLockEnabledForBucket(false)), + cl: NewObjectLockConfigurationClient(fake.MockBucketClient{ + MockGetObjectLockConfiguration: func(ctx context.Context, input *awss3.GetObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.GetObjectLockConfigurationOutput, error) { + return &awss3.GetObjectLockConfigurationOutput{ObjectLockConfiguration: &types.ObjectLockConfiguration{ObjectLockEnabled: "Enabled"}}, nil + }, + }), + }, + want: want{ + status: NeedsUpdate, + err: nil, + }, + }, + "ObjectLockSetToTrue": { + args: args{ + cr: s3Testing.Bucket(s3Testing.WithObjectLockEnabledForBucket(true)), + cl: NewObjectLockConfigurationClient(fake.MockBucketClient{ + MockGetObjectLockConfiguration: func(ctx context.Context, input *awss3.GetObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.GetObjectLockConfigurationOutput, error) { + return &awss3.GetObjectLockConfigurationOutput{ObjectLockConfiguration: &types.ObjectLockConfiguration{ObjectLockEnabled: "Disabled"}}, nil + }, + }), + }, + want: want{ + status: NeedsUpdate, + err: nil, + }, + }, + "ObjectLockRuleIsSetButObjectLockNotEnabled": { + args: args{ + cr: s3Testing.Bucket(s3Testing.WithObjectLockRule(&v1beta1.ObjectLockRule{DefaultRetention: &v1beta1.DefaultRetention{Mode: "GOVERNANCE", Days: aws.Int32(7)}})), + cl: NewObjectLockConfigurationClient(fake.MockBucketClient{ + MockGetObjectLockConfiguration: func(ctx context.Context, input *awss3.GetObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.GetObjectLockConfigurationOutput, error) { + return nil, &smithy.GenericAPIError{Code: clients3.ObjectLockConfigurationErrCode} + }, + }), + }, + want: want{ + status: Updated, + err: nil, + }, + }, + "ObjectLockRuleIsSet": { + args: args{ + cr: s3Testing.Bucket( + s3Testing.WithObjectLockEnabledForBucket(true), + s3Testing.WithObjectLockRule(&v1beta1.ObjectLockRule{DefaultRetention: &v1beta1.DefaultRetention{Mode: "GOVERNANCE", Days: aws.Int32(7)}}), + ), + cl: NewObjectLockConfigurationClient(fake.MockBucketClient{ + MockGetObjectLockConfiguration: func(ctx context.Context, input *awss3.GetObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.GetObjectLockConfigurationOutput, error) { + return nil, &smithy.GenericAPIError{Code: clients3.ObjectLockConfigurationErrCode} + }, + }), + }, + want: want{ + status: NeedsUpdate, + err: nil, + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got, err := tc.args.cl.Observe(context.Background(), tc.args.cr) + if diff := cmp.Diff(tc.want.status, got); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + }) + } +} + +func TestObjectLockConfigCreateOrUpdate(t *testing.T) { + type args struct { + cl *ObjectLockConfigurationClient + cr *v1beta1.Bucket + } + + type want struct { + cr resource.Managed + err error + } + + cases := map[string]struct { + args + want + }{ + "ObjectLockSetToFalseButWasEnabledBefore": { + args: args{ + cr: s3Testing.Bucket(s3Testing.WithObjectLockEnabledForBucket(false)), + cl: &ObjectLockConfigurationClient{ + cache: objectLockConfigurationCache{ + objectLockConfiguration: &types.ObjectLockConfiguration{ + ObjectLockEnabled: "Enabled", + }, + }, + }, + }, + want: want{ + err: errorutils.Wrap(errors.New(errMsgObjectLockIsNotDisableable), errObjectLockConfigurationPutFailed), + cr: s3Testing.Bucket( + s3Testing.WithObjectLockEnabledForBucket(false), + s3Testing.WithConditions(xpv1.ReconcileError(errors.New(errMsgObjectLockIsNotDisableable))), + ), + }, + }, + "ObjectLockAPIErrorResponse": { + args: args{ + cr: s3Testing.Bucket(s3Testing.WithObjectLockEnabledForBucket(true)), + cl: NewObjectLockConfigurationClient(fake.MockBucketClient{ + MockPutObjectLockConfiguration: func(ctx context.Context, input *awss3.PutObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.PutObjectLockConfigurationOutput, error) { + return &awss3.PutObjectLockConfigurationOutput{}, errBoom + }, + }), + }, + want: want{ + err: errorutils.Wrap(errBoom, errObjectLockConfigurationPutFailed), + cr: s3Testing.Bucket( + s3Testing.WithObjectLockEnabledForBucket(true), + s3Testing.WithConditions(xpv1.ReconcileError(errBoom)), + ), + }, + }, + "ObjectLockSetToTrue": { + args: args{ + cr: s3Testing.Bucket(s3Testing.WithObjectLockEnabledForBucket(true)), + cl: NewObjectLockConfigurationClient(fake.MockBucketClient{ + MockPutObjectLockConfiguration: func(ctx context.Context, input *awss3.PutObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.PutObjectLockConfigurationOutput, error) { + return &awss3.PutObjectLockConfigurationOutput{}, nil + }, + }), + }, + want: want{ + err: nil, + cr: s3Testing.Bucket(s3Testing.WithObjectLockEnabledForBucket(true)), + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + err := tc.args.cl.CreateOrUpdate(context.Background(), tc.args.cr) + if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + if diff := cmp.Diff(tc.want.cr, tc.args.cr, test.EquateConditions()); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + }) + } +} diff --git a/pkg/controller/s3/bucket/subresources.go b/pkg/controller/s3/bucket/subresources.go index 462fd78d21..a4294ceebc 100644 --- a/pkg/controller/s3/bucket/subresources.go +++ b/pkg/controller/s3/bucket/subresources.go @@ -50,6 +50,7 @@ func NewSubresourceClients(client s3.BucketClient) []SubresourceClient { NewWebsiteConfigurationClient(client), NewPublicAccessBlockClient(client), NewPolicyClient(client), + NewObjectLockConfigurationClient(client), } } diff --git a/pkg/controller/s3/bucket/taggingConfig.go b/pkg/controller/s3/bucket/tagging_config.go similarity index 97% rename from pkg/controller/s3/bucket/taggingConfig.go rename to pkg/controller/s3/bucket/tagging_config.go index ff62156603..e4d1866852 100644 --- a/pkg/controller/s3/bucket/taggingConfig.go +++ b/pkg/controller/s3/bucket/tagging_config.go @@ -41,14 +41,14 @@ const ( taggingDeleteFailed = "cannot delete Bucket tagging set" ) -type cache struct { +type taggingConfigurationCache struct { getBucketTaggingOutput *awss3.GetBucketTaggingOutput } // TaggingConfigurationClient is the client for API methods and reconciling the CORSConfiguration type TaggingConfigurationClient struct { client s3.BucketClient - cache cache + cache taggingConfigurationCache } // NewTaggingConfigurationClient creates the client for CORS Configuration @@ -57,7 +57,7 @@ func NewTaggingConfigurationClient(client s3.BucketClient) *TaggingConfiguration } // CacheBucketTaggingOutput returns cached *awss3.GetBucketTaggingOutput` if it exists, otherwise adds -// `TaggingConfigurationClient.GetBucketTagging` output to cache and then returns it +// `TaggingConfigurationClient.GetBucketTagging` output to taggingConfigurationCache and then returns it func (in *TaggingConfigurationClient) CacheBucketTaggingOutput(ctx context.Context, bucketName *string) (*awss3.GetBucketTaggingOutput, error) { if in.cache.getBucketTaggingOutput == nil { external, err := in.client.GetBucketTagging(ctx, &awss3.GetBucketTaggingInput{Bucket: bucketName}) diff --git a/pkg/controller/s3/bucket/taggingConfig_test.go b/pkg/controller/s3/bucket/tagging_config_test.go similarity index 100% rename from pkg/controller/s3/bucket/taggingConfig_test.go rename to pkg/controller/s3/bucket/tagging_config_test.go diff --git a/pkg/controller/s3/testing/clientHelper.go b/pkg/controller/s3/testing/client_helper.go similarity index 94% rename from pkg/controller/s3/testing/clientHelper.go rename to pkg/controller/s3/testing/client_helper.go index fea37c7bd9..4985d53169 100644 --- a/pkg/controller/s3/testing/clientHelper.go +++ b/pkg/controller/s3/testing/client_helper.go @@ -83,6 +83,12 @@ func Client(m ...ClientModifier) *fake.MockBucketClient { return &awss3.DeleteBucketPolicyOutput{}, nil }, }, + MockGetObjectLockConfiguration: func(ctx context.Context, input *awss3.GetObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.GetObjectLockConfigurationOutput, error) { + return &awss3.GetObjectLockConfigurationOutput{}, nil + }, + MockPutObjectLockConfiguration: func(ctx context.Context, input *awss3.PutObjectLockConfigurationInput, opts []func(*awss3.Options)) (*awss3.PutObjectLockConfigurationOutput, error) { + return &awss3.PutObjectLockConfigurationOutput{}, nil + }, } for _, v := range m { v(client) diff --git a/pkg/controller/s3/testing/testHelper.go b/pkg/controller/s3/testing/test_helper.go similarity index 87% rename from pkg/controller/s3/testing/testHelper.go rename to pkg/controller/s3/testing/test_helper.go index dd2a8255b8..1aba5f2a7e 100644 --- a/pkg/controller/s3/testing/testHelper.go +++ b/pkg/controller/s3/testing/test_helper.go @@ -34,7 +34,6 @@ var ( grantReadACP = "readACPGrant" grantWrite = "writeGrant" grantWriteACP = "writeACPGrant" - objectLock = true // BucketName is the name of the s3 bucket in testing BucketName = "test.bucket.name" ) @@ -123,19 +122,28 @@ func WithPolicyUpdatePolicy(s *v1beta1.BucketPolicyUpdatePolicy) BucketModifier return func(r *v1beta1.Bucket) { r.Spec.ForProvider.PolicyUpdatePolicy = s } } +// WithObjectLockEnabledForBucket sets ObjectLockEnabledForBucket for an S3 Bucket +func WithObjectLockEnabledForBucket(s bool) BucketModifier { + return func(r *v1beta1.Bucket) { r.Spec.ForProvider.ObjectLockEnabledForBucket = &s } +} + +// WithObjectLockRule sets ObjectLockRule for an S3 Bucket +func WithObjectLockRule(s *v1beta1.ObjectLockRule) BucketModifier { + return func(r *v1beta1.Bucket) { r.Spec.ForProvider.ObjectLockRule = s } +} + // Bucket creates a v1beta1 Bucket for use in testing func Bucket(m ...BucketModifier) *v1beta1.Bucket { cr := &v1beta1.Bucket{ Spec: v1beta1.BucketSpec{ ForProvider: v1beta1.BucketParameters{ - ACL: &acl, - LocationConstraint: Region, - GrantFullControl: &grantFullControl, - GrantRead: &grantRead, - GrantReadACP: &grantReadACP, - GrantWrite: &grantWrite, - GrantWriteACP: &grantWriteACP, - ObjectLockEnabledForBucket: &objectLock, + ACL: &acl, + LocationConstraint: Region, + GrantFullControl: &grantFullControl, + GrantRead: &grantRead, + GrantReadACP: &grantReadACP, + GrantWrite: &grantWrite, + GrantWriteACP: &grantWriteACP, }, }, } diff --git a/pkg/controller/secretsmanager/secret/setup.go b/pkg/controller/secretsmanager/secret/setup.go index 74d1856055..ad5ef86f2c 100644 --- a/pkg/controller/secretsmanager/secret/setup.go +++ b/pkg/controller/secretsmanager/secret/setup.go @@ -248,7 +248,7 @@ func (e *hooks) isUpToDate(ctx context.Context, cr *svcapitypes.Secret, resp *sv return false, "", nil } add, remove := DiffTags(cr.Spec.ForProvider.Tags, resp.Tags) - if len(add) != 0 && len(remove) != 0 { + if len(add) != 0 || len(remove) != 0 { return false, "", nil } diff --git a/pkg/controller/transfer/user/setup.go b/pkg/controller/transfer/user/setup.go index 13a6f3e395..c32b0bd721 100644 --- a/pkg/controller/transfer/user/setup.go +++ b/pkg/controller/transfer/user/setup.go @@ -167,7 +167,7 @@ func (h *hooks) isUpToDate(_ context.Context, cr *svcapitypes.User, obj *svcsdk. var areTagsUpToDate bool areTagsUpToDate, h.cache.tagsToAdd, h.cache.tagsToDelete = utils.DiffTags(cr.Spec.ForProvider.Tags, obj.User.Tags) - return areKeysUpToDate && areTagsUpToDate, "", nil + return areKeysUpToDate && areTagsUpToDate && isMappingsUpToDate(cr, obj), "", nil } func isSSHPublicKeysUpToDate(cr *svcapitypes.User, obj *svcsdk.DescribeUserOutput) (isUpToDate bool, toAdd, toRemove []string) { @@ -199,6 +199,34 @@ func isSSHPublicKeysUpToDate(cr *svcapitypes.User, obj *svcsdk.DescribeUserOutpu return len(toRemove) == 0 && len(toAdd) == 0, toAdd, toRemove } +func isMappingsUpToDate(cr *svcapitypes.User, obj *svcsdk.DescribeUserOutput) bool { + specMap := make(map[string]string, len(cr.Spec.ForProvider.HomeDirectoryMappings)) + for _, k := range cr.Spec.ForProvider.HomeDirectoryMappings { + specMap[*k.Entry] = *k.Target + } + + curMap := make(map[string]string, len(obj.User.HomeDirectoryMappings)) + + for _, mapping := range obj.User.HomeDirectoryMappings { + body := ptr.Deref(mapping.Entry, "") + curMap[body] = ptr.Deref(mapping.Target, "") + + if _, exists := specMap[body]; !exists { + return false + } + } + + for key, value := range specMap { + if val, exists := curMap[key]; !exists { + return false + } else if value != val { + return false + } + } + + return true +} + func preCreate(_ context.Context, cr *svcapitypes.User, obj *svcsdk.CreateUserInput) error { obj.ServerId = cr.Spec.ForProvider.ServerID obj.Role = cr.Spec.ForProvider.Role diff --git a/pkg/controller/transfer/user/setup_test.go b/pkg/controller/transfer/user/setup_test.go index 5abf80ff96..c69f440483 100644 --- a/pkg/controller/transfer/user/setup_test.go +++ b/pkg/controller/transfer/user/setup_test.go @@ -1277,3 +1277,148 @@ func TestIsSSHPublicKeysUpToDate(t *testing.T) { }) } } + +func TestIsMappingUpToDate(t *testing.T) { + type args struct { + cr *svcapitypes.User + obj *svcsdk.DescribeUserOutput + } + + type want struct { + isUpToDate bool + } + + cases := map[string]struct { + args + want + }{ + "NeedsUpdate": { + args: args{ + cr: user( + withExternalName("test"), + withSpec(svcapitypes.UserParameters{ + Region: "us-east-1", + HomeDirectoryMappings: []*svcapitypes.HomeDirectoryMapEntry{ + { + Entry: ptr.To("entry"), + Target: ptr.To("target"), + }, + }, + CustomUserParameters: svcapitypes.CustomUserParameters{ + ServerID: ptr.To("server"), + Role: ptr.To("role"), + SSHPublicKeys: []svcapitypes.SSHPublicKeySpec{ + { + Body: "some-public-key", + }, + }, + }, + }), + withStatus(svcapitypes.UserObservation{ + ARN: ptr.To("ARN"), + }), + ), + obj: &svcsdk.DescribeUserOutput{ + User: &svcsdk.DescribedUser{ + HomeDirectoryMappings: []*svcsdk.HomeDirectoryMapEntry{}, + }, + }, + }, + want: want{ + isUpToDate: false, + }, + }, + "NeedsUpdateNewTarget": { + args: args{ + cr: user( + withExternalName("test"), + withSpec(svcapitypes.UserParameters{ + Region: "us-east-1", + HomeDirectoryMappings: []*svcapitypes.HomeDirectoryMapEntry{ + { + Entry: ptr.To("entry"), + Target: ptr.To("targetnew"), + }, + }, + CustomUserParameters: svcapitypes.CustomUserParameters{ + ServerID: ptr.To("server"), + Role: ptr.To("role"), + SSHPublicKeys: []svcapitypes.SSHPublicKeySpec{ + { + Body: "some-public-key", + }, + }, + }, + }), + withStatus(svcapitypes.UserObservation{ + ARN: ptr.To("ARN"), + }), + ), + obj: &svcsdk.DescribeUserOutput{ + User: &svcsdk.DescribedUser{ + HomeDirectoryMappings: []*svcsdk.HomeDirectoryMapEntry{ + { + Entry: ptr.To("entry"), + Target: ptr.To("target"), + }, + }, + }, + }, + }, + want: want{ + isUpToDate: false, + }, + }, + "IsUpToDate": { + args: args{ + cr: user( + withExternalName("test"), + withSpec(svcapitypes.UserParameters{ + Region: "us-east-1", + HomeDirectoryMappings: []*svcapitypes.HomeDirectoryMapEntry{ + { + Entry: ptr.To("entry"), + Target: ptr.To("target"), + }, + }, + CustomUserParameters: svcapitypes.CustomUserParameters{ + ServerID: ptr.To("server"), + Role: ptr.To("role"), + SSHPublicKeys: []svcapitypes.SSHPublicKeySpec{ + { + Body: "some-public-key", + }, + }, + }, + }), + withStatus(svcapitypes.UserObservation{ + ARN: ptr.To("ARN"), + }), + ), + obj: &svcsdk.DescribeUserOutput{ + User: &svcsdk.DescribedUser{ + HomeDirectoryMappings: []*svcsdk.HomeDirectoryMapEntry{ + { + Entry: ptr.To("entry"), + Target: ptr.To("target"), + }, + }, + }, + }, + }, + want: want{ + isUpToDate: true, + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + isUpToDate := isMappingsUpToDate(tc.args.cr, tc.args.obj) + + if diff := cmp.Diff(tc.want.isUpToDate, isUpToDate, test.EquateErrors()); diff != "" { + t.Errorf("isUpToDate: -want, +got:\n%s", diff) + } + }) + } +}