diff --git a/pkg/resource/domain/descriptor.go b/pkg/resource/domain/descriptor.go index 2bcfa1b..0f93c98 100644 --- a/pkg/resource/domain/descriptor.go +++ b/pkg/resource/domain/descriptor.go @@ -28,7 +28,7 @@ import ( ) const ( - finalizerString = "finalizers.opensearchservice.services.k8s.aws/Domain" + FinalizerString = "finalizers.opensearchservice.services.k8s.aws/Domain" ) var ( @@ -88,8 +88,8 @@ func (d *resourceDescriptor) IsManaged( // https://github.com/kubernetes-sigs/controller-runtime/issues/994 is // fixed. This should be able to be: // - // return k8sctrlutil.ContainsFinalizer(obj, finalizerString) - return containsFinalizer(obj, finalizerString) + // return k8sctrlutil.ContainsFinalizer(obj, FinalizerString) + return containsFinalizer(obj, FinalizerString) } // Remove once https://github.com/kubernetes-sigs/controller-runtime/issues/994 @@ -118,7 +118,7 @@ func (d *resourceDescriptor) MarkManaged( // Should not happen. If it does, there is a bug in the code panic("nil RuntimeMetaObject in AWSResource") } - k8sctrlutil.AddFinalizer(obj, finalizerString) + k8sctrlutil.AddFinalizer(obj, FinalizerString) } // MarkUnmanaged removes the supplied resource from management by ACK. What @@ -133,7 +133,7 @@ func (d *resourceDescriptor) MarkUnmanaged( // Should not happen. If it does, there is a bug in the code panic("nil RuntimeMetaObject in AWSResource") } - k8sctrlutil.RemoveFinalizer(obj, finalizerString) + k8sctrlutil.RemoveFinalizer(obj, FinalizerString) } // MarkAdopted places descriptors on the custom resource that indicate the diff --git a/pkg/resource/domain/hooks.go b/pkg/resource/domain/hooks.go index 6d7e3e5..bb4805a 100644 --- a/pkg/resource/domain/hooks.go +++ b/pkg/resource/domain/hooks.go @@ -16,6 +16,8 @@ package domain import ( "context" "errors" + "strings" + "github.com/aws-controllers-k8s/opensearchservice-controller/apis/v1alpha1" ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" @@ -33,6 +35,7 @@ var ( errors.New("domain is currently processing changes, cannot be modified or deleted."), ackrequeue.DefaultRequeueAfterDuration, ) + noAutoTuneInstances = []string{"t2", "t3"} ) // domainProcessing returns true if the supplied domain is in a state of @@ -44,6 +47,19 @@ func domainProcessing(r *resource) bool { return *r.ko.Status.Processing } +// isAutoTuneSupported returns true if instance type supports AutoTune +// https://docs.aws.amazon.com/opensearch-service/latest/developerguide/supported-instance-types.html +func isAutoTuneSupported(r *resource) bool { + if r.ko.Spec.ClusterConfig != nil && r.ko.Spec.ClusterConfig.InstanceType != nil { + for _, v := range noAutoTuneInstances { + if strings.HasPrefix(*r.ko.Spec.ClusterConfig.InstanceType, v) { + return false + } + } + } + return true +} + func (rm *resourceManager) customUpdateDomain(ctx context.Context, desired, latest *resource, delta *ackcompare.Delta) (updated *resource, err error) { rlog := ackrtlog.FromContext(ctx) @@ -179,6 +195,7 @@ func (rm *resourceManager) customUpdateDomain(ctx context.Context, desired, late } ko.Spec.AutoTuneOptions = &v1alpha1.AutoTuneOptionsInput{ DesiredState: resp.DomainConfig.AutoTuneOptions.Options.DesiredState, + UseOffPeakWindow: resp.DomainConfig.AutoTuneOptions.Options.UseOffPeakWindow, MaintenanceSchedules: maintSchedules, } } else { @@ -198,17 +215,18 @@ func (rm *resourceManager) customUpdateDomain(ctx context.Context, desired, late } } ko.Spec.ClusterConfig = &v1alpha1.ClusterConfig{ - ColdStorageOptions: csOptions, - DedicatedMasterCount: resp.DomainConfig.ClusterConfig.Options.DedicatedMasterCount, - DedicatedMasterEnabled: resp.DomainConfig.ClusterConfig.Options.DedicatedMasterEnabled, - DedicatedMasterType: resp.DomainConfig.ClusterConfig.Options.DedicatedMasterType, - InstanceCount: resp.DomainConfig.ClusterConfig.Options.InstanceCount, - InstanceType: resp.DomainConfig.ClusterConfig.Options.InstanceType, - WarmCount: resp.DomainConfig.ClusterConfig.Options.WarmCount, - WarmEnabled: resp.DomainConfig.ClusterConfig.Options.WarmEnabled, - WarmType: resp.DomainConfig.ClusterConfig.Options.WarmType, - ZoneAwarenessConfig: zaConfig, - ZoneAwarenessEnabled: resp.DomainConfig.ClusterConfig.Options.ZoneAwarenessEnabled, + ColdStorageOptions: csOptions, + DedicatedMasterCount: resp.DomainConfig.ClusterConfig.Options.DedicatedMasterCount, + DedicatedMasterEnabled: resp.DomainConfig.ClusterConfig.Options.DedicatedMasterEnabled, + DedicatedMasterType: resp.DomainConfig.ClusterConfig.Options.DedicatedMasterType, + InstanceCount: resp.DomainConfig.ClusterConfig.Options.InstanceCount, + InstanceType: resp.DomainConfig.ClusterConfig.Options.InstanceType, + WarmCount: resp.DomainConfig.ClusterConfig.Options.WarmCount, + WarmEnabled: resp.DomainConfig.ClusterConfig.Options.WarmEnabled, + WarmType: resp.DomainConfig.ClusterConfig.Options.WarmType, + ZoneAwarenessConfig: zaConfig, + ZoneAwarenessEnabled: resp.DomainConfig.ClusterConfig.Options.ZoneAwarenessEnabled, + MultiAZWithStandbyEnabled: resp.DomainConfig.ClusterConfig.Options.MultiAZWithStandbyEnabled, } } else { ko.Spec.ClusterConfig = nil @@ -258,6 +276,11 @@ func (rm *resourceManager) customUpdateDomain(ctx context.Context, desired, late } else { ko.Spec.EngineVersion = nil } + if resp.DomainConfig.IPAddressType != nil { + ko.Spec.IPAddressType = resp.DomainConfig.IPAddressType.Options + } else { + ko.Spec.IPAddressType = nil + } if resp.DomainConfig.NodeToNodeEncryptionOptions != nil { ko.Spec.NodeToNodeEncryptionOptions = &v1alpha1.NodeToNodeEncryptionOptions{ Enabled: resp.DomainConfig.NodeToNodeEncryptionOptions.Options.Enabled, @@ -265,6 +288,41 @@ func (rm *resourceManager) customUpdateDomain(ctx context.Context, desired, late } else { ko.Spec.NodeToNodeEncryptionOptions = nil } + if resp.DomainConfig.SoftwareUpdateOptions != nil { + ko.Spec.SoftwareUpdateOptions = &v1alpha1.SoftwareUpdateOptions{ + AutoSoftwareUpdateEnabled: resp.DomainConfig.SoftwareUpdateOptions.Options.AutoSoftwareUpdateEnabled, + } + } else { + ko.Spec.SoftwareUpdateOptions = nil + } + if resp.DomainConfig.AIMLOptions != nil && resp.DomainConfig.AIMLOptions.Options != nil { + if resp.DomainConfig.AIMLOptions.Options.NaturalLanguageQueryGenerationOptions != nil { + ko.Spec.AIMLOptions = &v1alpha1.AIMLOptionsInput{ + NATuralLanguageQueryGenerationOptions: &v1alpha1.NATuralLanguageQueryGenerationOptionsInput{ + DesiredState: resp.DomainConfig.AIMLOptions.Options.NaturalLanguageQueryGenerationOptions.DesiredState, + }, + } + } + } else { + ko.Spec.AIMLOptions = nil + } + if resp.DomainConfig.OffPeakWindowOptions != nil && resp.DomainConfig.OffPeakWindowOptions.Options != nil { + var offPeakWindow *v1alpha1.OffPeakWindow + if resp.DomainConfig.OffPeakWindowOptions.Options.OffPeakWindow != nil { + offPeakWindow = &v1alpha1.OffPeakWindow{ + WindowStartTime: &v1alpha1.WindowStartTime{ + Hours: resp.DomainConfig.OffPeakWindowOptions.Options.OffPeakWindow.WindowStartTime.Hours, + Minutes: resp.DomainConfig.OffPeakWindowOptions.Options.OffPeakWindow.WindowStartTime.Minutes, + }, + } + } + ko.Spec.OffPeakWindowOptions = &v1alpha1.OffPeakWindowOptions{ + Enabled: resp.DomainConfig.OffPeakWindowOptions.Options.Enabled, + OffPeakWindow: offPeakWindow, + } + } else { + ko.Spec.OffPeakWindowOptions = nil + } rm.setStatusDefaults(ko) @@ -370,6 +428,9 @@ func (rm *resourceManager) newCustomUpdateRequestPayload( if desired.ko.Spec.AutoTuneOptions.DesiredState != nil { f3.SetDesiredState(*desired.ko.Spec.AutoTuneOptions.DesiredState) } + if desired.ko.Spec.AutoTuneOptions.UseOffPeakWindow != nil { + f3.SetUseOffPeakWindow(*desired.ko.Spec.AutoTuneOptions.UseOffPeakWindow) + } if desired.ko.Spec.AutoTuneOptions.MaintenanceSchedules != nil { f3f1 := []*svcsdk.AutoTuneMaintenanceSchedule{} for _, f3f1iter := range desired.ko.Spec.AutoTuneOptions.MaintenanceSchedules { @@ -440,6 +501,9 @@ func (rm *resourceManager) newCustomUpdateRequestPayload( if desired.ko.Spec.ClusterConfig.ZoneAwarenessEnabled != nil { f4.SetZoneAwarenessEnabled(*desired.ko.Spec.ClusterConfig.ZoneAwarenessEnabled) } + if desired.ko.Spec.ClusterConfig.MultiAZWithStandbyEnabled != nil { + f4.SetMultiAZWithStandbyEnabled(*desired.ko.Spec.ClusterConfig.MultiAZWithStandbyEnabled) + } res.SetClusterConfig(f4) } @@ -557,5 +621,51 @@ func (rm *resourceManager) newCustomUpdateRequestPayload( res.SetVPCOptions(f14) } + if desired.ko.Spec.IPAddressType != nil && delta.DifferentAt("Spec.IPAddressType") { + res.SetIPAddressType(*desired.ko.Spec.IPAddressType) + } + + if desired.ko.Spec.SoftwareUpdateOptions != nil && delta.DifferentAt("Spec.SoftwareUpdateOptions") { + f15 := &svcsdk.SoftwareUpdateOptions{} + if desired.ko.Spec.SoftwareUpdateOptions.AutoSoftwareUpdateEnabled != nil { + f15.SetAutoSoftwareUpdateEnabled(*desired.ko.Spec.SoftwareUpdateOptions.AutoSoftwareUpdateEnabled) + } + res.SetSoftwareUpdateOptions(f15) + } + + if desired.ko.Spec.AIMLOptions != nil && delta.DifferentAt("Spec.AIMLOptions") { + f16 := &svcsdk.AIMLOptionsInput_{} + if desired.ko.Spec.AIMLOptions.NATuralLanguageQueryGenerationOptions != nil { + f16f0 := &svcsdk.NaturalLanguageQueryGenerationOptionsInput_{} + if desired.ko.Spec.AIMLOptions.NATuralLanguageQueryGenerationOptions.DesiredState != nil { + f16f0.SetDesiredState(*desired.ko.Spec.AIMLOptions.NATuralLanguageQueryGenerationOptions.DesiredState) + } + f16.SetNaturalLanguageQueryGenerationOptions(f16f0) + } + res.SetAIMLOptions(f16) + } + + if desired.ko.Spec.OffPeakWindowOptions != nil && delta.DifferentAt("Spec.OffPeakWindowOptions") { + f17 := &svcsdk.OffPeakWindowOptions{} + if desired.ko.Spec.OffPeakWindowOptions.Enabled != nil { + f17.SetEnabled(*desired.ko.Spec.OffPeakWindowOptions.Enabled) + } + if desired.ko.Spec.OffPeakWindowOptions.OffPeakWindow != nil { + f17f1 := &svcsdk.OffPeakWindow{} + if desired.ko.Spec.OffPeakWindowOptions.OffPeakWindow.WindowStartTime != nil { + f17f1f1 := &svcsdk.WindowStartTime{} + if desired.ko.Spec.OffPeakWindowOptions.OffPeakWindow.WindowStartTime.Hours != nil { + f17f1f1.SetHours(*desired.ko.Spec.OffPeakWindowOptions.OffPeakWindow.WindowStartTime.Hours) + } + if desired.ko.Spec.OffPeakWindowOptions.OffPeakWindow.WindowStartTime.Minutes != nil { + f17f1f1.SetMinutes(*desired.ko.Spec.OffPeakWindowOptions.OffPeakWindow.WindowStartTime.Minutes) + } + f17f1.SetWindowStartTime(f17f1f1) + } + f17.SetOffPeakWindow(f17f1) + } + res.SetOffPeakWindowOptions(f17) + } + return res, nil } diff --git a/pkg/resource/domain/sdk.go b/pkg/resource/domain/sdk.go index b533358..5ab4d2c 100644 --- a/pkg/resource/domain/sdk.go +++ b/pkg/resource/domain/sdk.go @@ -553,6 +553,16 @@ func (rm *resourceManager) sdkFind( } rm.setStatusDefaults(ko) + if resp.DomainStatus.AutoTuneOptions != nil && resp.DomainStatus.AutoTuneOptions.State != nil { + if *resp.DomainStatus.AutoTuneOptions.State == "ERROR" && !isAutoTuneSupported(&resource{ko}) { + // t2,t3 instances does not support AutoTuneOptions.DesiredState: DISABLED + // set value manually to remove delta + ko.Spec.AutoTuneOptions.DesiredState = aws.String("DISABLED") + } else { + ko.Spec.AutoTuneOptions.DesiredState = resp.DomainStatus.AutoTuneOptions.State + } + } + if domainProcessing(&resource{ko}) { // Setting resource synced condition to false will trigger a requeue of // the resource. No need to return a requeue error here. @@ -1079,6 +1089,16 @@ func (rm *resourceManager) sdkCreate( } rm.setStatusDefaults(ko) + if resp.DomainStatus.AutoTuneOptions != nil && resp.DomainStatus.AutoTuneOptions.State != nil { + if *resp.DomainStatus.AutoTuneOptions.State == "ERROR" && !isAutoTuneSupported(&resource{ko}) { + // t2,t3 instances does not support AutoTuneOptions.DesiredState: DISABLED + // set value manually to remove delta + ko.Spec.AutoTuneOptions.DesiredState = aws.String("DISABLED") + } else { + ko.Spec.AutoTuneOptions.DesiredState = resp.DomainStatus.AutoTuneOptions.State + } + } + if domainProcessing(&resource{ko}) { // Setting resource synced condition to false will trigger a requeue of // the resource. No need to return a requeue error here. diff --git a/templates/hooks/domain/sdk_create_post_set_output.go.tpl b/templates/hooks/domain/sdk_create_post_set_output.go.tpl index 95f6342..f562810 100644 --- a/templates/hooks/domain/sdk_create_post_set_output.go.tpl +++ b/templates/hooks/domain/sdk_create_post_set_output.go.tpl @@ -1,3 +1,13 @@ + if resp.DomainStatus.AutoTuneOptions != nil && resp.DomainStatus.AutoTuneOptions.State != nil { + if *resp.DomainStatus.AutoTuneOptions.State == "ERROR" && !isAutoTuneSupported(&resource{ko}){ + // t2,t3 instances does not support AutoTuneOptions.DesiredState: DISABLED + // set value manually to remove delta + ko.Spec.AutoTuneOptions.DesiredState = aws.String("DISABLED") + } else { + ko.Spec.AutoTuneOptions.DesiredState = resp.DomainStatus.AutoTuneOptions.State + } + } + if domainProcessing(&resource{ko}) { // Setting resource synced condition to false will trigger a requeue of // the resource. No need to return a requeue error here. diff --git a/templates/hooks/domain/sdk_read_one_post_set_output.go.tpl b/templates/hooks/domain/sdk_read_one_post_set_output.go.tpl index 9739e50..a99808f 100644 --- a/templates/hooks/domain/sdk_read_one_post_set_output.go.tpl +++ b/templates/hooks/domain/sdk_read_one_post_set_output.go.tpl @@ -1,3 +1,13 @@ + if resp.DomainStatus.AutoTuneOptions != nil && resp.DomainStatus.AutoTuneOptions.State != nil { + if *resp.DomainStatus.AutoTuneOptions.State == "ERROR" && !isAutoTuneSupported(&resource{ko}){ + // t2,t3 instances does not support AutoTuneOptions.DesiredState: DISABLED + // set value manually to remove delta + ko.Spec.AutoTuneOptions.DesiredState = aws.String("DISABLED") + } else { + ko.Spec.AutoTuneOptions.DesiredState = resp.DomainStatus.AutoTuneOptions.State + } + } + if domainProcessing(&resource{ko}) { // Setting resource synced condition to false will trigger a requeue of // the resource. No need to return a requeue error here. diff --git a/test/e2e/tests/test_domain.py b/test/e2e/tests/test_domain.py index f8972fd..a219a07 100644 --- a/test/e2e/tests/test_domain.py +++ b/test/e2e/tests/test_domain.py @@ -280,6 +280,60 @@ def test_create_delete_es_2d3m_multi_az_no_vpc_7_9(self, es_2d3m_multi_az_no_vpc assert cr is not None assert 'status' in cr domain.assert_endpoint(cr) + print("before:", domain.get(resource.name)) + + # modify some cluster parameters to test updates + updates = { + "spec": { + "softwareUpdateOptions": { + "autoSoftwareUpdateEnabled": True + }, + "offPeakWindowOptions": { + "enabled": True, + "offPeakWindow": { + "windowStartTime": { + "hours": 23, + "minutes": 30 + } + } + } + }, + } + # updates = { + # "spec": { + # "AutoTuneOptions": { + # "UseOffPeakWindow": False + # }, + # "ClusterConfig": { + # "MultiAZWithStandbyEnabled": False + # }, + # "OffPeakWindowOptions": { + # "Enabled": True, + # "OffPeakWindow": { + # "WindowStartTime": { + # "Hours": 23, + # "Minutes": 30 + # } + # } + # }, + # "SoftwareUpdateOptions": { + # "AutoSoftwareUpdateEnabled": True + # } + # } + # } + k8s.patch_custom_resource(ref, updates) + time.sleep(CHECK_STATUS_WAIT_SECONDS) + print("after check wait:", domain.get(resource.name)) + assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=30) + latest = domain.get(resource.name) + print("latest:", latest) + + # assert latest['DomainStatus']['AutoTuneOptions']['UseOffPeakWindow'] is False + # assert latest['DomainStatus']['ClusterConfig']['MultiAZWithStandbyEnabled'] is False + assert latest['DomainStatus']['OffPeakWindowOptions']["Enabled"] is True + assert latest['DomainStatus']['OffPeakWindowOptions']["OffPeakWindow"]["WindowStartTime"]["Hours"] == 23 + assert latest['DomainStatus']['OffPeakWindowOptions']["OffPeakWindow"]["WindowStartTime"]["Minutes"] == 30 + assert latest['DomainStatus']['SoftwareUpdateOptions']["AutoSoftwareUpdateEnabled"] is True def test_create_delete_es_2d3m_multi_az_vpc_2_subnet7_9(self, es_2d3m_multi_az_vpc_2_subnet7_9_domain): ref, resource = es_2d3m_multi_az_vpc_2_subnet7_9_domain