diff --git a/.gitignore b/.gitignore index e14a1ec..adf5b04 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp *~ .idea +.vscode /docs/site bin build \ No newline at end of file diff --git a/apis/v1alpha1/ack-generate-metadata.yaml b/apis/v1alpha1/ack-generate-metadata.yaml index 75ca901..56c43bf 100755 --- a/apis/v1alpha1/ack-generate-metadata.yaml +++ b/apis/v1alpha1/ack-generate-metadata.yaml @@ -1,13 +1,13 @@ ack_generate_info: - build_date: "2025-09-19T17:08:59Z" - build_hash: 6b4211163dcc34776b01da9a18217bac0f4103fd - go_version: go1.24.6 - version: v0.52.0 + build_date: "2025-09-29T19:41:37Z" + build_hash: ef6e2f362a0f93d4a063b0a2b416f7ab0a156843 + go_version: go1.25.0 + version: v0.52.0-4-gef6e2f3 api_directory_checksum: 524e0af3e7ceea86a3153c12c06091ea924d3410 api_version: v1alpha1 aws_sdk_go_version: v1.32.6 generator_config_info: - file_checksum: 7d89869149ba948467065fc8d5947d9eff039b8b + file_checksum: 72d5fe6ac88d647ed6c67869928f3bc12ea6a566 original_file_name: generator.yaml last_modification: reason: API generation diff --git a/apis/v1alpha1/generator.yaml b/apis/v1alpha1/generator.yaml index ac1e03d..c26b339 100644 --- a/apis/v1alpha1/generator.yaml +++ b/apis/v1alpha1/generator.yaml @@ -17,18 +17,27 @@ resources: template_path: hooks/sdk_read_one_post_set_output.go.tpl sdk_update_pre_set_output: template_path: hooks/sdk_update_pre_set_output.go.tpl + delta_pre_compare: + template_path: hooks/delta_pre_compare.go.tpl renames: operations: CreateBroker: input_fields: BrokerName: Name + + update_operation: + omit_unchanged_fields: true + # UpdateBroker API returns nil for values not set in the request. + only_set_unchanged_fields: true fields: - securityGroups: + SecurityGroups: + late_initialize: {} references: service_name: ec2 resource: SecurityGroup path: Status.ID SubnetIDs: + late_initialize: {} references: service_name: ec2 resource: Subnet @@ -54,3 +63,27 @@ resources: is_ignored: true Users.Password: is_secret: true + AuthenticationStrategy: + late_initialize: {} + AutoMinorVersionUpgrade: + late_initialize: {} + EngineVersion: + late_initialize: {} + set: + - method: Update + ignore: true + MaintenanceWindowStartTime: + late_initialize: {} + EncryptionOptions: + late_initialize: {} + StorageType: + late_initialize: {} + PubliclyAccessible: + late_initialize: {} + Logs: + late_initialize: {} + LDAPServerMetadata: + late_initialize: { + # LDAP Server Metadata is only available for ActiveMQ brokers + skip_incomplete_check: {} + } \ No newline at end of file diff --git a/config/crd/bases/mq.services.k8s.aws_brokers.yaml b/config/crd/bases/mq.services.k8s.aws_brokers.yaml index 5b48210..a38f777 100644 --- a/config/crd/bases/mq.services.k8s.aws_brokers.yaml +++ b/config/crd/bases/mq.services.k8s.aws_brokers.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.2 + controller-gen.kubebuilder.io/version: v0.19.0 name: brokers.mq.services.k8s.aws spec: group: mq.services.k8s.aws diff --git a/generator.yaml b/generator.yaml index ac1e03d..c26b339 100644 --- a/generator.yaml +++ b/generator.yaml @@ -17,18 +17,27 @@ resources: template_path: hooks/sdk_read_one_post_set_output.go.tpl sdk_update_pre_set_output: template_path: hooks/sdk_update_pre_set_output.go.tpl + delta_pre_compare: + template_path: hooks/delta_pre_compare.go.tpl renames: operations: CreateBroker: input_fields: BrokerName: Name + + update_operation: + omit_unchanged_fields: true + # UpdateBroker API returns nil for values not set in the request. + only_set_unchanged_fields: true fields: - securityGroups: + SecurityGroups: + late_initialize: {} references: service_name: ec2 resource: SecurityGroup path: Status.ID SubnetIDs: + late_initialize: {} references: service_name: ec2 resource: Subnet @@ -54,3 +63,27 @@ resources: is_ignored: true Users.Password: is_secret: true + AuthenticationStrategy: + late_initialize: {} + AutoMinorVersionUpgrade: + late_initialize: {} + EngineVersion: + late_initialize: {} + set: + - method: Update + ignore: true + MaintenanceWindowStartTime: + late_initialize: {} + EncryptionOptions: + late_initialize: {} + StorageType: + late_initialize: {} + PubliclyAccessible: + late_initialize: {} + Logs: + late_initialize: {} + LDAPServerMetadata: + late_initialize: { + # LDAP Server Metadata is only available for ActiveMQ brokers + skip_incomplete_check: {} + } \ No newline at end of file diff --git a/helm/crds/mq.services.k8s.aws_brokers.yaml b/helm/crds/mq.services.k8s.aws_brokers.yaml index 5b48210..a38f777 100644 --- a/helm/crds/mq.services.k8s.aws_brokers.yaml +++ b/helm/crds/mq.services.k8s.aws_brokers.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.2 + controller-gen.kubebuilder.io/version: v0.19.0 name: brokers.mq.services.k8s.aws spec: group: mq.services.k8s.aws diff --git a/helm/crds/services.k8s.aws_adoptedresources.yaml b/helm/crds/services.k8s.aws_adoptedresources.yaml index b7be322..d6cdd10 100644 --- a/helm/crds/services.k8s.aws_adoptedresources.yaml +++ b/helm/crds/services.k8s.aws_adoptedresources.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.2 + controller-gen.kubebuilder.io/version: v0.19.0 name: adoptedresources.services.k8s.aws spec: group: services.k8s.aws diff --git a/helm/crds/services.k8s.aws_fieldexports.yaml b/helm/crds/services.k8s.aws_fieldexports.yaml index 49b4f38..6e2c61e 100644 --- a/helm/crds/services.k8s.aws_fieldexports.yaml +++ b/helm/crds/services.k8s.aws_fieldexports.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.2 + controller-gen.kubebuilder.io/version: v0.19.0 name: fieldexports.services.k8s.aws spec: group: services.k8s.aws diff --git a/pkg/resource/broker/delta.go b/pkg/resource/broker/delta.go index 8069458..e836632 100644 --- a/pkg/resource/broker/delta.go +++ b/pkg/resource/broker/delta.go @@ -42,6 +42,9 @@ func newResourceDelta( delta.Add("", a, b) return delta } + // MQ sets the patch version of the engine. For example when using 3.13 in the spec + // MQ will use the latest available patch version. + reconcileEngineVersion(a, b) if ackcompare.HasNilDifference(a.ko.Spec.AuthenticationStrategy, b.ko.Spec.AuthenticationStrategy) { delta.Add("Spec.AuthenticationStrategy", a.ko.Spec.AuthenticationStrategy, b.ko.Spec.AuthenticationStrategy) diff --git a/pkg/resource/broker/delta_test.go b/pkg/resource/broker/delta_test.go new file mode 100644 index 0000000..7ce3113 --- /dev/null +++ b/pkg/resource/broker/delta_test.go @@ -0,0 +1,114 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file 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 broker + +import ( + "testing" + + svcapitypes "github.com/aws-controllers-k8s/mq-controller/apis/v1alpha1" + "github.com/aws/aws-sdk-go-v2/aws" +) + +func TestNewResourceDelta_EngineVersionPrefix(t *testing.T) { + tests := []struct { + name string + aEngineVersion *string + bEngineVersion *string + expectDelta bool + }{ + { + name: "a is prefix of b - no delta expected", + aEngineVersion: aws.String("3.13"), + bEngineVersion: aws.String("3.13.1"), + expectDelta: false, + }, + { + name: "a is prefix of b with patch version - no delta expected", + aEngineVersion: aws.String("5.18"), + bEngineVersion: aws.String("5.18.4"), + expectDelta: false, + }, + { + name: "exact match - no delta expected", + aEngineVersion: aws.String("3.13.1"), + bEngineVersion: aws.String("3.13.1"), + expectDelta: false, + }, + { + name: "different patch versions - no delta expected", + aEngineVersion: aws.String("3.13.2"), + bEngineVersion: aws.String("3.13.1"), + expectDelta: true, + }, + { + name: "different minor versions - delta expected", + aEngineVersion: aws.String("3.13"), + bEngineVersion: aws.String("3.14.1"), + expectDelta: true, + }, + { + name: "a is longer than b - delta expected", + aEngineVersion: aws.String("3.13.1"), + bEngineVersion: aws.String("3.13"), + expectDelta: true, + }, + { + name: "nil versions - no delta expected", + aEngineVersion: nil, + bEngineVersion: nil, + expectDelta: false, + }, + { + name: "a nil, b not nil - delta expected", + aEngineVersion: nil, + bEngineVersion: aws.String("3.13.1"), + expectDelta: true, + }, + { + name: "a not nil, b nil - delta expected", + aEngineVersion: aws.String("3.13"), + bEngineVersion: nil, + expectDelta: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &resource{ + ko: &svcapitypes.Broker{ + Spec: svcapitypes.BrokerSpec{ + EngineVersion: tt.aEngineVersion, + }, + }, + } + b := &resource{ + ko: &svcapitypes.Broker{ + Spec: svcapitypes.BrokerSpec{ + EngineVersion: tt.bEngineVersion, + }, + }, + } + + delta := newResourceDelta(a, b) + hasDelta := delta.DifferentAt("Spec.EngineVersion") + + if tt.expectDelta && !hasDelta { + t.Errorf("Expected delta for EngineVersion but none found") + } + if !tt.expectDelta && hasDelta { + t.Errorf("Expected no delta for EngineVersion but found one") + } + }) + } +} diff --git a/pkg/resource/broker/hooks.go b/pkg/resource/broker/hooks.go index 1f3674e..15c25c4 100644 --- a/pkg/resource/broker/hooks.go +++ b/pkg/resource/broker/hooks.go @@ -14,6 +14,8 @@ package broker import ( + "strings" + svcapitypes "github.com/aws-controllers-k8s/mq-controller/apis/v1alpha1" ) @@ -46,3 +48,14 @@ func brokerDeleteInProgress(r *resource) bool { bs := *r.ko.Status.BrokerState return bs == string(svcapitypes.BrokerState_DELETION_IN_PROGRESS) } + +// MQ does not allow patch version to be set. +// For the purposes of comparison we should consider only the minor version. +func reconcileEngineVersion( + a *resource, + b *resource, +) { + if a != nil && b != nil && a.ko.Spec.EngineVersion != nil && b.ko.Spec.EngineVersion != nil && strings.HasPrefix(*b.ko.Spec.EngineVersion, *a.ko.Spec.EngineVersion) { + a.ko.Spec.EngineVersion = b.ko.Spec.EngineVersion + } +} diff --git a/pkg/resource/broker/manager.go b/pkg/resource/broker/manager.go index 44d65bf..352df15 100644 --- a/pkg/resource/broker/manager.go +++ b/pkg/resource/broker/manager.go @@ -50,7 +50,7 @@ var ( // +kubebuilder:rbac:groups=mq.services.k8s.aws,resources=brokers,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=mq.services.k8s.aws,resources=brokers/status,verbs=get;update;patch -var lateInitializeFieldNames = []string{} +var lateInitializeFieldNames = []string{"AuthenticationStrategy", "AutoMinorVersionUpgrade", "EncryptionOptions", "EngineVersion", "LDAPServerMetadata", "Logs", "MaintenanceWindowStartTime", "PubliclyAccessible", "SecurityGroups", "StorageType", "SubnetIDs"} // resourceManager is responsible for providing a consistent way to perform // CRUD operations in a backend AWS service API for Book custom resources. @@ -248,6 +248,37 @@ func (rm *resourceManager) LateInitialize( func (rm *resourceManager) incompleteLateInitialization( res acktypes.AWSResource, ) bool { + ko := rm.concreteResource(res).ko.DeepCopy() + if ko.Spec.AuthenticationStrategy == nil { + return true + } + if ko.Spec.AutoMinorVersionUpgrade == nil { + return true + } + if ko.Spec.EncryptionOptions == nil { + return true + } + if ko.Spec.EngineVersion == nil { + return true + } + if ko.Spec.Logs == nil { + return true + } + if ko.Spec.MaintenanceWindowStartTime == nil { + return true + } + if ko.Spec.PubliclyAccessible == nil { + return true + } + if ko.Spec.SecurityGroups == nil { + return true + } + if ko.Spec.StorageType == nil { + return true + } + if ko.Spec.SubnetIDs == nil { + return true + } return false } @@ -257,7 +288,42 @@ func (rm *resourceManager) lateInitializeFromReadOneOutput( observed acktypes.AWSResource, latest acktypes.AWSResource, ) acktypes.AWSResource { - return latest + observedKo := rm.concreteResource(observed).ko.DeepCopy() + latestKo := rm.concreteResource(latest).ko.DeepCopy() + if observedKo.Spec.AuthenticationStrategy != nil && latestKo.Spec.AuthenticationStrategy == nil { + latestKo.Spec.AuthenticationStrategy = observedKo.Spec.AuthenticationStrategy + } + if observedKo.Spec.AutoMinorVersionUpgrade != nil && latestKo.Spec.AutoMinorVersionUpgrade == nil { + latestKo.Spec.AutoMinorVersionUpgrade = observedKo.Spec.AutoMinorVersionUpgrade + } + if observedKo.Spec.EncryptionOptions != nil && latestKo.Spec.EncryptionOptions == nil { + latestKo.Spec.EncryptionOptions = observedKo.Spec.EncryptionOptions + } + if observedKo.Spec.EngineVersion != nil && latestKo.Spec.EngineVersion == nil { + latestKo.Spec.EngineVersion = observedKo.Spec.EngineVersion + } + if observedKo.Spec.LDAPServerMetadata != nil && latestKo.Spec.LDAPServerMetadata == nil { + latestKo.Spec.LDAPServerMetadata = observedKo.Spec.LDAPServerMetadata + } + if observedKo.Spec.Logs != nil && latestKo.Spec.Logs == nil { + latestKo.Spec.Logs = observedKo.Spec.Logs + } + if observedKo.Spec.MaintenanceWindowStartTime != nil && latestKo.Spec.MaintenanceWindowStartTime == nil { + latestKo.Spec.MaintenanceWindowStartTime = observedKo.Spec.MaintenanceWindowStartTime + } + if observedKo.Spec.PubliclyAccessible != nil && latestKo.Spec.PubliclyAccessible == nil { + latestKo.Spec.PubliclyAccessible = observedKo.Spec.PubliclyAccessible + } + if observedKo.Spec.SecurityGroups != nil && latestKo.Spec.SecurityGroups == nil { + latestKo.Spec.SecurityGroups = observedKo.Spec.SecurityGroups + } + if observedKo.Spec.StorageType != nil && latestKo.Spec.StorageType == nil { + latestKo.Spec.StorageType = observedKo.Spec.StorageType + } + if observedKo.Spec.SubnetIDs != nil && latestKo.Spec.SubnetIDs == nil { + latestKo.Spec.SubnetIDs = observedKo.Spec.SubnetIDs + } + return &resource{latestKo} } // IsSynced returns true if the resource is synced. diff --git a/pkg/resource/broker/sdk.go b/pkg/resource/broker/sdk.go index b47ed4b..5f0e76a 100644 --- a/pkg/resource/broker/sdk.go +++ b/pkg/resource/broker/sdk.go @@ -558,111 +558,122 @@ func (rm *resourceManager) sdkUpdate( latestKOStatus := latest.ko.DeepCopy().Status ko.Status = latestKOStatus - if resp.AuthenticationStrategy != "" { - ko.Spec.AuthenticationStrategy = aws.String(string(resp.AuthenticationStrategy)) - } else { - ko.Spec.AuthenticationStrategy = nil + if delta.DifferentAt("Spec.AuthenticationStrategy") { + if resp.AuthenticationStrategy != "" { + ko.Spec.AuthenticationStrategy = aws.String(string(resp.AuthenticationStrategy)) + } else { + ko.Spec.AuthenticationStrategy = nil + } } - if resp.AutoMinorVersionUpgrade != nil { - ko.Spec.AutoMinorVersionUpgrade = resp.AutoMinorVersionUpgrade - } else { - ko.Spec.AutoMinorVersionUpgrade = nil + if delta.DifferentAt("Spec.AutoMinorVersionUpgrade") { + if resp.AutoMinorVersionUpgrade != nil { + ko.Spec.AutoMinorVersionUpgrade = resp.AutoMinorVersionUpgrade + } else { + ko.Spec.AutoMinorVersionUpgrade = nil + } } if resp.BrokerId != nil { ko.Status.BrokerID = resp.BrokerId } else { ko.Status.BrokerID = nil } - if resp.Configuration != nil { - f3 := &svcapitypes.ConfigurationID{} - if resp.Configuration.Id != nil { - f3.ID = resp.Configuration.Id - } - if resp.Configuration.Revision != nil { - revisionCopy := int64(*resp.Configuration.Revision) - f3.Revision = &revisionCopy + if delta.DifferentAt("Spec.Configuration") { + if resp.Configuration != nil { + f3 := &svcapitypes.ConfigurationID{} + if resp.Configuration.Id != nil { + f3.ID = resp.Configuration.Id + } + if resp.Configuration.Revision != nil { + revisionCopy := int64(*resp.Configuration.Revision) + f3.Revision = &revisionCopy + } + ko.Spec.Configuration = f3 + } else { + ko.Spec.Configuration = nil } - ko.Spec.Configuration = f3 - } else { - ko.Spec.Configuration = nil - } - if resp.EngineVersion != nil { - ko.Spec.EngineVersion = resp.EngineVersion - } else { - ko.Spec.EngineVersion = nil } - if resp.HostInstanceType != nil { - ko.Spec.HostInstanceType = resp.HostInstanceType - } else { - ko.Spec.HostInstanceType = nil - } - if resp.LdapServerMetadata != nil { - f8 := &svcapitypes.LDAPServerMetadataInput{} - if resp.LdapServerMetadata.Hosts != nil { - f8.Hosts = aws.StringSlice(resp.LdapServerMetadata.Hosts) - } - if resp.LdapServerMetadata.RoleBase != nil { - f8.RoleBase = resp.LdapServerMetadata.RoleBase - } - if resp.LdapServerMetadata.RoleName != nil { - f8.RoleName = resp.LdapServerMetadata.RoleName - } - if resp.LdapServerMetadata.RoleSearchMatching != nil { - f8.RoleSearchMatching = resp.LdapServerMetadata.RoleSearchMatching - } - if resp.LdapServerMetadata.RoleSearchSubtree != nil { - f8.RoleSearchSubtree = resp.LdapServerMetadata.RoleSearchSubtree - } - if resp.LdapServerMetadata.ServiceAccountUsername != nil { - f8.ServiceAccountUsername = resp.LdapServerMetadata.ServiceAccountUsername - } - if resp.LdapServerMetadata.UserBase != nil { - f8.UserBase = resp.LdapServerMetadata.UserBase - } - if resp.LdapServerMetadata.UserRoleName != nil { - f8.UserRoleName = resp.LdapServerMetadata.UserRoleName - } - if resp.LdapServerMetadata.UserSearchMatching != nil { - f8.UserSearchMatching = resp.LdapServerMetadata.UserSearchMatching - } - if resp.LdapServerMetadata.UserSearchSubtree != nil { - f8.UserSearchSubtree = resp.LdapServerMetadata.UserSearchSubtree + if delta.DifferentAt("Spec.HostInstanceType") { + if resp.HostInstanceType != nil { + ko.Spec.HostInstanceType = resp.HostInstanceType + } else { + ko.Spec.HostInstanceType = nil } - ko.Spec.LDAPServerMetadata = f8 - } else { - ko.Spec.LDAPServerMetadata = nil } - if resp.Logs != nil { - f9 := &svcapitypes.Logs{} - if resp.Logs.Audit != nil { - f9.Audit = resp.Logs.Audit - } - if resp.Logs.General != nil { - f9.General = resp.Logs.General + if delta.DifferentAt("Spec.LDAPServerMetadata") { + if resp.LdapServerMetadata != nil { + f8 := &svcapitypes.LDAPServerMetadataInput{} + if resp.LdapServerMetadata.Hosts != nil { + f8.Hosts = aws.StringSlice(resp.LdapServerMetadata.Hosts) + } + if resp.LdapServerMetadata.RoleBase != nil { + f8.RoleBase = resp.LdapServerMetadata.RoleBase + } + if resp.LdapServerMetadata.RoleName != nil { + f8.RoleName = resp.LdapServerMetadata.RoleName + } + if resp.LdapServerMetadata.RoleSearchMatching != nil { + f8.RoleSearchMatching = resp.LdapServerMetadata.RoleSearchMatching + } + if resp.LdapServerMetadata.RoleSearchSubtree != nil { + f8.RoleSearchSubtree = resp.LdapServerMetadata.RoleSearchSubtree + } + if resp.LdapServerMetadata.ServiceAccountUsername != nil { + f8.ServiceAccountUsername = resp.LdapServerMetadata.ServiceAccountUsername + } + if resp.LdapServerMetadata.UserBase != nil { + f8.UserBase = resp.LdapServerMetadata.UserBase + } + if resp.LdapServerMetadata.UserRoleName != nil { + f8.UserRoleName = resp.LdapServerMetadata.UserRoleName + } + if resp.LdapServerMetadata.UserSearchMatching != nil { + f8.UserSearchMatching = resp.LdapServerMetadata.UserSearchMatching + } + if resp.LdapServerMetadata.UserSearchSubtree != nil { + f8.UserSearchSubtree = resp.LdapServerMetadata.UserSearchSubtree + } + ko.Spec.LDAPServerMetadata = f8 + } else { + ko.Spec.LDAPServerMetadata = nil } - ko.Spec.Logs = f9 - } else { - ko.Spec.Logs = nil } - if resp.MaintenanceWindowStartTime != nil { - f10 := &svcapitypes.WeeklyStartTime{} - if resp.MaintenanceWindowStartTime.DayOfWeek != "" { - f10.DayOfWeek = aws.String(string(resp.MaintenanceWindowStartTime.DayOfWeek)) - } - if resp.MaintenanceWindowStartTime.TimeOfDay != nil { - f10.TimeOfDay = resp.MaintenanceWindowStartTime.TimeOfDay + if delta.DifferentAt("Spec.Logs") { + if resp.Logs != nil { + f9 := &svcapitypes.Logs{} + if resp.Logs.Audit != nil { + f9.Audit = resp.Logs.Audit + } + if resp.Logs.General != nil { + f9.General = resp.Logs.General + } + ko.Spec.Logs = f9 + } else { + ko.Spec.Logs = nil } - if resp.MaintenanceWindowStartTime.TimeZone != nil { - f10.TimeZone = resp.MaintenanceWindowStartTime.TimeZone + } + if delta.DifferentAt("Spec.MaintenanceWindowStartTime") { + if resp.MaintenanceWindowStartTime != nil { + f10 := &svcapitypes.WeeklyStartTime{} + if resp.MaintenanceWindowStartTime.DayOfWeek != "" { + f10.DayOfWeek = aws.String(string(resp.MaintenanceWindowStartTime.DayOfWeek)) + } + if resp.MaintenanceWindowStartTime.TimeOfDay != nil { + f10.TimeOfDay = resp.MaintenanceWindowStartTime.TimeOfDay + } + if resp.MaintenanceWindowStartTime.TimeZone != nil { + f10.TimeZone = resp.MaintenanceWindowStartTime.TimeZone + } + ko.Spec.MaintenanceWindowStartTime = f10 + } else { + ko.Spec.MaintenanceWindowStartTime = nil } - ko.Spec.MaintenanceWindowStartTime = f10 - } else { - ko.Spec.MaintenanceWindowStartTime = nil } - if resp.SecurityGroups != nil { - ko.Spec.SecurityGroups = aws.StringSlice(resp.SecurityGroups) - } else { - ko.Spec.SecurityGroups = nil + if delta.DifferentAt("Spec.SecurityGroups") { + if resp.SecurityGroups != nil { + ko.Spec.SecurityGroups = aws.StringSlice(resp.SecurityGroups) + } else { + ko.Spec.SecurityGroups = nil + } } rm.setStatusDefaults(ko) @@ -678,98 +689,116 @@ func (rm *resourceManager) newUpdateRequestPayload( ) (*svcsdk.UpdateBrokerInput, error) { res := &svcsdk.UpdateBrokerInput{} - if r.ko.Spec.AuthenticationStrategy != nil { - res.AuthenticationStrategy = svcsdktypes.AuthenticationStrategy(*r.ko.Spec.AuthenticationStrategy) + if delta.DifferentAt("Spec.AuthenticationStrategy") { + if r.ko.Spec.AuthenticationStrategy != nil { + res.AuthenticationStrategy = svcsdktypes.AuthenticationStrategy(*r.ko.Spec.AuthenticationStrategy) + } } - if r.ko.Spec.AutoMinorVersionUpgrade != nil { - res.AutoMinorVersionUpgrade = r.ko.Spec.AutoMinorVersionUpgrade + if delta.DifferentAt("Spec.AutoMinorVersionUpgrade") { + if r.ko.Spec.AutoMinorVersionUpgrade != nil { + res.AutoMinorVersionUpgrade = r.ko.Spec.AutoMinorVersionUpgrade + } } if r.ko.Status.BrokerID != nil { res.BrokerId = r.ko.Status.BrokerID } - if r.ko.Spec.Configuration != nil { - f3 := &svcsdktypes.ConfigurationId{} - if r.ko.Spec.Configuration.ID != nil { - f3.Id = r.ko.Spec.Configuration.ID - } - if r.ko.Spec.Configuration.Revision != nil { - revisionCopy0 := *r.ko.Spec.Configuration.Revision - if revisionCopy0 > math.MaxInt32 || revisionCopy0 < math.MinInt32 { - return nil, fmt.Errorf("error: field Revision is of type int32") + if delta.DifferentAt("Spec.Configuration") { + if r.ko.Spec.Configuration != nil { + f3 := &svcsdktypes.ConfigurationId{} + if r.ko.Spec.Configuration.ID != nil { + f3.Id = r.ko.Spec.Configuration.ID } - revisionCopy := int32(revisionCopy0) - f3.Revision = &revisionCopy + if r.ko.Spec.Configuration.Revision != nil { + revisionCopy0 := *r.ko.Spec.Configuration.Revision + if revisionCopy0 > math.MaxInt32 || revisionCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Revision is of type int32") + } + revisionCopy := int32(revisionCopy0) + f3.Revision = &revisionCopy + } + res.Configuration = f3 } - res.Configuration = f3 - } - if r.ko.Spec.EngineVersion != nil { - res.EngineVersion = r.ko.Spec.EngineVersion - } - if r.ko.Spec.HostInstanceType != nil { - res.HostInstanceType = r.ko.Spec.HostInstanceType } - if r.ko.Spec.LDAPServerMetadata != nil { - f7 := &svcsdktypes.LdapServerMetadataInput{} - if r.ko.Spec.LDAPServerMetadata.Hosts != nil { - f7.Hosts = aws.ToStringSlice(r.ko.Spec.LDAPServerMetadata.Hosts) - } - if r.ko.Spec.LDAPServerMetadata.RoleBase != nil { - f7.RoleBase = r.ko.Spec.LDAPServerMetadata.RoleBase - } - if r.ko.Spec.LDAPServerMetadata.RoleName != nil { - f7.RoleName = r.ko.Spec.LDAPServerMetadata.RoleName - } - if r.ko.Spec.LDAPServerMetadata.RoleSearchMatching != nil { - f7.RoleSearchMatching = r.ko.Spec.LDAPServerMetadata.RoleSearchMatching - } - if r.ko.Spec.LDAPServerMetadata.RoleSearchSubtree != nil { - f7.RoleSearchSubtree = r.ko.Spec.LDAPServerMetadata.RoleSearchSubtree + if delta.DifferentAt("Spec.EngineVersion") { + if r.ko.Spec.EngineVersion != nil { + res.EngineVersion = r.ko.Spec.EngineVersion } - if r.ko.Spec.LDAPServerMetadata.ServiceAccountPassword != nil { - f7.ServiceAccountPassword = r.ko.Spec.LDAPServerMetadata.ServiceAccountPassword - } - if r.ko.Spec.LDAPServerMetadata.ServiceAccountUsername != nil { - f7.ServiceAccountUsername = r.ko.Spec.LDAPServerMetadata.ServiceAccountUsername - } - if r.ko.Spec.LDAPServerMetadata.UserBase != nil { - f7.UserBase = r.ko.Spec.LDAPServerMetadata.UserBase - } - if r.ko.Spec.LDAPServerMetadata.UserRoleName != nil { - f7.UserRoleName = r.ko.Spec.LDAPServerMetadata.UserRoleName - } - if r.ko.Spec.LDAPServerMetadata.UserSearchMatching != nil { - f7.UserSearchMatching = r.ko.Spec.LDAPServerMetadata.UserSearchMatching - } - if r.ko.Spec.LDAPServerMetadata.UserSearchSubtree != nil { - f7.UserSearchSubtree = r.ko.Spec.LDAPServerMetadata.UserSearchSubtree - } - res.LdapServerMetadata = f7 } - if r.ko.Spec.Logs != nil { - f8 := &svcsdktypes.Logs{} - if r.ko.Spec.Logs.Audit != nil { - f8.Audit = r.ko.Spec.Logs.Audit - } - if r.ko.Spec.Logs.General != nil { - f8.General = r.ko.Spec.Logs.General + if delta.DifferentAt("Spec.HostInstanceType") { + if r.ko.Spec.HostInstanceType != nil { + res.HostInstanceType = r.ko.Spec.HostInstanceType } - res.Logs = f8 } - if r.ko.Spec.MaintenanceWindowStartTime != nil { - f9 := &svcsdktypes.WeeklyStartTime{} - if r.ko.Spec.MaintenanceWindowStartTime.DayOfWeek != nil { - f9.DayOfWeek = svcsdktypes.DayOfWeek(*r.ko.Spec.MaintenanceWindowStartTime.DayOfWeek) + if delta.DifferentAt("Spec.LDAPServerMetadata") { + if r.ko.Spec.LDAPServerMetadata != nil { + f7 := &svcsdktypes.LdapServerMetadataInput{} + if r.ko.Spec.LDAPServerMetadata.Hosts != nil { + f7.Hosts = aws.ToStringSlice(r.ko.Spec.LDAPServerMetadata.Hosts) + } + if r.ko.Spec.LDAPServerMetadata.RoleBase != nil { + f7.RoleBase = r.ko.Spec.LDAPServerMetadata.RoleBase + } + if r.ko.Spec.LDAPServerMetadata.RoleName != nil { + f7.RoleName = r.ko.Spec.LDAPServerMetadata.RoleName + } + if r.ko.Spec.LDAPServerMetadata.RoleSearchMatching != nil { + f7.RoleSearchMatching = r.ko.Spec.LDAPServerMetadata.RoleSearchMatching + } + if r.ko.Spec.LDAPServerMetadata.RoleSearchSubtree != nil { + f7.RoleSearchSubtree = r.ko.Spec.LDAPServerMetadata.RoleSearchSubtree + } + if r.ko.Spec.LDAPServerMetadata.ServiceAccountPassword != nil { + f7.ServiceAccountPassword = r.ko.Spec.LDAPServerMetadata.ServiceAccountPassword + } + if r.ko.Spec.LDAPServerMetadata.ServiceAccountUsername != nil { + f7.ServiceAccountUsername = r.ko.Spec.LDAPServerMetadata.ServiceAccountUsername + } + if r.ko.Spec.LDAPServerMetadata.UserBase != nil { + f7.UserBase = r.ko.Spec.LDAPServerMetadata.UserBase + } + if r.ko.Spec.LDAPServerMetadata.UserRoleName != nil { + f7.UserRoleName = r.ko.Spec.LDAPServerMetadata.UserRoleName + } + if r.ko.Spec.LDAPServerMetadata.UserSearchMatching != nil { + f7.UserSearchMatching = r.ko.Spec.LDAPServerMetadata.UserSearchMatching + } + if r.ko.Spec.LDAPServerMetadata.UserSearchSubtree != nil { + f7.UserSearchSubtree = r.ko.Spec.LDAPServerMetadata.UserSearchSubtree + } + res.LdapServerMetadata = f7 } - if r.ko.Spec.MaintenanceWindowStartTime.TimeOfDay != nil { - f9.TimeOfDay = r.ko.Spec.MaintenanceWindowStartTime.TimeOfDay + } + if delta.DifferentAt("Spec.Logs") { + if r.ko.Spec.Logs != nil { + f8 := &svcsdktypes.Logs{} + if r.ko.Spec.Logs.Audit != nil { + f8.Audit = r.ko.Spec.Logs.Audit + } + if r.ko.Spec.Logs.General != nil { + f8.General = r.ko.Spec.Logs.General + } + res.Logs = f8 } - if r.ko.Spec.MaintenanceWindowStartTime.TimeZone != nil { - f9.TimeZone = r.ko.Spec.MaintenanceWindowStartTime.TimeZone + } + if delta.DifferentAt("Spec.MaintenanceWindowStartTime") { + if r.ko.Spec.MaintenanceWindowStartTime != nil { + f9 := &svcsdktypes.WeeklyStartTime{} + if r.ko.Spec.MaintenanceWindowStartTime.DayOfWeek != nil { + f9.DayOfWeek = svcsdktypes.DayOfWeek(*r.ko.Spec.MaintenanceWindowStartTime.DayOfWeek) + } + if r.ko.Spec.MaintenanceWindowStartTime.TimeOfDay != nil { + f9.TimeOfDay = r.ko.Spec.MaintenanceWindowStartTime.TimeOfDay + } + if r.ko.Spec.MaintenanceWindowStartTime.TimeZone != nil { + f9.TimeZone = r.ko.Spec.MaintenanceWindowStartTime.TimeZone + } + res.MaintenanceWindowStartTime = f9 } - res.MaintenanceWindowStartTime = f9 } - if r.ko.Spec.SecurityGroups != nil { - res.SecurityGroups = aws.ToStringSlice(r.ko.Spec.SecurityGroups) + if delta.DifferentAt("Spec.SecurityGroups") { + if r.ko.Spec.SecurityGroups != nil { + res.SecurityGroups = aws.ToStringSlice(r.ko.Spec.SecurityGroups) + } } return res, nil diff --git a/templates/hooks/delta_pre_compare.go.tpl b/templates/hooks/delta_pre_compare.go.tpl new file mode 100644 index 0000000..442af27 --- /dev/null +++ b/templates/hooks/delta_pre_compare.go.tpl @@ -0,0 +1,3 @@ +// MQ sets the patch version of the engine. For example when using 3.13 in the spec +// MQ will use the latest available patch version. +reconcileEngineVersion(a, b) \ No newline at end of file diff --git a/test/e2e/bootstrap_resources.py b/test/e2e/bootstrap_resources.py index aee47fd..6e7c910 100644 --- a/test/e2e/bootstrap_resources.py +++ b/test/e2e/bootstrap_resources.py @@ -23,7 +23,7 @@ @dataclass class BootstrapResources(Resources): - pass + BrokerVpc: VPC _bootstrap_resources = None diff --git a/test/e2e/requirements.txt b/test/e2e/requirements.txt index 1dfc96c..14af9f1 100644 --- a/test/e2e/requirements.txt +++ b/test/e2e/requirements.txt @@ -1 +1 @@ -acktest @ git+https://github.com/aws-controllers-k8s/test-infra.git@441e21f888c20d6207a1fb813e4c6848128f3043 \ No newline at end of file +acktest @ git+https://github.com/aws-controllers-k8s/test-infra.git@098144245704c500a53a15804b0b33e940bee800 \ No newline at end of file diff --git a/test/e2e/resources/broker_rabbitmq_non_public.yaml b/test/e2e/resources/broker_rabbitmq_non_public.yaml index 6cd8791..7d602c6 100644 --- a/test/e2e/resources/broker_rabbitmq_non_public.yaml +++ b/test/e2e/resources/broker_rabbitmq_non_public.yaml @@ -10,6 +10,10 @@ spec: engineVersion: "$MQ_RABBITMQ_ENGINE_VERSION" hostInstanceType: $MQ_HOST_INSTANCE_TYPE publiclyAccessible: false + maintenanceWindowStartTime: + dayOfWeek: MONDAY + timeOfDay: "22:00" + timeZone: UTC users: - password: namespace: $ADMIN_USER_PASS_SECRET_NAMESPACE diff --git a/test/e2e/resources/broker_rabbitmq_security_group.yaml b/test/e2e/resources/broker_rabbitmq_security_group.yaml new file mode 100644 index 0000000..718c656 --- /dev/null +++ b/test/e2e/resources/broker_rabbitmq_security_group.yaml @@ -0,0 +1,26 @@ +apiVersion: mq.services.k8s.aws/v1alpha1 +kind: Broker +metadata: + name: $BROKER_NAME +spec: + name: $BROKER_NAME + autoMinorVersionUpgrade: true + deploymentMode: SINGLE_INSTANCE + engineType: RabbitMQ + engineVersion: "$MQ_RABBITMQ_ENGINE_VERSION" + hostInstanceType: $MQ_HOST_INSTANCE_TYPE + publiclyAccessible: false + securityGroups: + - $SECURITY_GROUP_ID + subnetIDs: + - $SUBNET_ID + users: + - password: + namespace: $ADMIN_USER_PASS_SECRET_NAMESPACE + name: $ADMIN_USER_PASS_SECRET_NAME + key: $ADMIN_USER_PASS_SECRET_KEY + groups: [] + consoleAccess: true + username: admin + tags: + key1: value1 diff --git a/test/e2e/service_bootstrap.py b/test/e2e/service_bootstrap.py index befd7a8..4283d0a 100644 --- a/test/e2e/service_bootstrap.py +++ b/test/e2e/service_bootstrap.py @@ -16,6 +16,7 @@ import logging from time import sleep +from acktest.bootstrapping import BootstrapFailureException from acktest.bootstrapping.vpc import VPC from e2e import bootstrap_directory from e2e.bootstrap_resources import BootstrapResources @@ -23,7 +24,15 @@ def service_bootstrap() -> dict: logging.getLogger().setLevel(logging.INFO) - resources = BootstrapResources() + resources = BootstrapResources( + BrokerVpc=VPC("broker-vpc", num_private_subnet=1) + ) + + try: + resources.bootstrap() + except BootstrapFailureException as ex: + exit(254) + return resources if __name__ == "__main__": diff --git a/test/e2e/tests/test_broker.py b/test/e2e/tests/test_broker.py index f1b739a..2e49260 100644 --- a/test/e2e/tests/test_broker.py +++ b/test/e2e/tests/test_broker.py @@ -23,6 +23,7 @@ from acktest.resources import random_suffix_name from acktest.k8s import resource as k8s +from acktest.k8s import condition from e2e.bootstrap_resources import get_bootstrap_resources from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_mq_resource @@ -36,6 +37,8 @@ # longer appearing in the AMQ API... DELETE_TIMEOUT_SECONDS = 300 +UPDATE_WAITE_INTERVAL_SLEEP_SECONDS = 20 + CREATE_INTERVAL_SLEEP_SECONDS = 30 # Time to wait before we get to an expected RUNNING state. # In my experience, it regularly takes more than 6 minutes to create a @@ -47,6 +50,23 @@ def amq_client(): return boto3.client('mq') +def wait_till_deleted(broker_id: str): + amq_client = boto3.client('mq') + now = datetime.datetime.now() + timeout = now + datetime.timedelta(seconds=DELETE_TIMEOUT_SECONDS) + + while True: + if datetime.datetime.now() >= timeout: + pytest.fail("Timed out waiting for ES Domain to being deleted in AES API") + time.sleep(DELETE_WAIT_INTERVAL_SLEEP_SECONDS) + + try: + aws_res = amq_client.describe_broker(BrokerId=broker_id) + if aws_res['BrokerState'] != "DELETION_IN_PROGRESS": + pytest.fail("BrokerState is not DELETION_IN_PROGRESS for broker that was deleted. BrokerState is "+aws_res['BrokerState']) + except amq_client.exceptions.NotFoundException: + break + #TODO(a-hilaly): Move to test-infra def wait_for_cr_status( @@ -78,48 +98,139 @@ def wait_for_cr_status( @pytest.fixture(scope="module") def admin_user_pass_secret(): ns = "default" - name = "dbsecrets" + name = random_suffix_name("dbsecrets", 24) key = "admin_user_password" secret_val = "adminpassneeds12chars" k8s.create_opaque_secret(ns, name, key, secret_val) yield ns, name, key k8s.delete_secret(ns, name) +@pytest.fixture(scope="module") +def test_broker_nonpublic(admin_user_pass_secret): + resource_name = random_suffix_name("my-rabbit-broker-non-public", 32) + aup_sec_ns, aup_sec_name, aup_sec_key = admin_user_pass_secret + + replacements = REPLACEMENT_VALUES.copy() + replacements["BROKER_NAME"] = resource_name + replacements["ADMIN_USER_PASS_SECRET_NAMESPACE"] = aup_sec_ns + replacements["ADMIN_USER_PASS_SECRET_NAME"] = aup_sec_name + replacements["ADMIN_USER_PASS_SECRET_KEY"] = aup_sec_key + + resource_data = load_mq_resource( + "broker_rabbitmq_non_public", + additional_replacements=replacements, + ) + logging.error(resource_data) + + # Create the k8s resource + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + resource_name, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + cr = k8s.wait_resource_consumed_by_controller(ref) + + assert cr is not None + + broker_id = cr['status']['brokerID'] + + yield ref, cr, broker_id + + try: + _, deleted = k8s.delete_custom_resource(ref, 3, 10) + assert deleted + time.sleep(DELETE_WAIT_AFTER_SECONDS) + except: + pass + + wait_till_deleted(broker_id) + +@pytest.fixture(scope="module") +def test_broker_with_security_group(admin_user_pass_secret): + resource_name = random_suffix_name("rabbitmq-security-group", 32) + aup_sec_ns, aup_sec_name, aup_sec_key = admin_user_pass_secret + broker_vpc = get_bootstrap_resources().BrokerVpc + subnet_id = broker_vpc.private_subnets.subnet_ids[0] + security_group_id = broker_vpc.security_group.group_id + + + replacements = REPLACEMENT_VALUES.copy() + replacements["BROKER_NAME"] = resource_name + replacements["ADMIN_USER_PASS_SECRET_NAMESPACE"] = aup_sec_ns + replacements["ADMIN_USER_PASS_SECRET_NAME"] = aup_sec_name + replacements["ADMIN_USER_PASS_SECRET_KEY"] = aup_sec_key + replacements["SUBNET_ID"] = subnet_id + replacements["SECURITY_GROUP_ID"] = security_group_id + + resource_data = load_mq_resource( + "broker_rabbitmq_security_group", + additional_replacements=replacements, + ) + logging.error(resource_data) + + # Create the k8s resource + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + resource_name, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + cr = k8s.wait_resource_consumed_by_controller(ref) + + + assert cr is not None + broker_id = cr['status']['brokerID'] + + yield ref, cr, broker_id, security_group_id + + try: + _, deleted = k8s.delete_custom_resource(ref, 3, 10) + assert deleted + time.sleep(DELETE_WAIT_AFTER_SECONDS) + except: + pass + + wait_till_deleted(broker_id) + + + @service_marker @pytest.mark.canary class TestRabbitMQBroker: - def test_create_delete_non_public( - self, - amq_client, - admin_user_pass_secret, - ): - resource_name = random_suffix_name("my-rabbit-broker-non-public", 32) - aup_sec_ns, aup_sec_name, aup_sec_key = admin_user_pass_secret - - replacements = REPLACEMENT_VALUES.copy() - replacements["BROKER_NAME"] = resource_name - replacements["ADMIN_USER_PASS_SECRET_NAMESPACE"] = aup_sec_ns - replacements["ADMIN_USER_PASS_SECRET_NAME"] = aup_sec_name - replacements["ADMIN_USER_PASS_SECRET_KEY"] = aup_sec_key - - resource_data = load_mq_resource( - "broker_rabbitmq_non_public", - additional_replacements=replacements, - ) - logging.error(resource_data) + def test_rabbitmq_nondefault_security_group(self, amq_client, test_broker_with_security_group): + ref, cr, broker_id, security_group_id = test_broker_with_security_group + # Let's check that the Broker appears in AmazonMQ + aws_res = amq_client.describe_broker(BrokerId=broker_id) + assert aws_res is not None - # Create the k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", + wait_for_cr_status( + ref, + "brokerState", + "RUNNING", + CREATE_INTERVAL_SLEEP_SECONDS, + 45, ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - assert cr is not None + # Verify that the ACK resource has successfully synced + condition.assert_synced(ref) - broker_id = cr['status']['brokerID'] + latest_res = k8s.get_resource(ref) + assert len(latest_res['spec']['securityGroups']) == 1 + assert latest_res['spec']['securityGroups'][0] == security_group_id + + broker = amq_client.describe_broker(BrokerId=broker_id) + assert broker['SecurityGroups'] is not None + assert len(broker['SecurityGroups']) == 1 + assert broker['SecurityGroups'][0] == security_group_id + + + + def test_crud_non_public( + self, + amq_client, + test_broker_nonpublic, + ): + ref, cr, broker_id = test_broker_nonpublic # Let's check that the Broker appears in AmazonMQ aws_res = amq_client.describe_broker(BrokerId=broker_id) @@ -133,6 +244,10 @@ def test_create_delete_non_public( 45, ) + # Verify that the ACK resource has successfully synced + condition.assert_synced(ref) + + # At this point, there should be at least one BrokerInstance record in # the Broker.Status.BrokerInstances collection which we can grab an # endpoint from. @@ -141,23 +256,49 @@ def test_create_delete_non_public( assert len(latest_res['status']['brokerInstances']) == 1 assert len(latest_res['status']['brokerInstances'][0]['endpoints']) > 0 - # Delete the k8s resource on teardown of the module - k8s.delete_custom_resource(ref) + assert latest_res["spec"]["maintenanceWindowStartTime"] is not None + assert latest_res["spec"]["maintenanceWindowStartTime"]["dayOfWeek"] == "MONDAY" + assert latest_res["spec"]["maintenanceWindowStartTime"]["timeOfDay"] == "22:00" + assert latest_res["spec"]["maintenanceWindowStartTime"]["timeZone"] == "UTC" + + + # Update the broker's maintenance window + maintenance_window_patch = { + "spec": { + "maintenanceWindowStartTime": { + "dayOfWeek": "TUESDAY", + "timeOfDay": "02:00", + "timeZone": "UTC", + } + } + } + + k8s.patch_custom_resource(ref, maintenance_window_patch) + time.sleep(UPDATE_WAITE_INTERVAL_SLEEP_SECONDS) + + assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=5) + + updated_res = k8s.get_resource(ref) + assert updated_res["spec"]["maintenanceWindowStartTime"] is not None + assert updated_res["spec"]["maintenanceWindowStartTime"]["dayOfWeek"] == "TUESDAY" + assert updated_res["spec"]["maintenanceWindowStartTime"]["timeOfDay"] == "02:00" + assert updated_res["spec"]["maintenanceWindowStartTime"]["timeZone"] == "UTC" + + updated_broker = amq_client.describe_broker(BrokerId=broker_id) + assert updated_broker['MaintenanceWindowStartTime'] is not None + assert updated_broker['MaintenanceWindowStartTime']['DayOfWeek'] == "TUESDAY" + assert updated_broker['MaintenanceWindowStartTime']['TimeOfDay'] == "02:00" + assert updated_broker['MaintenanceWindowStartTime']['TimeZone'] == "UTC" + + # Double check that other spec fields have not being set to nil. + assert updated_res["spec"]["deploymentMode"] == "SINGLE_INSTANCE" + + + + + + + + - time.sleep(DELETE_WAIT_AFTER_SECONDS) - now = datetime.datetime.now() - timeout = now + datetime.timedelta(seconds=DELETE_TIMEOUT_SECONDS) - - # Broker should no longer appear in AmazonMQ - while True: - if datetime.datetime.now() >= timeout: - pytest.fail("Timed out waiting for ES Domain to being deleted in AES API") - time.sleep(DELETE_WAIT_INTERVAL_SLEEP_SECONDS) - - try: - aws_res = amq_client.describe_broker(BrokerId=broker_id) - if aws_res['BrokerState'] != "DELETION_IN_PROGRESS": - pytest.fail("BrokerState is not DELETION_IN_PROGRESS for broker that was deleted. BrokerState is "+aws_res['BrokerState']) - except amq_client.exceptions.NotFoundException: - break