diff --git a/apis/clusters/v1beta1/kafka_webhook_test.go b/apis/clusters/v1beta1/kafka_webhook_test.go index 191eb2840..7653439cc 100644 --- a/apis/clusters/v1beta1/kafka_webhook_test.go +++ b/apis/clusters/v1beta1/kafka_webhook_test.go @@ -48,6 +48,10 @@ var _ = Describe("Kafka Controller", Ordered, func() { testKafkaManifest.Spec.Kraft[0].ControllerNodeCount = 4 Expect(k8sClient.Create(ctx, &testKafkaManifest)).ShouldNot(Succeed()) testKafkaManifest.Spec.Kraft[0].ControllerNodeCount = 3 + + testKafkaManifest.Spec.Version += ".1" + Expect(k8sClient.Create(ctx, &testKafkaManifest)).ShouldNot(Succeed()) + testKafkaManifest.Spec.Version = kafkaManifest.Spec.Version }) }) diff --git a/apis/clusters/v1beta1/opensearch_types.go b/apis/clusters/v1beta1/opensearch_types.go index a9a89b59f..f17badb54 100644 --- a/apis/clusters/v1beta1/opensearch_types.go +++ b/apis/clusters/v1beta1/opensearch_types.go @@ -41,7 +41,7 @@ type OpenSearchSpec struct { DataCentres []*OpenSearchDataCentre `json:"dataCentres,omitempty"` DataNodes []*OpenSearchDataNodes `json:"dataNodes,omitempty"` Dashboards []*OpenSearchDashboards `json:"opensearchDashboards,omitempty"` - ClusterManagerNodes []*ClusterManagerNodes `json:"clusterManagerNodes,omitempty"` + ClusterManagerNodes []*ClusterManagerNodes `json:"clusterManagerNodes"` ICUPlugin bool `json:"icuPlugin,omitempty"` AsynchronousSearchPlugin bool `json:"asynchronousSearchPlugin,omitempty"` KNNPlugin bool `json:"knnPlugin,omitempty"` diff --git a/apis/clusters/v1beta1/opensearch_webhook.go b/apis/clusters/v1beta1/opensearch_webhook.go index b36fc7faf..0db68fbf2 100644 --- a/apis/clusters/v1beta1/opensearch_webhook.go +++ b/apis/clusters/v1beta1/opensearch_webhook.go @@ -125,7 +125,7 @@ func (osv *openSearchValidator) ValidateCreate(ctx context.Context, obj runtime. return err } - err = dc.ValidatePrivateLink() + err = dc.ValidatePrivateLink(os.Spec.PrivateNetwork) if err != nil { return err } @@ -172,6 +172,10 @@ func (osv *openSearchValidator) ValidateUpdate(ctx context.Context, old runtime. return fmt.Errorf("cannot assert object %v to openSearch", new.GetObjectKind()) } + if os.Status.ID == "" { + return osv.ValidateCreate(ctx, os) + } + opensearchlog.Info("validate update", "name", os.Name) oldCluster := old.(*OpenSearch) @@ -271,12 +275,12 @@ type specificOpenSearchDC struct { ReplicationFactor int } -func (oss *OpenSearchDataCentre) newImmutableFields() *immutableOpenSearchDCFields { +func (osdc *OpenSearchDataCentre) newImmutableFields() *immutableOpenSearchDCFields { return &immutableOpenSearchDCFields{ - immutableDC: oss.GenericDataCentreSpec.immutableFields(), + immutableDC: osdc.GenericDataCentreSpec.immutableFields(), specificOpenSearchDC: specificOpenSearchDC{ - PrivateLink: oss.PrivateLink, - ReplicationFactor: oss.NumberOfRacks, + PrivateLink: osdc.PrivateLink, + ReplicationFactor: osdc.NumberOfRacks, }, } } @@ -311,6 +315,14 @@ func (oss *OpenSearchSpec) validateUpdate(oldSpec OpenSearchSpec) error { if err != nil { return err } + err = validateIngestNodes(oss.IngestNodes, oldSpec.IngestNodes) + if err != nil { + return err + } + err = validateClusterManagedNodes(oss.ClusterManagerNodes, oldSpec.ClusterManagerNodes) + if err != nil { + return err + } return nil } @@ -392,10 +404,13 @@ func validateDataNode(newNodes, oldNodes []*OpenSearchDataNodes) error { return nil } -func (dc *OpenSearchDataCentre) ValidatePrivateLink() error { +func (dc *OpenSearchDataCentre) ValidatePrivateLink(privateNetworkCluster bool) error { if dc.CloudProvider != models.AWSVPC && dc.PrivateLink { return models.ErrPrivateLinkSupportedOnlyForAWS } + if dc.PrivateLink && !privateNetworkCluster { + return models.ErrPrivateLinkAllowedOnlyWithPrivateNetworkCluster + } return nil } diff --git a/apis/clusters/v1beta1/opensearch_webhook_test.go b/apis/clusters/v1beta1/opensearch_webhook_test.go new file mode 100644 index 000000000..99bf1cae3 --- /dev/null +++ b/apis/clusters/v1beta1/opensearch_webhook_test.go @@ -0,0 +1,315 @@ +package v1beta1 + +import ( + "context" + "os" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/util/yaml" + + "github.com/instaclustr/operator/pkg/models" +) + +var _ = Describe("Kafka Controller", Ordered, func() { + openSearchManifest := OpenSearch{} + testOpenSearchManifest := OpenSearch{} + + It("Reading kafka manifest", func() { + yfile, err := os.ReadFile("../../../controllers/clusters/datatest/opensearch_v1beta1.yaml") + Expect(err).Should(Succeed()) + + err = yaml.Unmarshal(yfile, &openSearchManifest) + Expect(err).Should(Succeed()) + openSearchManifest.Spec.TwoFactorDelete = []*TwoFactorDelete{{Email: "emailTEST", Phone: "phoneTEST"}} + testOpenSearchManifest = openSearchManifest + }) + + ctx := context.Background() + + When("apply an OpenSearch manifest", func() { + It("should test OpenSearch creation flow", func() { + testOpenSearchManifest.Spec.TwoFactorDelete = []*TwoFactorDelete{openSearchManifest.Spec.TwoFactorDelete[0], openSearchManifest.Spec.TwoFactorDelete[0]} + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.TwoFactorDelete = openSearchManifest.Spec.TwoFactorDelete + + testOpenSearchManifest.Spec.SLATier = "some SLATier that is not supported" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.SLATier = openSearchManifest.Spec.SLATier + + testOpenSearchManifest.Spec.DataCentres = []*OpenSearchDataCentre{} + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres = openSearchManifest.Spec.DataCentres + + prevDataNode := openSearchManifest.Spec.DataNodes[0] + testOpenSearchManifest.Spec.DataNodes = []*OpenSearchDataNodes{} + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataNodes = []*OpenSearchDataNodes{prevDataNode} + + prevDC := *openSearchManifest.Spec.DataCentres[0] + testOpenSearchManifest.Spec.DataCentres[0].CloudProvider = "test" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + + testOpenSearchManifest.Spec.DataCentres[0].CloudProvider = "AWS_VPC" + testOpenSearchManifest.Spec.DataCentres[0].Region = "test" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + + testOpenSearchManifest.Spec.DataCentres[0].CloudProvider = "AZURE_AZ" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + + testOpenSearchManifest.Spec.DataCentres[0].CloudProvider = "GCP" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0] = &prevDC + + prevStringValue := openSearchManifest.Spec.DataCentres[0].ProviderAccountName + testOpenSearchManifest.Spec.DataCentres[0].ProviderAccountName = models.DefaultAccountName + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].ProviderAccountName = prevStringValue + + providerSettings := openSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0] + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings = []*CloudProviderSettings{providerSettings, providerSettings} + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings = []*CloudProviderSettings{providerSettings} + + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].ResourceGroup = "test" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + + prevStringValue = openSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].DiskEncryptionKey + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].DiskEncryptionKey = "" + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].CustomVirtualNetworkID = "test" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].ResourceGroup = "" + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].CustomVirtualNetworkID = "" + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].DiskEncryptionKey = prevStringValue + + prevStringValue = openSearchManifest.Spec.DataCentres[0].Network + testOpenSearchManifest.Spec.DataCentres[0].Network = "test/test" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].Network = prevStringValue + + testOpenSearchManifest.Spec.DataNodes[0].NodesNumber++ + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataNodes[0].NodesNumber-- + + testOpenSearchManifest.Spec.DataCentres[0].NumberOfRacks++ + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].NumberOfRacks-- + + testOpenSearchManifest.Spec.DataCentres[0].CloudProvider = "GCP" + testOpenSearchManifest.Spec.DataCentres[0].PrivateLink = true + testOpenSearchManifest.Spec.DataCentres[0].Region = "us-east1" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].CloudProvider = "AWS_VPC" + testOpenSearchManifest.Spec.DataCentres[0].Region = "US_EAST_1" + + testOpenSearchManifest.Spec.PrivateNetwork = !testOpenSearchManifest.Spec.PrivateNetwork + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].PrivateLink = false + testOpenSearchManifest.Spec.PrivateNetwork = !testOpenSearchManifest.Spec.PrivateNetwork + + testOpenSearchManifest.Spec.ResizeSettings[0].Concurrency++ + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.ResizeSettings[0].Concurrency-- + + prevManagedNode := openSearchManifest.Spec.ClusterManagerNodes[0] + testOpenSearchManifest.Spec.ClusterManagerNodes = []*ClusterManagerNodes{prevManagedNode, prevManagedNode, prevManagedNode, prevManagedNode} + testOpenSearchManifest.Spec.ResizeSettings[0].Concurrency += 3 + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.ResizeSettings[0].Concurrency -= 3 + testOpenSearchManifest.Spec.ClusterManagerNodes = []*ClusterManagerNodes{prevManagedNode} + + testOpenSearchManifest.Spec.Version += ".1" + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.Version = openSearchManifest.Spec.Version + + }) + }) + + When("updating an OpenSearch manifest", func() { + It("should test OpenSearch update flow", func() { + testOpenSearchManifest.Status.State = models.RunningStatus + Expect(k8sClient.Create(ctx, &testOpenSearchManifest)).Should(Succeed()) + + patch := testOpenSearchManifest.NewPatch() + testOpenSearchManifest.Status.ID = models.CreatedEvent + Expect(k8sClient.Status().Patch(ctx, &testOpenSearchManifest, patch)).Should(Succeed()) + + testOpenSearchManifest.Spec.Name += "newValue" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.Name = openSearchManifest.Spec.Name + + testOpenSearchManifest.Spec.BundledUseOnly = !testOpenSearchManifest.Spec.BundledUseOnly + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.BundledUseOnly = !testOpenSearchManifest.Spec.BundledUseOnly + + testOpenSearchManifest.Spec.ICUPlugin = !testOpenSearchManifest.Spec.ICUPlugin + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.ICUPlugin = !testOpenSearchManifest.Spec.ICUPlugin + + testOpenSearchManifest.Spec.AsynchronousSearchPlugin = !testOpenSearchManifest.Spec.AsynchronousSearchPlugin + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.AsynchronousSearchPlugin = !testOpenSearchManifest.Spec.AsynchronousSearchPlugin + + testOpenSearchManifest.Spec.KNNPlugin = !testOpenSearchManifest.Spec.KNNPlugin + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.KNNPlugin = !testOpenSearchManifest.Spec.KNNPlugin + + testOpenSearchManifest.Spec.ReportingPlugin = !testOpenSearchManifest.Spec.ReportingPlugin + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.ReportingPlugin = !testOpenSearchManifest.Spec.ReportingPlugin + + testOpenSearchManifest.Spec.SQLPlugin = !testOpenSearchManifest.Spec.SQLPlugin + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.SQLPlugin = !testOpenSearchManifest.Spec.SQLPlugin + + testOpenSearchManifest.Spec.NotificationsPlugin = !testOpenSearchManifest.Spec.NotificationsPlugin + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.NotificationsPlugin = !testOpenSearchManifest.Spec.NotificationsPlugin + + testOpenSearchManifest.Spec.AnomalyDetectionPlugin = !testOpenSearchManifest.Spec.AnomalyDetectionPlugin + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.AnomalyDetectionPlugin = !testOpenSearchManifest.Spec.AnomalyDetectionPlugin + + testOpenSearchManifest.Spec.LoadBalancer = !testOpenSearchManifest.Spec.LoadBalancer + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.LoadBalancer = !testOpenSearchManifest.Spec.LoadBalancer + + testOpenSearchManifest.Spec.IndexManagementPlugin = !testOpenSearchManifest.Spec.IndexManagementPlugin + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.IndexManagementPlugin = !testOpenSearchManifest.Spec.IndexManagementPlugin + + testOpenSearchManifest.Spec.AlertingPlugin = !testOpenSearchManifest.Spec.AlertingPlugin + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.AlertingPlugin = !testOpenSearchManifest.Spec.AlertingPlugin + + testOpenSearchManifest.Spec.PCICompliance = !testOpenSearchManifest.Spec.PCICompliance + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.PCICompliance = !testOpenSearchManifest.Spec.PCICompliance + + testOpenSearchManifest.Spec.PrivateNetwork = !testOpenSearchManifest.Spec.PrivateNetwork + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.PrivateNetwork = !testOpenSearchManifest.Spec.PrivateNetwork + + prevStringValue := openSearchManifest.Spec.SLATier + testOpenSearchManifest.Spec.SLATier = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.SLATier = prevStringValue + + prevTwoFactorDelete := testOpenSearchManifest.Spec.TwoFactorDelete + testOpenSearchManifest.Spec.TwoFactorDelete = []*TwoFactorDelete{prevTwoFactorDelete[0], prevTwoFactorDelete[0]} + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.TwoFactorDelete = []*TwoFactorDelete{prevTwoFactorDelete[0]} + + testOpenSearchManifest.Spec.TwoFactorDelete = []*TwoFactorDelete{} + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.TwoFactorDelete = []*TwoFactorDelete{prevTwoFactorDelete[0]} + + prevStringValue = openSearchManifest.Spec.TwoFactorDelete[0].Email + testOpenSearchManifest.Spec.TwoFactorDelete[0].Email = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.TwoFactorDelete[0].Email = prevStringValue + + prevIngestNodes := testOpenSearchManifest.Spec.IngestNodes + testOpenSearchManifest.Spec.IngestNodes = []*OpenSearchIngestNodes{prevIngestNodes[0], prevIngestNodes[0]} + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.IngestNodes = []*OpenSearchIngestNodes{prevIngestNodes[0]} + + testOpenSearchManifest.Spec.IngestNodes = []*OpenSearchIngestNodes{} + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.IngestNodes = []*OpenSearchIngestNodes{prevIngestNodes[0]} + + prevStringValue = openSearchManifest.Spec.IngestNodes[0].NodeSize + testOpenSearchManifest.Spec.IngestNodes[0].NodeSize = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.IngestNodes[0].NodeSize = prevStringValue + + prevClusterManagedNodes := testOpenSearchManifest.Spec.ClusterManagerNodes + testOpenSearchManifest.Spec.ClusterManagerNodes = []*ClusterManagerNodes{prevClusterManagedNodes[0], prevClusterManagedNodes[0]} + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.ClusterManagerNodes = []*ClusterManagerNodes{prevClusterManagedNodes[0]} + + testOpenSearchManifest.Spec.ClusterManagerNodes = []*ClusterManagerNodes{} + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.ClusterManagerNodes = []*ClusterManagerNodes{prevClusterManagedNodes[0]} + + prevStringValue = openSearchManifest.Spec.ClusterManagerNodes[0].NodeSize + testOpenSearchManifest.Spec.ClusterManagerNodes[0].NodeSize = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.ClusterManagerNodes[0].NodeSize = prevStringValue + + By("changing datacentres fields") + + prevDCs := openSearchManifest.Spec.DataCentres + testOpenSearchManifest.Spec.DataCentres = []*OpenSearchDataCentre{prevDCs[0], prevDCs[0]} + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres = []*OpenSearchDataCentre{prevDCs[0]} + + prevStringValue = prevDCs[0].Name + testOpenSearchManifest.Spec.DataCentres[0].Name = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].Name = prevStringValue + + prevStringValue = prevDCs[0].Region + testOpenSearchManifest.Spec.DataCentres[0].Region = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].Region = prevStringValue + + prevStringValue = prevDCs[0].CloudProvider + testOpenSearchManifest.Spec.DataCentres[0].CloudProvider = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].CloudProvider = prevStringValue + + prevStringValue = prevDCs[0].ProviderAccountName + testOpenSearchManifest.Spec.DataCentres[0].ProviderAccountName = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].ProviderAccountName = prevStringValue + + prevStringValue = prevDCs[0].Network + testOpenSearchManifest.Spec.DataCentres[0].Network = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].Network = prevStringValue + + testOpenSearchManifest.Spec.DataCentres[0].PrivateLink = !testOpenSearchManifest.Spec.DataCentres[0].PrivateLink + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].PrivateLink = !testOpenSearchManifest.Spec.DataCentres[0].PrivateLink + + testOpenSearchManifest.Spec.DataCentres[0].NumberOfRacks += 1 + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].NumberOfRacks -= 1 + + prevCloudProviderSettings := openSearchManifest.Spec.DataCentres[0].CloudProviderSettings + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings = []*CloudProviderSettings{prevCloudProviderSettings[0], prevCloudProviderSettings[0]} + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings = []*CloudProviderSettings{prevCloudProviderSettings[0]} + + prevStringValue = openSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].DiskEncryptionKey + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].DiskEncryptionKey = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].DiskEncryptionKey = prevStringValue + + prevStringValue = openSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].ResourceGroup + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].ResourceGroup = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].ResourceGroup = prevStringValue + + prevStringValue = openSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].CustomVirtualNetworkID + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].CustomVirtualNetworkID = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].CloudProviderSettings[0].CustomVirtualNetworkID = prevStringValue + + testOpenSearchManifest.Spec.DataCentres[0].Tags["test"] = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + delete(testOpenSearchManifest.Spec.DataCentres[0].Tags, "test") + + delete(testOpenSearchManifest.Spec.DataCentres[0].Tags, "tag") + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].Tags["tag"] = "oneTag" + + testOpenSearchManifest.Spec.DataCentres[0].Tags["tag"] = "test" + Expect(k8sClient.Patch(ctx, &testOpenSearchManifest, patch)).ShouldNot(Succeed()) + testOpenSearchManifest.Spec.DataCentres[0].Tags["tag"] = "oneTag" + + }) + + }) +}) diff --git a/apis/clusters/v1beta1/validation.go b/apis/clusters/v1beta1/validation.go index fa6461e51..fe60305d6 100644 --- a/apis/clusters/v1beta1/validation.go +++ b/apis/clusters/v1beta1/validation.go @@ -216,6 +216,30 @@ func validateTwoFactorDelete(new, old []*TwoFactorDelete) error { return nil } +func validateIngestNodes(new, old []*OpenSearchIngestNodes) error { + if len(old) != len(new) { + return models.ErrImmutableIngestNodes + } + + if *old[0] != *new[0] { + return models.ErrImmutableIngestNodes + } + + return nil +} + +func validateClusterManagedNodes(new, old []*ClusterManagerNodes) error { + if len(old) != len(new) { + return models.ErrImmutableClusterManagedNodes + } + + if *old[0] != *new[0] { + return models.ErrImmutableClusterManagedNodes + } + + return nil +} + func validateTagsUpdate(new, old map[string]string) error { if len(old) != len(new) { return models.ErrImmutableTags diff --git a/apis/clusters/v1beta1/webhook_suite_test.go b/apis/clusters/v1beta1/webhook_suite_test.go index b83da4bcf..480ada4e7 100644 --- a/apis/clusters/v1beta1/webhook_suite_test.go +++ b/apis/clusters/v1beta1/webhook_suite_test.go @@ -27,6 +27,8 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + k8sappsv1 "k8s.io/api/apps/v1" + k8scorev1 "k8s.io/api/core/v1" admissionv1beta1 "k8s.io/api/admission/v1beta1" //+kubebuilder:scaffold:imports @@ -79,6 +81,12 @@ var _ = BeforeSuite(func() { err = AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) + err = k8scorev1.AddToScheme(scheme) + Expect(err).NotTo(HaveOccurred()) + + err = k8sappsv1.AddToScheme(scheme) + Expect(err).NotTo(HaveOccurred()) + err = admissionv1beta1.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) @@ -110,7 +118,7 @@ var _ = BeforeSuite(func() { err = (&Redis{}).SetupWebhookWithManager(mgr, nil) Expect(err).NotTo(HaveOccurred()) - err = (&OpenSearch{}).SetupWebhookWithManager(mgr, nil) + err = (&OpenSearch{}).SetupWebhookWithManager(mgr, api) Expect(err).NotTo(HaveOccurred()) err = (&Kafka{}).SetupWebhookWithManager(mgr, api) diff --git a/config/crd/bases/clusters.instaclustr.com_opensearches.yaml b/config/crd/bases/clusters.instaclustr.com_opensearches.yaml index 3825b9146..11c7c6f20 100644 --- a/config/crd/bases/clusters.instaclustr.com_opensearches.yaml +++ b/config/crd/bases/clusters.instaclustr.com_opensearches.yaml @@ -264,6 +264,8 @@ spec: type: array version: type: string + required: + - clusterManagerNodes type: object status: description: OpenSearchStatus defines the observed state of OpenSearch diff --git a/controllers/clusters/datatest/kafka_v1beta1.yaml b/controllers/clusters/datatest/kafka_v1beta1.yaml index 4d73b5344..9f0668542 100644 --- a/controllers/clusters/datatest/kafka_v1beta1.yaml +++ b/controllers/clusters/datatest/kafka_v1beta1.yaml @@ -7,7 +7,7 @@ metadata: defaulter: webhook spec: name: "kafka" - version: "2.8.2" + version: 1.0.0 pciCompliance: true replicationFactor: 3 partitionsNumber: 3 diff --git a/controllers/clusters/datatest/opensearch_v1beta1.yaml b/controllers/clusters/datatest/opensearch_v1beta1.yaml index 6d40fbf88..d400d98e9 100644 --- a/controllers/clusters/datatest/opensearch_v1beta1.yaml +++ b/controllers/clusters/datatest/opensearch_v1beta1.yaml @@ -7,13 +7,17 @@ metadata: defaulter: webhook spec: alertingPlugin: false + bundledUseOnly: false anomalyDetectionPlugin: false asynchronousSearchPlugin: false +# twoFactorDelete: +# - email: "emailTEST" +# phone: "phoneTEST" # userRef: # name: test-user # namespace: default clusterManagerNodes: - - dedicatedManager: false + - dedicatedManager: true nodeSize: SRH-DEV-t4g.small-5 dataCentres: - cloudProvider: AWS_VPC @@ -22,9 +26,20 @@ spec: numberOfRacks: 3 privateLink: false region: US_EAST_1 -# dataNodes: -# - nodeNumber: 3 -# nodeSize: SRH-DEV-t4g.small-5 + accountName: "Custom" + cloudProviderSettings: + - diskEncryptionKey: "123e4567-e89b-12d3-a456-426614174000" + tags: + tag: "oneTag" + tag2: "twoTags" + resizeSettings: + - concurrency: 1 + ingestNodes: + - nodeSize: SRH-DI-PRD-m6g.large-10 + nodeCount: 3 + dataNodes: + - nodesNumber: 3 + nodeSize: SRH-DEV-t4g.small-5 icuPlugin: false indexManagementPlugin: true knnPlugin: false @@ -35,9 +50,9 @@ spec: # - nodeSize: SRH-DEV-t4g.small-5 # oidcProvider: '' # version: opensearch-dashboards:2.5.0 - version: 2.5.0 + version: 1.0.0 pciCompliance: false - privateNetworkCluster: false + privateNetwork: true reportingPlugin: false slaTier: NON_PRODUCTION sqlPlugin: false diff --git a/pkg/instaclustr/mock/appversionsmock/models.go b/pkg/instaclustr/mock/appversionsmock/models.go index efc4ed1da..9f4e9d42d 100644 --- a/pkg/instaclustr/mock/appversionsmock/models.go +++ b/pkg/instaclustr/mock/appversionsmock/models.go @@ -15,5 +15,14 @@ func NewInstAPI() *mockClient { } func (c *mockClient) ListAppVersions(app string) ([]*models.AppVersions, error) { - return []*models.AppVersions{{Application: app, Versions: []string{"1.0.0"}}}, nil + versions := []string{"1.0.0"} + + switch app { + case models.OpenSearchAppKind: + return []*models.AppVersions{{Application: models.OpenSearchAppType, Versions: versions}}, nil + case models.KafkaAppKind: + return []*models.AppVersions{{Application: models.KafkaAppType, Versions: versions}}, nil + } + + return []*models.AppVersions{{Application: app, Versions: versions}}, nil } diff --git a/pkg/models/errors.go b/pkg/models/errors.go index 3ef4b2c4a..8646a19cd 100644 --- a/pkg/models/errors.go +++ b/pkg/models/errors.go @@ -21,59 +21,62 @@ import ( ) var ( - ErrZeroDataCentres = errors.New("cluster spec doesn't have data centres") - ErrMoreThanOneKraft = errors.New("cluster spec does not support more than one kraft") - ErrMoreThanThreeControllerNodeCount = errors.New("kraft does not support more than three controller nodes") - ErrNetworkOverlaps = errors.New("cluster network overlaps") - ErrImmutableTwoFactorDelete = errors.New("twoFactorDelete field is immutable") - ErrImmutableCloudProviderSettings = errors.New("cloudProviderSettings are immutable") - ErrImmutableIntraDataCentreReplication = errors.New("intraDataCentreReplication fields are immutable") - ErrImmutableInterDataCentreReplication = errors.New("interDataCentreReplication fields are immutable") - ErrImmutableDataCentresNumber = errors.New("data centres number is immutable") - ErrImmutableAWSSecurityGroupFirewallRule = errors.New("awsSecurityGroupFirewallRule is immutable") - ErrImmutableTags = errors.New("tags field is immutable") - ErrTypeAssertion = errors.New("unable to assert type") - ErrImmutableSchemaRegistry = errors.New("schema registry is immutable") - ErrImmutableRestProxy = errors.New("rest proxy is immutable") - ErrImmutableKraft = errors.New("kraft is immutable") - ErrImmutableKarapaceSchemaRegistry = errors.New("karapace schema registry is immutable") - ErrImmutableKarapaceRestProxy = errors.New("karapace rest proxy is immutable") - ErrImmutableDedicatedZookeeper = errors.New("dedicated zookeeper nodes cannot be changed") - ErrDecreasedDataCentresNumber = errors.New("data centres number cannot be decreased") - ErrImmutableTargetCluster = errors.New("TargetCluster field is immutable") - ErrImmutableExternalCluster = errors.New("ExternalCluster field is immutable") - ErrImmutableManagedCluster = errors.New("ManagedCluster field is immutable") - ErrIncorrectDayOfWeek = errors.New("dayOfWeek field is invalid") - ErrImmutableAWSArchival = errors.New("AWSArchival array is immutable") - ErrImmutableStandardProvisioning = errors.New("StandardProvisioning array is immutable") - ErrImmutableSharedProvisioning = errors.New("SharedProvisioning array is immutable") - ErrImmutablePackagedProvisioning = errors.New("PackagedProvisioning array is immutable") - ErrImmutableAdvancedVisibility = errors.New("AdvancedVisibility array is immutable") - ErrImmutablePrivateLink = errors.New("PrivateLink array is immutable") - ErrImmutableNodesNumber = errors.New("nodes number is immutable") - ErrImmutableSecretRef = errors.New("secret reference is immutable") - ErrEmptySecretRef = errors.New("secretRef.name and secretRef.namespace should not be empty") - ErrMissingSecretKeys = errors.New("the secret is missing the correct keys for the user") - ErrUserStillExist = errors.New("the user is still attached to the cluster. If you want to delete the user, remove the user from the cluster specification first") - ErrOnlyOneEntityTwoFactorDelete = errors.New("currently only one entity of two factor delete can be filled") - ErrPrivateLinkOnlyWithPrivateNetworkCluster = errors.New("private link is available only for private network clusters") - ErrPrivateLinkSupportedOnlyForSingleDC = errors.New("private link is only supported for a single data centre") - ErrPrivateLinkSupportedOnlyForAWS = errors.New("private link is supported only for an AWS cloud provider") - ErrImmutableSpec = errors.New("resource specification is immutable") - ErrUnsupportedBackupClusterKind = errors.New("backups for provided cluster kind are not supported") - ErrUnsupportedClusterKind = errors.New("provided cluster kind is not supported") - ErrExposeServiceNotCreatedYet = errors.New("expose service is not created yet") - ErrExposeServiceEndpointsNotCreatedYet = errors.New("expose service endpoints is not created yet") - ErrOnlySingleConcurrentResizeAvailable = errors.New("only single concurrent resize is allowed") - ErrBundledUseOnlyResourceUpdateIsNotSupported = errors.New("updating of bundled use resource is not supported") - ErrDebeziumImmutable = errors.New("debezium array is immutable") - ErrShotoverProxyImmutable = errors.New("shotoverProxy array is immutable") - ErrEmptyNamespace = errors.New("namespace field is empty") - ErrEmptyName = errors.New("name field is empty") - ErrCreateClusterWithMultiDC = errors.New("multiple data center is still not supported. Please create a cluster with one data centre and add a second one when the cluster is in the running state") - ErrOnPremicesWithMultiDC = errors.New("on-premises cluster can be provisioned with only one data centre") - ErrUnsupportedDeletingDC = errors.New("deleting data centre is not supported") - ErrClusterIsNotReadyToUpdate = errors.New("cluster is not ready to update") - ErrKubeVirtAddonNotFound = errors.New("cannot create KubeVirt based resources automatially without KubeVirt operator installed. Please install KubeVirt add-on") - ErrOpenSearchNumberOfRacksInvalid = errors.New("number of racks should be between 2 and 5") + ErrZeroDataCentres = errors.New("cluster spec doesn't have data centres") + ErrMoreThanOneKraft = errors.New("cluster spec does not support more than one kraft") + ErrMoreThanThreeControllerNodeCount = errors.New("kraft does not support more than three controller nodes") + ErrNetworkOverlaps = errors.New("cluster network overlaps") + ErrImmutableTwoFactorDelete = errors.New("twoFactorDelete field is immutable") + ErrImmutableIngestNodes = errors.New("IngestNodes field is immutable") + ErrImmutableClusterManagedNodes = errors.New("ClusterManagedNodes field is immutable") + ErrImmutableCloudProviderSettings = errors.New("cloudProviderSettings are immutable") + ErrImmutableIntraDataCentreReplication = errors.New("intraDataCentreReplication fields are immutable") + ErrImmutableInterDataCentreReplication = errors.New("interDataCentreReplication fields are immutable") + ErrImmutableDataCentresNumber = errors.New("data centres number is immutable") + ErrImmutableAWSSecurityGroupFirewallRule = errors.New("awsSecurityGroupFirewallRule is immutable") + ErrImmutableTags = errors.New("tags field is immutable") + ErrTypeAssertion = errors.New("unable to assert type") + ErrImmutableSchemaRegistry = errors.New("schema registry is immutable") + ErrImmutableRestProxy = errors.New("rest proxy is immutable") + ErrImmutableKraft = errors.New("kraft is immutable") + ErrImmutableKarapaceSchemaRegistry = errors.New("karapace schema registry is immutable") + ErrImmutableKarapaceRestProxy = errors.New("karapace rest proxy is immutable") + ErrImmutableDedicatedZookeeper = errors.New("dedicated zookeeper nodes cannot be changed") + ErrDecreasedDataCentresNumber = errors.New("data centres number cannot be decreased") + ErrImmutableTargetCluster = errors.New("TargetCluster field is immutable") + ErrImmutableExternalCluster = errors.New("ExternalCluster field is immutable") + ErrImmutableManagedCluster = errors.New("ManagedCluster field is immutable") + ErrIncorrectDayOfWeek = errors.New("dayOfWeek field is invalid") + ErrImmutableAWSArchival = errors.New("AWSArchival array is immutable") + ErrImmutableStandardProvisioning = errors.New("StandardProvisioning array is immutable") + ErrImmutableSharedProvisioning = errors.New("SharedProvisioning array is immutable") + ErrImmutablePackagedProvisioning = errors.New("PackagedProvisioning array is immutable") + ErrImmutableAdvancedVisibility = errors.New("AdvancedVisibility array is immutable") + ErrImmutablePrivateLink = errors.New("PrivateLink array is immutable") + ErrImmutableNodesNumber = errors.New("nodes number is immutable") + ErrImmutableSecretRef = errors.New("secret reference is immutable") + ErrEmptySecretRef = errors.New("secretRef.name and secretRef.namespace should not be empty") + ErrMissingSecretKeys = errors.New("the secret is missing the correct keys for the user") + ErrUserStillExist = errors.New("the user is still attached to the cluster. If you want to delete the user, remove the user from the cluster specification first") + ErrOnlyOneEntityTwoFactorDelete = errors.New("currently only one entity of two factor delete can be filled") + ErrPrivateLinkOnlyWithPrivateNetworkCluster = errors.New("private link is available only for private network clusters") + ErrPrivateLinkSupportedOnlyForSingleDC = errors.New("private link is only supported for a single data centre") + ErrPrivateLinkSupportedOnlyForAWS = errors.New("private link is supported only for an AWS cloud provider") + ErrPrivateLinkAllowedOnlyWithPrivateNetworkCluster = errors.New("private link is allowed only with privateNetworkCluster field enabled") + ErrImmutableSpec = errors.New("resource specification is immutable") + ErrUnsupportedBackupClusterKind = errors.New("backups for provided cluster kind are not supported") + ErrUnsupportedClusterKind = errors.New("provided cluster kind is not supported") + ErrExposeServiceNotCreatedYet = errors.New("expose service is not created yet") + ErrExposeServiceEndpointsNotCreatedYet = errors.New("expose service endpoints is not created yet") + ErrOnlySingleConcurrentResizeAvailable = errors.New("only single concurrent resize is allowed") + ErrBundledUseOnlyResourceUpdateIsNotSupported = errors.New("updating of bundled use resource is not supported") + ErrDebeziumImmutable = errors.New("debezium array is immutable") + ErrShotoverProxyImmutable = errors.New("shotoverProxy array is immutable") + ErrEmptyNamespace = errors.New("namespace field is empty") + ErrEmptyName = errors.New("name field is empty") + ErrCreateClusterWithMultiDC = errors.New("multiple data center is still not supported. Please create a cluster with one data centre and add a second one when the cluster is in the running state") + ErrOnPremicesWithMultiDC = errors.New("on-premises cluster can be provisioned with only one data centre") + ErrUnsupportedDeletingDC = errors.New("deleting data centre is not supported") + ErrClusterIsNotReadyToUpdate = errors.New("cluster is not ready to update") + ErrKubeVirtAddonNotFound = errors.New("cannot create KubeVirt based resources automatially without KubeVirt operator installed. Please install KubeVirt add-on") + ErrOpenSearchNumberOfRacksInvalid = errors.New("number of racks should be between 2 and 5") )