From fea2d59fd850e886a84aa1f8b007e03d2ba51236 Mon Sep 17 00:00:00 2001 From: John Sanda Date: Wed, 16 Dec 2020 16:04:48 -0500 Subject: [PATCH] remove Reaper integration Removing Reaper integration because Reaper sidecar mode had too many problems that required changes in Reaper to make it work better. See https://github.com/thelastpickle/cassandra-reaper/issues/956 for details. --- .../templates/customresourcedefinition.yaml | 38 ---- ...datastax.com_cassandradatacenters_crd.yaml | 38 ---- .../v1beta1/cassandradatacenter_types.go | 20 -- .../v1beta1/zz_generated.deepcopy.go | 22 -- .../construct_podtemplatespec.go | 17 -- .../construct_podtemplatespec_test.go | 74 +------ operator/pkg/reconciliation/constructor.go | 44 ---- .../pkg/reconciliation/reconcile_racks.go | 8 - .../pkg/reconciliation/reconcile_reaper.go | 209 ------------------ .../reconciliation/reconcile_reaper_test.go | 153 ------------- .../enable_reaper/enable_reaper_suite_test.go | 108 --------- 11 files changed, 2 insertions(+), 729 deletions(-) delete mode 100644 operator/pkg/reconciliation/reconcile_reaper.go delete mode 100644 operator/pkg/reconciliation/reconcile_reaper_test.go delete mode 100644 tests/enable_reaper/enable_reaper_suite_test.go diff --git a/charts/cass-operator-chart/templates/customresourcedefinition.yaml b/charts/cass-operator-chart/templates/customresourcedefinition.yaml index 0fcf5fc5f..896e77e77 100644 --- a/charts/cass-operator-chart/templates/customresourcedefinition.yaml +++ b/charts/cass-operator-chart/templates/customresourcedefinition.yaml @@ -5950,44 +5950,6 @@ spec: - name type: object type: array - reaper: - properties: - enabled: - type: boolean - image: - type: string - imagePullPolicy: - description: PullPolicy describes a policy for if/when to pull a - container image - type: string - resources: - description: Kubernetes resource requests and limits per reaper - container. - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of compute - resources required. If Requests is omitted for a container, - it defaults to Limits if that is explicitly specified, otherwise - to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' - type: object - type: object - type: object replaceNodes: description: A list of pod names that need to be replaced. items: diff --git a/operator/deploy/crds/cassandra.datastax.com_cassandradatacenters_crd.yaml b/operator/deploy/crds/cassandra.datastax.com_cassandradatacenters_crd.yaml index 5d8a945df..83b504043 100644 --- a/operator/deploy/crds/cassandra.datastax.com_cassandradatacenters_crd.yaml +++ b/operator/deploy/crds/cassandra.datastax.com_cassandradatacenters_crd.yaml @@ -5962,44 +5962,6 @@ spec: - name type: object type: array - reaper: - properties: - enabled: - type: boolean - image: - type: string - imagePullPolicy: - description: PullPolicy describes a policy for if/when to pull a - container image - type: string - resources: - description: Kubernetes resource requests and limits per reaper - container. - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of compute - resources required. If Requests is omitted for a container, - it defaults to Limits if that is explicitly specified, otherwise - to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' - type: object - type: object - type: object replaceNodes: description: A list of pod names that need to be replaced. items: diff --git a/operator/pkg/apis/cassandra/v1beta1/cassandradatacenter_types.go b/operator/pkg/apis/cassandra/v1beta1/cassandradatacenter_types.go index 0398b79f4..4e3865ec9 100644 --- a/operator/pkg/apis/cassandra/v1beta1/cassandradatacenter_types.go +++ b/operator/pkg/apis/cassandra/v1beta1/cassandradatacenter_types.go @@ -174,8 +174,6 @@ type CassandraDatacenterSpec struct { AdditionalSeeds []string `json:"additionalSeeds,omitempty"` - Reaper *ReaperConfig `json:"reaper,omitempty"` - // Configuration for disabling the simple log tailing sidecar container. Our default is to have it enabled. DisableSystemLoggerSidecar bool `json:"disableSystemLoggerSidecar,omitempty"` @@ -359,17 +357,6 @@ type ManagementApiAuthConfig struct { // other strategy configs (e.g. Cert Manager) go here } -type ReaperConfig struct { - Enabled bool `json:"enabled,omitempty"` - - Image string `json:"image,omitempty"` - - ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` - - // Kubernetes resource requests and limits per reaper container. - Resources corev1.ResourceRequirements `json:"resources,omitempty"` -} - // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // CassandraDatacenterList contains a list of CassandraDatacenter @@ -424,13 +411,6 @@ func (dc *CassandraDatacenter) GetRackLabels(rackName string) map[string]string return labels } -func (dc *CassandraDatacenter) IsReaperEnabled() bool { - if dc.Spec.Reaper != nil && dc.Spec.Reaper.Enabled && dc.Spec.ServerType == "cassandra" { - return true - } - return false -} - func (status *CassandraDatacenterStatus) GetConditionStatus(conditionType DatacenterConditionType) corev1.ConditionStatus { for _, condition := range status.Conditions { if condition.Type == conditionType { diff --git a/operator/pkg/apis/cassandra/v1beta1/zz_generated.deepcopy.go b/operator/pkg/apis/cassandra/v1beta1/zz_generated.deepcopy.go index d95c3b8ef..979192df6 100644 --- a/operator/pkg/apis/cassandra/v1beta1/zz_generated.deepcopy.go +++ b/operator/pkg/apis/cassandra/v1beta1/zz_generated.deepcopy.go @@ -146,11 +146,6 @@ func (in *CassandraDatacenterSpec) DeepCopyInto(out *CassandraDatacenterSpec) { *out = make([]string, len(*in)) copy(*out, *in) } - if in.Reaper != nil { - in, out := &in.Reaper, &out.Reaper - *out = new(ReaperConfig) - (*in).DeepCopyInto(*out) - } return } @@ -409,23 +404,6 @@ func (in *Rack) DeepCopy() *Rack { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReaperConfig) DeepCopyInto(out *ReaperConfig) { - *out = *in - in.Resources.DeepCopyInto(&out.Resources) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReaperConfig. -func (in *ReaperConfig) DeepCopy() *ReaperConfig { - if in == nil { - return nil - } - out := new(ReaperConfig) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StorageConfig) DeepCopyInto(out *StorageConfig) { *out = *in diff --git a/operator/pkg/reconciliation/construct_podtemplatespec.go b/operator/pkg/reconciliation/construct_podtemplatespec.go index cfafef3c8..d13ed260f 100644 --- a/operator/pkg/reconciliation/construct_podtemplatespec.go +++ b/operator/pkg/reconciliation/construct_podtemplatespec.go @@ -289,11 +289,9 @@ func buildContainers(dc *api.CassandraDatacenter, baseTemplate *corev1.PodTempla cassContainer := &corev1.Container{} loggerContainer := &corev1.Container{} - reaperContainer := &corev1.Container{} foundCass := false foundLogger := false - foundReaper := false for i, c := range baseTemplate.Spec.Containers { if c.Name == CassandraContainerName { foundCass = true @@ -301,9 +299,6 @@ func buildContainers(dc *api.CassandraDatacenter, baseTemplate *corev1.PodTempla } else if c.Name == SystemLoggerContainerName { foundLogger = true loggerContainer = &baseTemplate.Spec.Containers[i] - } else if c.Name == ReaperContainerName { - foundReaper = true - reaperContainer = &baseTemplate.Spec.Containers[i] } } @@ -422,12 +417,6 @@ func buildContainers(dc *api.CassandraDatacenter, baseTemplate *corev1.PodTempla loggerContainer.Resources = *getResourcesOrDefault(&dc.Spec.SystemLoggerResources, &DefaultsLoggerContainer) - // Reaper Container - - if dc.IsReaperEnabled() { - buildReaperContainer(dc, reaperContainer) - } - // Note that append() can make copies of each element, // so we call it after modifying any existing elements. @@ -441,12 +430,6 @@ func buildContainers(dc *api.CassandraDatacenter, baseTemplate *corev1.PodTempla } } - if dc.IsReaperEnabled() { - if !foundReaper { - baseTemplate.Spec.Containers = append(baseTemplate.Spec.Containers, *reaperContainer) - } - } - return nil } diff --git a/operator/pkg/reconciliation/construct_podtemplatespec_test.go b/operator/pkg/reconciliation/construct_podtemplatespec_test.go index d163e7428..42d4b293a 100644 --- a/operator/pkg/reconciliation/construct_podtemplatespec_test.go +++ b/operator/pkg/reconciliation/construct_podtemplatespec_test.go @@ -203,72 +203,12 @@ func TestCassandraDatacenter_buildContainers_systemlogger_resources_set_when_not } } -func TestCassandraDatacenter_buildContainers_reaper_resources(t *testing.T) { - dc := &api.CassandraDatacenter{ - Spec: api.CassandraDatacenterSpec{ - ClusterName: "bob", - ServerType: "cassandra", - ServerVersion: "3.11.7", - Reaper: &api.ReaperConfig{ - Enabled: true, - Resources: corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - "cpu": *resource.NewMilliQuantity(1, resource.DecimalSI), - "memory": *resource.NewScaledQuantity(1, resource.Giga), - }, - Requests: corev1.ResourceList{ - "cpu": *resource.NewMilliQuantity(1, resource.DecimalSI), - "memory": *resource.NewScaledQuantity(1, resource.Giga), - }, - }, - }, - }, - } - - podTemplateSpec := &corev1.PodTemplateSpec{} - err := buildContainers(dc, podTemplateSpec) - containers := podTemplateSpec.Spec.Containers - assert.NotNil(t, containers, "Unexpected containers containers received") - assert.Nil(t, err, "Unexpected error encountered") - - assert.Len(t, containers, 3, "Unexpected number of containers containers returned") - assert.Equal(t, containers[2].Resources, dc.Spec.Reaper.Resources, - "reaper container resources have unexpected values.") -} - -func TestCassandraDatacenter_buildContainers_reaper_resources_set_when_not_specified(t *testing.T) { - dc := &api.CassandraDatacenter{ - Spec: api.CassandraDatacenterSpec{ - ClusterName: "bob", - ServerType: "cassandra", - ServerVersion: "3.11.7", - Reaper: &api.ReaperConfig{ - Enabled: true, - }, - }, - } - - podTemplateSpec := &corev1.PodTemplateSpec{} - err := buildContainers(dc, podTemplateSpec) - containers := podTemplateSpec.Spec.Containers - assert.NotNil(t, containers, "Unexpected containers containers received") - assert.Nil(t, err, "Unexpected error encountered") - - assert.Len(t, containers, 3, "Unexpected number of containers containers returned") - if !reflect.DeepEqual(containers[2].Resources, DefaultsReaperContainer) { - t.Error("reaper container resources are not set to the default values.") - } -} - func TestCassandraDatacenter_buildContainers_use_cassandra_settings(t *testing.T) { dc := &api.CassandraDatacenter{ Spec: api.CassandraDatacenterSpec{ ClusterName: "bob", ServerType: "cassandra", ServerVersion: "3.11.7", - Reaper: &api.ReaperConfig{ - Enabled: true, - }, }, } @@ -290,11 +230,7 @@ func TestCassandraDatacenter_buildContainers_use_cassandra_settings(t *testing.T assert.NotNil(t, containers, "Unexpected containers containers received") assert.Nil(t, err, "Unexpected error encountered") - assert.Len(t, containers, 3, "Unexpected number of containers containers returned") - if !reflect.DeepEqual(containers[2].Resources, DefaultsReaperContainer) { - t.Error("reaper container resources are not set to the default values.") - } - + assert.Len(t, containers, 2, "Unexpected number of containers containers returned") if !reflect.DeepEqual(containers[0].Env[0].Name, "k1") { t.Errorf("Unexpected env vars allocated for the cassandra container: %v", containers[0].Env) } @@ -306,9 +242,6 @@ func TestCassandraDatacenter_buildContainers_override_other_containers(t *testin ClusterName: "bob", ServerType: "cassandra", ServerVersion: "3.11.7", - Reaper: &api.ReaperConfig{ - Enabled: true, - }, }, } @@ -333,10 +266,7 @@ func TestCassandraDatacenter_buildContainers_override_other_containers(t *testin assert.NotNil(t, containers, "Unexpected containers containers received") assert.Nil(t, err, "Unexpected error encountered") - assert.Len(t, containers, 3, "Unexpected number of containers containers returned") - if !reflect.DeepEqual(containers[2].Resources, DefaultsReaperContainer) { - t.Error("reaper container resources are not set to the default values.") - } + assert.Len(t, containers, 2, "Unexpected number of containers containers returned") if !reflect.DeepEqual(containers[0].VolumeMounts, []corev1.VolumeMount{ diff --git a/operator/pkg/reconciliation/constructor.go b/operator/pkg/reconciliation/constructor.go index e9418dd91..846e9fb96 100644 --- a/operator/pkg/reconciliation/constructor.go +++ b/operator/pkg/reconciliation/constructor.go @@ -10,8 +10,6 @@ import ( "github.com/datastax/cass-operator/operator/pkg/oplabels" "github.com/datastax/cass-operator/operator/pkg/utils" - batchv1 "k8s.io/api/batch/v1" - corev1 "k8s.io/api/core/v1" policyv1beta1 "k8s.io/api/policy/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -65,45 +63,3 @@ func setOperatorProgressStatus(rc *ReconciliationContext, newState api.ProgressS return nil } - -func buildInitReaperSchemaJob(dc *api.CassandraDatacenter) *batchv1.Job { - return &batchv1.Job{ - TypeMeta: metav1.TypeMeta{ - Kind: "Job", - APIVersion: "batch/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: dc.Namespace, - Name: getReaperSchemaInitJobName(dc), - Labels: dc.GetDatacenterLabels(), - }, - Spec: batchv1.JobSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - RestartPolicy: corev1.RestartPolicyOnFailure, - Containers: []corev1.Container{ - { - Name: getReaperSchemaInitJobName(dc), - Image: ReaperSchemaInitJobImage, - ImagePullPolicy: corev1.PullIfNotPresent, - Env: []corev1.EnvVar{ - { - Name: "KEYSPACE", - Value: ReaperKeyspace, - }, - { - Name: "CONTACT_POINTS", - Value: dc.GetSeedServiceName(), - }, - { - Name: "REPLICATION", - Value: getReaperReplication(dc), - }, - }, - }, - }, - }, - }, - }, - } -} diff --git a/operator/pkg/reconciliation/reconcile_racks.go b/operator/pkg/reconciliation/reconcile_racks.go index f2bc4628f..b0f7d1333 100644 --- a/operator/pkg/reconciliation/reconcile_racks.go +++ b/operator/pkg/reconciliation/reconcile_racks.go @@ -2318,14 +2318,6 @@ func (rc *ReconciliationContext) ReconcileAllRacks() (reconcile.Result, error) { return recResult.Output() } - if recResult := rc.CheckReaperService(); recResult.Completed() { - return recResult.Output() - } - - if recResult := rc.CheckReaperSchemaInitialized(); recResult.Completed() { - return recResult.Output() - } - if recResult := rc.CheckRollingRestart(); recResult.Completed() { return recResult.Output() } diff --git a/operator/pkg/reconciliation/reconcile_reaper.go b/operator/pkg/reconciliation/reconcile_reaper.go deleted file mode 100644 index 2a0a1e844..000000000 --- a/operator/pkg/reconciliation/reconcile_reaper.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright DataStax, Inc. -// Please see the included license file for details. - -package reconciliation - -import ( - "fmt" - "math" - "strconv" - - v1batch "k8s.io/api/batch/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" - - "github.com/datastax/cass-operator/operator/internal/result" - api "github.com/datastax/cass-operator/operator/pkg/apis/cassandra/v1beta1" - "github.com/datastax/cass-operator/operator/pkg/images" -) - -const ( - ReaperUIPort = 7080 - ReaperAdminPort = 7081 - ReaperDefaultPullPolicy = corev1.PullIfNotPresent - ReaperContainerName = "reaper" - ReaperHealthCheckPath = "/healthcheck" - ReaperKeyspace = "reaper_db" - ReaperSchemaInitJob = "ReaperSchemaInitJob" - // This code currently lives at https://github.com/jsanda/create_keyspace. - ReaperSchemaInitJobImage = "jsanda/reaper-init-keyspace:latest" -) - -// We are passing in container by reference because the user may have already provided a -// reaper container with desired settings in CassandraDatacenter.Spec.PodTemplateSpec. -// Therefore we will simply fill-in any missing defaults inside of buildReaperContainer. -// TODO: provide more unit testing for building reaper containers. -func buildReaperContainer(dc *api.CassandraDatacenter, container *corev1.Container) { - - ports := []corev1.ContainerPort{ - {Name: "ui", ContainerPort: ReaperUIPort, Protocol: "TCP"}, - {Name: "admin", ContainerPort: ReaperAdminPort, Protocol: "TCP"}, - } - - container.Name = ReaperContainerName - container.Image = getReaperImage(dc) - container.ImagePullPolicy = getReaperPullPolicy(dc) - - container.Ports = combinePortSlices(ports, container.Ports) - - if container.LivenessProbe == nil { - container.LivenessProbe = probe(ReaperAdminPort, ReaperHealthCheckPath, int(60*dc.Spec.Size), 10) - } - - if container.ReadinessProbe == nil { - container.ReadinessProbe = probe(ReaperAdminPort, ReaperHealthCheckPath, 30, 15) - } - - envDefaults := []corev1.EnvVar{ - {Name: "REAPER_STORAGE_TYPE", Value: "cassandra"}, - {Name: "REAPER_ENABLE_DYNAMIC_SEED_LIST", Value: "false"}, - {Name: "REAPER_DATACENTER_AVAILABILITY", Value: "SIDECAR"}, - {Name: "REAPER_SERVER_APP_PORT", Value: strconv.Itoa(ReaperUIPort)}, - {Name: "REAPER_SERVER_ADMIN_PORT", Value: strconv.Itoa(ReaperAdminPort)}, - {Name: "REAPER_CASS_CLUSTER_NAME", Value: dc.ClusterName}, - {Name: "REAPER_CASS_CONTACT_POINTS", Value: fmt.Sprintf("[%s]", dc.GetSeedServiceName())}, - {Name: "REAPER_AUTH_ENABLED", Value: "false"}, - {Name: "REAPER_JMX_AUTH_USERNAME", Value: ""}, - {Name: "REAPER_JMX_AUTH_PASSWORD", Value: ""}, - } - - container.Env = combineEnvSlices(envDefaults, container.Env) - - container.Resources = *getResourcesOrDefault(&dc.Spec.Reaper.Resources, &DefaultsReaperContainer) -} - -func getReaperImage(dc *api.CassandraDatacenter) string { - if len(dc.Spec.Reaper.Image) == 0 { - return images.GetReaperImage() - } - return dc.Spec.Reaper.Image -} - -func getReaperPullPolicy(dc *api.CassandraDatacenter) corev1.PullPolicy { - if len(dc.Spec.Reaper.ImagePullPolicy) == 0 { - return ReaperDefaultPullPolicy - } - return dc.Spec.Reaper.ImagePullPolicy -} - -func (rc *ReconciliationContext) CheckReaperSchemaInitialized() result.ReconcileResult { - // Using a job eventually get replaced with calls to the mgmt api once it has support for - // creating keyspaces and tables. - - rc.ReqLogger.Info("reconcile_reaper::CheckReaperSchemaInitialized") - - if rc.Datacenter.Spec.Reaper == nil || !rc.Datacenter.Spec.Reaper.Enabled { - return result.Continue() - } - - jobName := getReaperSchemaInitJobName(rc.Datacenter) - schemaJob := &v1batch.Job{} - - err := rc.Client.Get(rc.Ctx, types.NamespacedName{Namespace: rc.Datacenter.Namespace, Name: jobName}, schemaJob) - if err != nil && errors.IsNotFound(err) { - // Create the job - schemaJob := buildInitReaperSchemaJob(rc.Datacenter) - rc.ReqLogger.Info("creating Reaper schema init job", ReaperSchemaInitJob, schemaJob.Name) - if err := setControllerReference(rc.Datacenter, schemaJob, rc.Scheme); err != nil { - rc.ReqLogger.Error(err, "failed to set owner reference", ReaperSchemaInitJob, schemaJob.Name) - return result.Error(err) - } - if err := rc.Client.Create(rc.Ctx, schemaJob); err != nil { - rc.ReqLogger.Error(err, "failed to create job", ReaperSchemaInitJob, schemaJob.Name) - return result.Error(err) - } else { - return result.RequeueSoon(2) - } - } else if err != nil { - return result.Error(err) - } else if jobFinished(schemaJob) { - return result.Continue() - } else { - return result.RequeueSoon(2) - } -} - -func getReaperSchemaInitJobName(dc *api.CassandraDatacenter) string { - return fmt.Sprintf("%s-reaper-init-schema", dc.Spec.ClusterName) -} - -func getReaperReplication(dc *api.CassandraDatacenter) string { - replicationFactor := int(math.Min(float64(dc.Spec.Size), 3)) - return fmt.Sprintf("{'class': 'NetworkTopologyStrategy', '%s': %d}", dc.Name, replicationFactor) -} - -func jobFinished(job *v1batch.Job) bool { - for _, c := range job.Status.Conditions { - if (c.Type == v1batch.JobComplete || c.Type == v1batch.JobFailed) && c.Status == corev1.ConditionTrue { - return true - } - } - return false -} - -func (rc *ReconciliationContext) CheckReaperService() result.ReconcileResult { - rc.ReqLogger.Info("reconcile_reaper::CheckReaperService") - - serviceName := getReaperServiceName(rc.Datacenter) - service := &corev1.Service{} - - err := rc.Client.Get(rc.Ctx, types.NamespacedName{Namespace: rc.Datacenter.Namespace, Name: serviceName}, service) - if err != nil && errors.IsNotFound(err) { - if rc.Datacenter.Spec.Reaper != nil && rc.Datacenter.Spec.Reaper.Enabled { - // Create the service - service = newReaperService(rc.Datacenter) - rc.ReqLogger.Info("creating Reaper service") - if err := setControllerReference(rc.Datacenter, service, rc.Scheme); err != nil { - rc.ReqLogger.Error(err, "failed to set owner reference", "ReaperService", serviceName) - return result.Error(err) - } - if err := rc.Client.Create(rc.Ctx, service); err != nil { - rc.ReqLogger.Error(err, "failed to create Reaper service") - return result.Error(err) - } - return result.Continue() - } - } else if err != nil { - return result.Error(err) - } else if rc.Datacenter.Spec.Reaper == nil || !rc.Datacenter.Spec.Reaper.Enabled { - if err := rc.Client.Delete(rc.Ctx, service); err != nil { - rc.ReqLogger.Error(err, "failed to delete Reaper service", "ReaperService", serviceName) - } - } - return result.Continue() -} - -func getReaperServiceName(dc *api.CassandraDatacenter) string { - return fmt.Sprintf("%s-reaper-service", dc.Spec.ClusterName) -} - -func newReaperService(dc *api.CassandraDatacenter) *corev1.Service { - return &corev1.Service{ - TypeMeta: metav1.TypeMeta{ - Kind: "Service", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: getReaperServiceName(dc), - Namespace: dc.Namespace, - Labels: dc.GetDatacenterLabels(), - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Port: ReaperUIPort, - Name: "ui", - Protocol: corev1.ProtocolTCP, - TargetPort: intstr.IntOrString{ - Type: intstr.String, - StrVal: "ui", - }, - }, - }, - Selector: dc.GetDatacenterLabels(), - }, - } -} diff --git a/operator/pkg/reconciliation/reconcile_reaper_test.go b/operator/pkg/reconciliation/reconcile_reaper_test.go deleted file mode 100644 index 6cd3e0cc6..000000000 --- a/operator/pkg/reconciliation/reconcile_reaper_test.go +++ /dev/null @@ -1,153 +0,0 @@ -package reconciliation - -import ( - "testing" - - api "github.com/datastax/cass-operator/operator/pkg/apis/cassandra/v1beta1" - "github.com/stretchr/testify/assert" - v1batch "k8s.io/api/batch/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -func TestReconcileReaper_buildInitReaperSchemaJob(t *testing.T) { - dc := newCassandraDatacenter() - job := buildInitReaperSchemaJob(dc) - - assert.Equal(t, getReaperSchemaInitJobName(dc), job.Name) - assert.Equal(t, dc.GetDatacenterLabels(), job.Labels) - - assert.Equal(t, 1, len(job.Spec.Template.Spec.Containers)) - container := job.Spec.Template.Spec.Containers[0] - - assert.Equal(t, ReaperSchemaInitJobImage, container.Image) - - expectedEnvVars := []corev1.EnvVar{ - {Name: "KEYSPACE", Value: ReaperKeyspace}, - {Name: "CONTACT_POINTS", Value: dc.GetSeedServiceName()}, - {Name: "REPLICATION", Value: "{'class': 'NetworkTopologyStrategy', 'ReaperSchemaJobTest': 3}"}, - } - assert.ElementsMatch(t, expectedEnvVars, container.Env) -} - -func TestReconcileReaper_newReaperService(t *testing.T) { - dc := newCassandraDatacenter() - service := newReaperService(dc) - - assert.Equal(t, getReaperServiceName(dc), service.Name) - assert.Equal(t, dc.GetDatacenterLabels(), service.Labels) - assert.Equal(t, 1, len(service.Spec.Ports)) - - port := service.Spec.Ports[0] - assert.Equal(t, int32(ReaperUIPort), port.Port) - assert.Equal(t, dc.GetDatacenterLabels(), service.Spec.Selector) -} - -func TestReconcileReaper_CheckReaperSchemaInitialized(t *testing.T) { - rc, _, cleanupMockScr := setupTest() - rc.Datacenter.Spec.Reaper = &api.ReaperConfig{Enabled: true} - defer cleanupMockScr() - - trackObjects := []runtime.Object{rc.Datacenter} - - rc.Client = fake.NewFakeClient(trackObjects...) - - reconcileResult := rc.CheckReaperSchemaInitialized() - assert.True(t, reconcileResult.Completed()) - - result, err := reconcileResult.Output() - - assert.NoError(t, err) - assert.True(t, result.Requeue, "should requeue request") - - job := &v1batch.Job{} - jobName := getReaperSchemaInitJobName(rc.Datacenter) - err = rc.Client.Get(rc.Ctx, types.NamespacedName{Namespace: rc.Datacenter.Namespace, Name: jobName}, job) - - assert.NoErrorf(t, err, "failed to get job %s", jobName) -} - -func TestReconcileReaper_CheckReaperSchemaNotInitialized(t *testing.T) { - rc, _, cleanupMockScr := setupTest() - defer cleanupMockScr() - - trackObjects := []runtime.Object{rc.Datacenter} - - rc.Client = fake.NewFakeClient(trackObjects...) - - reconcileResult := rc.CheckReaperSchemaInitialized() - assert.False(t, reconcileResult.Completed()) - - job := &v1batch.Job{} - jobName := getReaperSchemaInitJobName(rc.Datacenter) - err := rc.Client.Get(rc.Ctx, types.NamespacedName{Namespace: rc.Datacenter.Namespace, Name: jobName}, job) - - assert.True(t, errors.IsNotFound(err), "did not expect to find job %s", jobName) -} - -func TestReconcileReaper_CheckReaperService(t *testing.T) { - rc, _, cleanupMockScr := setupTest() - defer cleanupMockScr() - - rc.Datacenter.Spec.Reaper = &api.ReaperConfig{Enabled: true} - - trackObjects := []runtime.Object{rc.Datacenter} - - rc.Client = fake.NewFakeClient(trackObjects...) - - reconcileResult := rc.CheckReaperService() - assert.False(t, reconcileResult.Completed()) - - service := &corev1.Service{} - serviceName := getReaperServiceName(rc.Datacenter) - err := rc.Client.Get(rc.Ctx, types.NamespacedName{Namespace: rc.Datacenter.Namespace, Name: serviceName}, service) - - assert.NoErrorf(t, err, "failed to get service %s", serviceName) -} - -func TestReconcileReaper_CheckReaperServiceReaperDisabled(t *testing.T) { - rc, _, cleanupMockScr := setupTest() - defer cleanupMockScr() - - serviceName := getReaperServiceName(rc.Datacenter) - service := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: rc.Datacenter.Namespace, - Name: serviceName, - }, - } - - trackObjects := []runtime.Object{rc.Datacenter, service} - - rc.Client = fake.NewFakeClient(trackObjects...) - - reconcileResult := rc.CheckReaperService() - assert.False(t, reconcileResult.Completed()) - - err := rc.Client.Get(rc.Ctx, types.NamespacedName{Namespace: rc.Datacenter.Namespace, Name: serviceName}, service) - - assert.True(t, errors.IsNotFound(err), "did not expect to find service %s", serviceName) -} - -func newCassandraDatacenter() *api.CassandraDatacenter { - return &api.CassandraDatacenter{ - ObjectMeta: metav1.ObjectMeta{ - Name: "ReaperSchemaJobTest", - Namespace: "reaper", - Labels: map[string]string{ - api.DatacenterLabel: "ReaperSchemaJobTest", - api.ClusterLabel: "reaper", - }, - }, - Spec: api.CassandraDatacenterSpec{ - Size: 6, - ClusterName: "reaper", - ServerType: "Cassandra", - ServerVersion: "3.11.7", - }, - } -} diff --git a/tests/enable_reaper/enable_reaper_suite_test.go b/tests/enable_reaper/enable_reaper_suite_test.go deleted file mode 100644 index c4a8903c9..000000000 --- a/tests/enable_reaper/enable_reaper_suite_test.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright DataStax, Inc. -// Please see the included license file for details. - -package enable_reaper - -import ( - "fmt" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - corev1 "k8s.io/api/core/v1" - - ginkgo_util "github.com/datastax/cass-operator/mage/ginkgo" - "github.com/datastax/cass-operator/mage/kubectl" -) - -var ( - testName = "Enable Reaper" - namespace = "test-enable-reaper" - dcName = "dc1" - dcYaml = "../testdata/oss-three-rack-three-node-dc.yaml" - operatorYaml = "../testdata/operator.yaml" - dcResource = fmt.Sprintf("CassandraDatacenter/%s", dcName) - dcLabel = fmt.Sprintf("cassandra.datastax.com/datacenter=%s", dcName) - ns = ginkgo_util.NewWrapper(testName, namespace) -) - -func TestLifecycle(t *testing.T) { - AfterSuite(func() { - logPath := fmt.Sprintf("%s/aftersuite", ns.LogDir) - kubectl.DumpAllLogs(logPath).ExecV() - fmt.Printf("\n\tPost-run logs dumped at: %s\n\n", logPath) - ns.Terminate() - }) - - RegisterFailHandler(Fail) - RunSpecs(t, testName) -} - -var _ = Describe(testName, func() { - Context("when in a new cluster", func() { - Specify("the operator can scale up and enable Reaper and then disable Reaper", func() { - By("creating a namespace") - err := kubectl.CreateNamespace(namespace).ExecV() - Expect(err).ToNot(HaveOccurred()) - - step := "setting up cass-operator resources via helm chart" - ns.HelmInstall("../../charts/cass-operator-chart") - - ns.WaitForOperatorReady() - - step = "creating a datacenter resource with 3 racks/3 nodes" - k := kubectl.ApplyFiles(dcYaml) - ns.ExecAndLog(step, k) - - ns.WaitForSuperUserUpserted(dcName, 600) - - step = "check recorded host IDs" - nodeStatusesHostIds := ns.GetNodeStatusesHostIds(dcName) - Expect(len(nodeStatusesHostIds), 3) - - ns.WaitForDatacenterReady(dcName) - ns.WaitForDatacenterCondition(dcName, "Ready", string(corev1.ConditionTrue)) - ns.WaitForDatacenterCondition(dcName, "Initialized", string(corev1.ConditionTrue)) - - step = "enable Reaper" - json := `{"spec": {"reaper": {"enabled": true}}}` - k = kubectl.PatchMerge(dcResource, json) - ns.ExecAndLog(step, k) - - ns.WaitForDatacenterOperatorProgress(dcName, "Updating", 120) - ns.WaitForDatacenterOperatorProgress(dcName, "Ready", 1200) - - step = "check that Reaper container is deployed" - json = `jsonpath={.items[*].spec.containers[?(@.name=="reaper")].name}` - k = kubectl.Get("pods"). - FormatOutput(json) - ns.WaitForOutputAndLog(step, k, "reaper reaper reaper", 20) - - step = "disable Reaper" - json = `{"spec": {"reaper": {"enabled": false}}}` - k = kubectl.PatchMerge(dcResource, json) - ns.ExecAndLog(step, k) - - ns.WaitForDatacenterOperatorProgress(dcName, "Updating", 120) - ns.WaitForDatacenterOperatorProgress(dcName, "Ready", 1200) - - step = "check that Reaper container is not deployed" - json = `jsonpath={.items[*].spec.containers[?(@.name=="reaper")]}` - k = kubectl.Get("pods"). - FormatOutput(json) - ns.WaitForOutputAndLog(step, k, "", 20) - - step = "deleting the dc" - k = kubectl.DeleteFromFiles(dcYaml) - ns.ExecAndLog(step, k) - - step = "checking that the dc no longer exists" - json = "jsonpath={.items}" - k = kubectl.Get("CassandraDatacenter"). - WithLabel(dcLabel). - FormatOutput(json) - ns.WaitForOutputAndLog(step, k, "[]", 300) - }) - }) -})