Repository: k8ssandra/k8ssandra-operator (go)

Issue:
DC-level annotations and labels are ignored
**What happened?**
I set 
```
apiVersion: k8ssandra.io/v1alpha1
kind: K8ssandraCluster
metadata:
  name: cluster
spec:
  cassandra:
    datacenters:
    - ....  
      metadata:
        name: some-name
        annotations:
          sidecar.istio.io/inject: "false"
```
But then generated CassandraDatacenter is having empty metadata.
```
apiVersion: cassandra.datastax.com/v1beta1
kind: CassandraDatacenter
metadata:
  name: some-name
spec:
  podTemplateSpec:
    metadata: {}
```
**Did you expect to see something different?**
I expected to see my annotation in podTemplateSpec.
```
apiVersion: cassandra.datastax.com/v1beta1
kind: CassandraDatacenter
metadata:
  name: some-name
spec:
  podTemplateSpec:
    metadata:
      annotations:
        sidecar.istio.io/inject: "false"
```

* K8ssandra Operator version:

docker.io/k8ssandra/k8ssandra-operator:v1.4.1

* Kubernetes version information:

v1.24.11

* K8ssandra Operator Logs:

No error in operator logs.

**Anything else we need to know?**:
Maybe I should set this annotation in a different way? 

Thank you!


Pull request:
Inline tags in EmbeddedObjectMeta to work around YAML bug (fixes #969)
**What this PR does**:
Avoid too many levels of inlining that confuse the YAML parser.
I kept the test separate for easy reproduction, but I'll squash everything into the second commit before merging.

**Which issue(s) this PR fixes**:
Fixes #969

**Checklist**
- [x] Changes manually tested
- [x] Automated Tests added/updated
- [ ] Documentation added/updated
- [x] CHANGELOG.md updated (not required for documentation PRs)
- [x] CLA Signed:  [DataStax CLA](https://cla.datastax.com/)


Patch:
diff --git a/CHANGELOG/CHANGELOG-1.7.md b/CHANGELOG/CHANGELOG-1.7.md
index d1258f39..efd914ee 100644
--- a/CHANGELOG/CHANGELOG-1.7.md
+++ b/CHANGELOG/CHANGELOG-1.7.md
@@ -21,6 +21,7 @@ When cutting a new release, update the `unreleased` heading to the tag being gen
 * [BUGFIX] [#946](https://github.com/k8ssandra/k8ssandra-operator/issues/946) Fix medusaClient to fetch the pods from correct namespace
 * [BUGFIX] [#940](https://github.com/k8ssandra/k8ssandra-operator/issues/940) Vector resource requirements are correctly set to the server-system-logger and also allow override of server-system-logger resource properties from containers.
 * [BUGFIX] [#973](https://github.com/k8ssandra/k8ssandra-operator/issues/973) ReplicatedSecrets don't get updated when a DC is added in a different namespace but without context
+* [BUGFIX] [#969](https://github.com/k8ssandra/k8ssandra-operator/issues/969) Inline tags in EmbeddedObjectMeta to work around YAML bug
 * [DOCS] [#935](https://github.com/k8ssandra/k8ssandra-operator/issues/935) Add and document updated dashboards for the new metrics endpoint
 * [DOCS] [#919](https://github.com/k8ssandra/k8ssandra-operator/issues/919) Improve the release process documentation.
 * [CHANGE] [#601](https://github.com/k8ssandra/k8ssandra-operator/issues/601) Add injection annotation to Cassandra and Reaper pods
diff --git a/apis/k8ssandra/v1alpha1/k8ssandracluster_types.go b/apis/k8ssandra/v1alpha1/k8ssandracluster_types.go
index 08ba80e1..53d4ca33 100644
--- a/apis/k8ssandra/v1alpha1/k8ssandracluster_types.go
+++ b/apis/k8ssandra/v1alpha1/k8ssandracluster_types.go
@@ -226,7 +226,7 @@ type K8ssandraClusterList struct {
 type CassandraClusterTemplate struct {
 	DatacenterOptions `json:",inline"`
 
-	Meta meta.CassandraDatacenterMeta `json:"metadata,omitempty"`
+	Meta meta.CassandraClusterMeta `json:"metadata,omitempty"`
 
 	// The reference to the superuser secret to use for Cassandra. If unspecified, a default secret will be generated
 	// with a random password; the generated secret name will be "<cluster_name>-superuser" where <cluster_name> is the
@@ -466,8 +466,24 @@ type EmbeddedObjectMeta struct {
 
 	Name string `json:"name"`
 
+	// Note that the rest of the fields below are shared with CassandraClusterMeta. We originally tried to inline that
+	// struct instead of repeating the fields, but that doesn't work because of a YAML unmarshalling bug.
+
+	// labels/annotations for the CassandraDatacenter component
+	// +optional
+	meta.Tags `json:",inline"`
+
+	// labels/annotations that will be applied to all components
+	// created by the CRD
 	// +optional
-	Metadata meta.CassandraDatacenterMeta `json:",inline"`
+	CommonLabels map[string]string `json:"commonLabels,omitempty"`
+
+	// labels/annotations for the pod components
+	// +optional
+	Pods meta.Tags `json:"pods,omitempty"`
+
+	// labels/annotations for all of the CassandraDatacenter service components
+	ServiceConfig meta.CassandraDatacenterServicesMeta `json:"services,omitempty"`
 }
 
 func (s *K8ssandraClusterStatus) GetConditionStatus(conditionType K8ssandraClusterConditionType) corev1.ConditionStatus {
diff --git a/apis/k8ssandra/v1alpha1/zz_generated.deepcopy.go b/apis/k8ssandra/v1alpha1/zz_generated.deepcopy.go
index 9199b482..9dbdcd15 100644
--- a/apis/k8ssandra/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/k8ssandra/v1alpha1/zz_generated.deepcopy.go
@@ -305,7 +305,16 @@ func (in *DatacenterOptions) DeepCopy() *DatacenterOptions {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *EmbeddedObjectMeta) DeepCopyInto(out *EmbeddedObjectMeta) {
 	*out = *in
-	in.Metadata.DeepCopyInto(&out.Metadata)
+	in.Tags.DeepCopyInto(&out.Tags)
+	if in.CommonLabels != nil {
+		in, out := &in.CommonLabels, &out.CommonLabels
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+	in.Pods.DeepCopyInto(&out.Pods)
+	in.ServiceConfig.DeepCopyInto(&out.ServiceConfig)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbeddedObjectMeta.
diff --git a/config/crd/bases/k8ssandra.io_k8ssandraclusters.yaml b/config/crd/bases/k8ssandra.io_k8ssandraclusters.yaml
index 2c2804ad..984e3b15 100644
--- a/config/crd/bases/k8ssandra.io_k8ssandraclusters.yaml
+++ b/config/crd/bases/k8ssandra.io_k8ssandraclusters.yaml
@@ -22010,7 +22010,8 @@ spec:
                         type: object
                     type: object
                   metadata:
-                    description: Struct to hold labels and annotations for a CassandraDatacenter
+                    description: Struct to hold labels and annotations for the top-level
+                      Cassandra cluster definition.
                     properties:
                       annotations:
                         additionalProperties:
diff --git a/controllers/k8ssandra/medusa_reconciler.go b/controllers/k8ssandra/medusa_reconciler.go
index 31bac371..4ea5d552 100644
--- a/controllers/k8ssandra/medusa_reconciler.go
+++ b/controllers/k8ssandra/medusa_reconciler.go
@@ -51,10 +51,10 @@ func (r *K8ssandraClusterReconciler) reconcileMedusa(
 			cassandraUserSecretName := medusa.CassandraUserSecretName(medusaSpec, kc.SanitizedName())
 			cassandra.AddCqlUser(medusaSpec.CassandraUserSecretRef, dcConfig, cassandraUserSecretName)
 
-			if dcConfig.Meta.Metadata.Pods.Annotations == nil {
-				dcConfig.Meta.Metadata.Pods.Annotations = map[string]string{}
+			if dcConfig.Meta.Pods.Annotations == nil {
+				dcConfig.Meta.Pods.Annotations = map[string]string{}
 			}
-			secret.AddInjectionAnnotationMedusaContainers(&dcConfig.Meta.Metadata.Pods, cassandraUserSecretName)
+			secret.AddInjectionAnnotationMedusaContainers(&dcConfig.Meta.Pods, cassandraUserSecretName)
 		}
 	} else {
 		logger.Info("Medusa is not enabled")
diff --git a/pkg/cassandra/datacenter.go b/pkg/cassandra/datacenter.go
index 4ecb2714..7113c4cb 100644
--- a/pkg/cassandra/datacenter.go
+++ b/pkg/cassandra/datacenter.go
@@ -2,7 +2,6 @@ package cassandra
 
 import (
 	"fmt"
-
 	"github.com/Masterminds/semver/v3"
 
 	"github.com/k8ssandra/cass-operator/apis/cassandra/v1beta1"
@@ -12,7 +11,6 @@ import (
 	"github.com/k8ssandra/k8ssandra-operator/pkg/encryption"
 	goalesceutils "github.com/k8ssandra/k8ssandra-operator/pkg/goalesce"
 	"github.com/k8ssandra/k8ssandra-operator/pkg/images"
-	"github.com/k8ssandra/k8ssandra-operator/pkg/meta"
 	"github.com/k8ssandra/k8ssandra-operator/pkg/utils"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
@@ -220,7 +218,7 @@ func NewDatacenter(klusterKey types.NamespacedName, template *DatacenterConfig)
 		dc.Spec.ManagementApiAuth = *template.ManagementApiAuth
 	}
 
-	m := template.Meta.Metadata
+	m := template.Meta
 	dc.ObjectMeta.Labels = utils.MergeMap(dc.ObjectMeta.Labels, m.Labels)
 	dc.ObjectMeta.Annotations = utils.MergeMap(dc.ObjectMeta.Annotations, m.Annotations)
 
@@ -363,9 +361,12 @@ func Coalesce(clusterName string, clusterTemplate *api.CassandraClusterTemplate,
 	dcConfig.PerNodeInitContainerImage = mergedOptions.PerNodeConfigInitContainerImage
 	dcConfig.ServiceAccount = mergedOptions.ServiceAccount
 
-	dcConfig.Meta.Metadata = goalesceutils.MergeCRs(clusterTemplate.Meta, dcTemplate.Meta.Metadata)
+	dcConfig.Meta.Tags = goalesceutils.MergeCRs(clusterTemplate.Meta.Tags, dcTemplate.Meta.Tags)
+	dcConfig.Meta.CommonLabels = goalesceutils.MergeCRs(clusterTemplate.Meta.CommonLabels, dcTemplate.Meta.CommonLabels)
+	dcConfig.Meta.Pods = goalesceutils.MergeCRs(clusterTemplate.Meta.Pods, dcTemplate.Meta.Pods)
+	dcConfig.Meta.ServiceConfig = goalesceutils.MergeCRs(clusterTemplate.Meta.ServiceConfig, dcTemplate.Meta.ServiceConfig)
 
-	AddPodTemplateSpecMeta(dcConfig, dcConfig.Meta.Metadata)
+	AddPodTemplateSpecMeta(dcConfig, dcConfig.Meta)
 
 	if len(mergedOptions.Containers) > 0 {
 		AddContainersToPodTemplateSpec(dcConfig, mergedOptions.Containers...)
@@ -435,7 +436,7 @@ func AddVolumesToPodTemplateSpec(podTemplateSpec *corev1.PodTemplateSpec, volume
 	podTemplateSpec.Spec.Volumes = append(podTemplateSpec.Spec.Volumes, volume)
 }
 
-func AddPodTemplateSpecMeta(dcConfig *DatacenterConfig, m meta.CassandraDatacenterMeta) {
+func AddPodTemplateSpecMeta(dcConfig *DatacenterConfig, m api.EmbeddedObjectMeta) {
 	// We don't need to overlay m.CommonLabels as this will be done by cass-operator itself
 	dcConfig.PodTemplateSpec.ObjectMeta = metav1.ObjectMeta{
 		Annotations: m.Pods.Annotations,
diff --git a/pkg/meta/meta.go b/pkg/meta/meta.go
index 7233b39e..07141943 100644
--- a/pkg/meta/meta.go
+++ b/pkg/meta/meta.go
@@ -31,9 +31,9 @@ type ResourceMeta struct {
 	Service Tags `json:"service,omitempty"`
 }
 
-// Struct to hold labels and annotations for a CassandraDatacenter
+// Struct to hold labels and annotations for the top-level Cassandra cluster definition.
 // +kubebuilder:object:generate=true
-type CassandraDatacenterMeta struct {
+type CassandraClusterMeta struct {
 	// labels/annotations for the CassandraDatacenter component
 	// +optional
 	Tags `json:",inline"`
diff --git a/pkg/meta/zz_generated.deepcopy.go b/pkg/meta/zz_generated.deepcopy.go
index 06d824f9..3df83dc0 100644
--- a/pkg/meta/zz_generated.deepcopy.go
+++ b/pkg/meta/zz_generated.deepcopy.go
@@ -24,7 +24,7 @@ package meta
 import ()
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *CassandraDatacenterMeta) DeepCopyInto(out *CassandraDatacenterMeta) {
+func (in *CassandraClusterMeta) DeepCopyInto(out *CassandraClusterMeta) {
 	*out = *in
 	in.Tags.DeepCopyInto(&out.Tags)
 	if in.CommonLabels != nil {
@@ -38,12 +38,12 @@ func (in *CassandraDatacenterMeta) DeepCopyInto(out *CassandraDatacenterMeta) {
 	in.ServiceConfig.DeepCopyInto(&out.ServiceConfig)
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CassandraDatacenterMeta.
-func (in *CassandraDatacenterMeta) DeepCopy() *CassandraDatacenterMeta {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CassandraClusterMeta.
+func (in *CassandraClusterMeta) DeepCopy() *CassandraClusterMeta {
 	if in == nil {
 		return nil
 	}
-	out := new(CassandraDatacenterMeta)
+	out := new(CassandraClusterMeta)
 	in.DeepCopyInto(out)
 	return out
 }


Test patch:
diff --git a/apis/k8ssandra/v1alpha1/k8ssandracluster_types_test.go b/apis/k8ssandra/v1alpha1/k8ssandracluster_types_test.go
index bd13ce88..24303e49 100644
--- a/apis/k8ssandra/v1alpha1/k8ssandracluster_types_test.go
+++ b/apis/k8ssandra/v1alpha1/k8ssandracluster_types_test.go
@@ -1,6 +1,7 @@
 package v1alpha1
 
 import (
+	"sigs.k8s.io/yaml"
 	"testing"
 
 	cassdcapi "github.com/k8ssandra/cass-operator/apis/cassandra/v1beta1"
@@ -128,3 +129,67 @@ func TestNetworkingConfig_ToCassNetworkingConfig(t *testing.T) {
 		})
 	}
 }
+
+// TestUnmarshallDatacenterMeta checks that user-provided labels and annotations are properly set when unmarshalling
+// YAML.
+func TestUnmarshallDatacenterMeta(t *testing.T) {
+	input := `
+metadata:
+  labels:
+    label1: labelValue1
+  annotations:
+    annotation1: annotationValue1
+  commonLabels:
+    commonLabel1: commonLabelValue1
+  pods:
+    labels:
+      podLabel1: podLabelValue1
+    annotations:
+      podAnnotation1: podAnnotationValue1
+  services:
+    dcService:
+      labels:
+        dcSvcLabel1: dcSvcValue1
+      annotations:
+        dcSvcAnnotation1: dcSvcAnnotationValue1
+    seedService:
+      labels:
+        seedSvcLabel1: seedSvcLabelValue1
+      annotations:
+        seedSvcAnnotation1: seedSvcAnnotationValue1
+    allPodsService:
+      labels:
+        allPodsSvcLabel1: allPodsSvcLabelValue1
+      annotations:
+        allPodsSvcAnnotation1: allPodsSvcAnnotationValue1
+    additionalSeedService:
+      labels:
+        addSeedSvcLabel1: addSeedSvcLabelValue1
+      annotations:
+        addSeedSvcAnnotation1: addSeedSvcAnnotationValue1
+    nodePortService:
+      labels:
+        nodePortSvcLabel1: nodePortSvcLabelValue1
+      annotations:
+        nodePortSvcAnnotation1: nodePortSvcAnnotationValue1
+`
+	dc := &CassandraDatacenterTemplate{}
+	err := yaml.Unmarshal([]byte(input), dc)
+	assert.NoError(t, err)
+
+	assert.Equal(t, "labelValue1", dc.Meta.Labels["label1"])
+	assert.Equal(t, "annotationValue1", dc.Meta.Annotations["annotation1"])
+	assert.Equal(t, "commonLabelValue1", dc.Meta.CommonLabels["commonLabel1"])
+	assert.Equal(t, "podLabelValue1", dc.Meta.Pods.Labels["podLabel1"])
+	assert.Equal(t, "podAnnotationValue1", dc.Meta.Pods.Annotations["podAnnotation1"])
+	assert.Equal(t, "dcSvcValue1", dc.Meta.ServiceConfig.DatacenterService.Labels["dcSvcLabel1"])
+	assert.Equal(t, "dcSvcAnnotationValue1", dc.Meta.ServiceConfig.DatacenterService.Annotations["dcSvcAnnotation1"])
+	assert.Equal(t, "seedSvcLabelValue1", dc.Meta.ServiceConfig.SeedService.Labels["seedSvcLabel1"])
+	assert.Equal(t, "seedSvcAnnotationValue1", dc.Meta.ServiceConfig.SeedService.Annotations["seedSvcAnnotation1"])
+	assert.Equal(t, "allPodsSvcLabelValue1", dc.Meta.ServiceConfig.AllPodsService.Labels["allPodsSvcLabel1"])
+	assert.Equal(t, "allPodsSvcAnnotationValue1", dc.Meta.ServiceConfig.AllPodsService.Annotations["allPodsSvcAnnotation1"])
+	assert.Equal(t, "addSeedSvcLabelValue1", dc.Meta.ServiceConfig.AdditionalSeedService.Labels["addSeedSvcLabel1"])
+	assert.Equal(t, "addSeedSvcAnnotationValue1", dc.Meta.ServiceConfig.AdditionalSeedService.Annotations["addSeedSvcAnnotation1"])
+	assert.Equal(t, "nodePortSvcLabelValue1", dc.Meta.ServiceConfig.NodePortService.Labels["nodePortSvcLabel1"])
+	assert.Equal(t, "nodePortSvcAnnotationValue1", dc.Meta.ServiceConfig.NodePortService.Annotations["nodePortSvcAnnotation1"])
+}
diff --git a/pkg/cassandra/datacenter_test.go b/pkg/cassandra/datacenter_test.go
index dd7bf1d5..95e3774b 100644
--- a/pkg/cassandra/datacenter_test.go
+++ b/pkg/cassandra/datacenter_test.go
@@ -51,11 +51,9 @@ func TestCoalesce(t *testing.T) {
 				Meta: api.EmbeddedObjectMeta{
 					Namespace: "k8ssandra",
 					Name:      "dc1",
-					Metadata: meta.CassandraDatacenterMeta{
-						Tags: meta.Tags{
-							Labels: map[string]string{
-								"env": "dev",
-							},
+					Tags: meta.Tags{
+						Labels: map[string]string{
+							"env": "dev",
 						},
 					},
 				},
@@ -66,11 +64,9 @@ func TestCoalesce(t *testing.T) {
 				Meta: api.EmbeddedObjectMeta{
 					Namespace: "k8ssandra",
 					Name:      "dc1",
-					Metadata: meta.CassandraDatacenterMeta{
-						Tags: meta.Tags{
-							Labels: map[string]string{
-								"env": "dev",
-							},
+					Tags: meta.Tags{
+						Labels: map[string]string{
+							"env": "dev",
 						},
 					},
 				},
@@ -344,11 +340,9 @@ func TestCoalesce(t *testing.T) {
 				Meta: api.EmbeddedObjectMeta{
 					Namespace: "k8ssandra",
 					Name:      "dc1",
-					Metadata: meta.CassandraDatacenterMeta{
-						Tags: meta.Tags{
-							Labels: map[string]string{
-								"env": "dev",
-							},
+					Tags: meta.Tags{
+						Labels: map[string]string{
+							"env": "dev",
 						},
 					},
 				},
@@ -367,11 +361,9 @@ func TestCoalesce(t *testing.T) {
 				Meta: api.EmbeddedObjectMeta{
 					Namespace: "k8ssandra",
 					Name:      "dc1",
-					Metadata: meta.CassandraDatacenterMeta{
-						Tags: meta.Tags{
-							Labels: map[string]string{
-								"env": "dev",
-							},
+					Tags: meta.Tags{
+						Labels: map[string]string{
+							"env": "dev",
 						},
 					},
 				},
@@ -399,11 +391,9 @@ func TestCoalesce(t *testing.T) {
 				Meta: api.EmbeddedObjectMeta{
 					Namespace: "k8ssandra",
 					Name:      "dc1",
-					Metadata: meta.CassandraDatacenterMeta{
-						Tags: meta.Tags{
-							Labels: map[string]string{
-								"env": "dev",
-							},
+					Tags: meta.Tags{
+						Labels: map[string]string{
+							"env": "dev",
 						},
 					},
 				},
@@ -414,11 +404,9 @@ func TestCoalesce(t *testing.T) {
 				Meta: api.EmbeddedObjectMeta{
 					Namespace: "k8ssandra",
 					Name:      "dc1",
-					Metadata: meta.CassandraDatacenterMeta{
-						Tags: meta.Tags{
-							Labels: map[string]string{
-								"env": "dev",
-							},
+					Tags: meta.Tags{
+						Labels: map[string]string{
+							"env": "dev",
 						},
 					},
 				},
@@ -935,7 +923,7 @@ func TestCoalesce(t *testing.T) {
 			name: "Set Cluster Pod Tags",
 			clusterTemplate: &api.CassandraClusterTemplate{
 				DatacenterOptions: api.DatacenterOptions{},
-				Meta: meta.CassandraDatacenterMeta{
+				Meta: meta.CassandraClusterMeta{
 					CommonLabels: map[string]string{
 						"common": "label",
 					},
@@ -951,14 +939,12 @@ func TestCoalesce(t *testing.T) {
 			want: &DatacenterConfig{
 				Meta: api.EmbeddedObjectMeta{
 					Name: "",
-					Metadata: meta.CassandraDatacenterMeta{
-						CommonLabels: map[string]string{
-							"common": "label",
-						},
-						Pods: meta.Tags{
-							Labels:      map[string]string{"label": "lvalue"},
-							Annotations: map[string]string{"annotation:": "avalue"},
-						},
+					CommonLabels: map[string]string{
+						"common": "label",
+					},
+					Pods: meta.Tags{
+						Labels:      map[string]string{"label": "lvalue"},
+						Annotations: map[string]string{"annotation:": "avalue"},
 					},
 				},
 				McacEnabled: true,
@@ -982,28 +968,24 @@ func TestCoalesce(t *testing.T) {
 				DatacenterOptions: api.DatacenterOptions{},
 				Meta: api.EmbeddedObjectMeta{
 					Name: "",
-					Metadata: meta.CassandraDatacenterMeta{
-						CommonLabels: map[string]string{
-							"common": "label",
-						},
-						Pods: meta.Tags{
-							Labels:      map[string]string{"label": "lvalue"},
-							Annotations: map[string]string{"annotation:": "avalue"},
-						},
+					CommonLabels: map[string]string{
+						"common": "label",
+					},
+					Pods: meta.Tags{
+						Labels:      map[string]string{"label": "lvalue"},
+						Annotations: map[string]string{"annotation:": "avalue"},
 					},
 				},
 			},
 			want: &DatacenterConfig{
 				Meta: api.EmbeddedObjectMeta{
 					Name: "",
-					Metadata: meta.CassandraDatacenterMeta{
-						CommonLabels: map[string]string{
-							"common": "label",
-						},
-						Pods: meta.Tags{
-							Labels:      map[string]string{"label": "lvalue"},
-							Annotations: map[string]string{"annotation:": "avalue"},
-						},
+					CommonLabels: map[string]string{
+						"common": "label",
+					},
+					Pods: meta.Tags{
+						Labels:      map[string]string{"label": "lvalue"},
+						Annotations: map[string]string{"annotation:": "avalue"},
 					},
 				},
 				McacEnabled: true,
@@ -1022,7 +1004,7 @@ func TestCoalesce(t *testing.T) {
 			name: "Set Cluster & DC Pod Tags",
 			clusterTemplate: &api.CassandraClusterTemplate{
 				DatacenterOptions: api.DatacenterOptions{},
-				Meta: meta.CassandraDatacenterMeta{
+				Meta: meta.CassandraClusterMeta{
 					Pods: meta.Tags{
 						Labels:      map[string]string{"label": "lvalue", "cluster": "cluster"},
 						Annotations: map[string]string{"annotation:": "avalue", "cluster": "cluster"},
@@ -1033,22 +1015,18 @@ func TestCoalesce(t *testing.T) {
 				DatacenterOptions: api.DatacenterOptions{},
 				Meta: api.EmbeddedObjectMeta{
 					Name: "",
-					Metadata: meta.CassandraDatacenterMeta{
-						Pods: meta.Tags{
-							Labels:      map[string]string{"label": "dcvalue", "dc": "dc"},
-							Annotations: map[string]string{"annotation:": "dcvalue", "dc": "dc"},
-						},
+					Pods: meta.Tags{
+						Labels:      map[string]string{"label": "dcvalue", "dc": "dc"},
+						Annotations: map[string]string{"annotation:": "dcvalue", "dc": "dc"},
 					},
 				},
 			},
 			want: &DatacenterConfig{
 				Meta: api.EmbeddedObjectMeta{
 					Name: "",
-					Metadata: meta.CassandraDatacenterMeta{
-						Pods: meta.Tags{
-							Labels:      map[string]string{"label": "dcvalue", "dc": "dc", "cluster": "cluster"},
-							Annotations: map[string]string{"annotation:": "dcvalue", "dc": "dc", "cluster": "cluster"},
-						},
+					Pods: meta.Tags{
+						Labels:      map[string]string{"label": "dcvalue", "dc": "dc", "cluster": "cluster"},
+						Annotations: map[string]string{"annotation:": "dcvalue", "dc": "dc", "cluster": "cluster"},
 					},
 				},
 				McacEnabled: true,
@@ -1067,7 +1045,7 @@ func TestCoalesce(t *testing.T) {
 			name: "Set Cluster Service Tags",
 			clusterTemplate: &api.CassandraClusterTemplate{
 				DatacenterOptions: api.DatacenterOptions{},
-				Meta: meta.CassandraDatacenterMeta{
+				Meta: meta.CassandraClusterMeta{
 					CommonLabels: map[string]string{
 						"common": "label",
 					},
@@ -1100,31 +1078,29 @@ func TestCoalesce(t *testing.T) {
 			},
 			want: &DatacenterConfig{
 				Meta: api.EmbeddedObjectMeta{
-					Metadata: meta.CassandraDatacenterMeta{
-						CommonLabels: map[string]string{
-							"common": "label",
-						},
-						ServiceConfig: meta.CassandraDatacenterServicesMeta{
-							DatacenterService: meta.Tags{
-								Labels:      map[string]string{"dclabel": "dcvalue"},
-								Annotations: map[string]string{"dcannotation:": "dcvalue"},
-							},
-							SeedService: meta.Tags{
-								Labels:      map[string]string{"seedlabel": "seedvalue"},
-								Annotations: map[string]string{"seedannotation:": "seedvalue"},
-							},
-							AdditionalSeedService: meta.Tags{
-								Labels:      map[string]string{"aslabel": "asvalue"},
-								Annotations: map[string]string{"asannotation:": "asvalue"},
-							},
-							AllPodsService: meta.Tags{
-								Labels:      map[string]string{"aplabel": "apvalue"},
-								Annotations: map[string]string{"apannotation:": "apvalue"},
-							},
-							NodePortService: meta.Tags{
-								Labels:      map[string]string{"nodeportlabel": "nodeportval"},
-								Annotations: map[string]string{"nodeportann:": "nodeportvalue"},
-							},
+					CommonLabels: map[string]string{
+						"common": "label",
+					},
+					ServiceConfig: meta.CassandraDatacenterServicesMeta{
+						DatacenterService: meta.Tags{
+							Labels:      map[string]string{"dclabel": "dcvalue"},
+							Annotations: map[string]string{"dcannotation:": "dcvalue"},
+						},
+						SeedService: meta.Tags{
+							Labels:      map[string]string{"seedlabel": "seedvalue"},
+							Annotations: map[string]string{"seedannotation:": "seedvalue"},
+						},
+						AdditionalSeedService: meta.Tags{
+							Labels:      map[string]string{"aslabel": "asvalue"},
+							Annotations: map[string]string{"asannotation:": "asvalue"},
+						},
+						AllPodsService: meta.Tags{
+							Labels:      map[string]string{"aplabel": "apvalue"},
+							Annotations: map[string]string{"apannotation:": "apvalue"},
+						},
+						NodePortService: meta.Tags{
+							Labels:      map[string]string{"nodeportlabel": "nodeportval"},
+							Annotations: map[string]string{"nodeportann:": "nodeportvalue"},
 						},
 					},
 				},
@@ -1144,62 +1120,58 @@ func TestCoalesce(t *testing.T) {
 			dcTemplate: &api.CassandraDatacenterTemplate{
 				DatacenterOptions: api.DatacenterOptions{},
 				Meta: api.EmbeddedObjectMeta{
-					Metadata: meta.CassandraDatacenterMeta{
-						CommonLabels: map[string]string{
-							"common": "label",
-						},
-						ServiceConfig: meta.CassandraDatacenterServicesMeta{
-							DatacenterService: meta.Tags{
-								Labels:      map[string]string{"dclabel": "dcvalue"},
-								Annotations: map[string]string{"dcannotation:": "dcvalue"},
-							},
-							SeedService: meta.Tags{
-								Labels:      map[string]string{"seedlabel": "seedvalue"},
-								Annotations: map[string]string{"seedannotation:": "seedvalue"},
-							},
-							AdditionalSeedService: meta.Tags{
-								Labels:      map[string]string{"aslabel": "asvalue"},
-								Annotations: map[string]string{"asannotation:": "asvalue"},
-							},
-							AllPodsService: meta.Tags{
-								Labels:      map[string]string{"aplabel": "apvalue"},
-								Annotations: map[string]string{"apannotation:": "apvalue"},
-							},
-							NodePortService: meta.Tags{
-								Labels:      map[string]string{"nodeportlabel": "nodeportval"},
-								Annotations: map[string]string{"nodeportann:": "nodeportvalue"},
-							},
+					CommonLabels: map[string]string{
+						"common": "label",
+					},
+					ServiceConfig: meta.CassandraDatacenterServicesMeta{
+						DatacenterService: meta.Tags{
+							Labels:      map[string]string{"dclabel": "dcvalue"},
+							Annotations: map[string]string{"dcannotation:": "dcvalue"},
+						},
+						SeedService: meta.Tags{
+							Labels:      map[string]string{"seedlabel": "seedvalue"},
+							Annotations: map[string]string{"seedannotation:": "seedvalue"},
+						},
+						AdditionalSeedService: meta.Tags{
+							Labels:      map[string]string{"aslabel": "asvalue"},
+							Annotations: map[string]string{"asannotation:": "asvalue"},
+						},
+						AllPodsService: meta.Tags{
+							Labels:      map[string]string{"aplabel": "apvalue"},
+							Annotations: map[string]string{"apannotation:": "apvalue"},
+						},
+						NodePortService: meta.Tags{
+							Labels:      map[string]string{"nodeportlabel": "nodeportval"},
+							Annotations: map[string]string{"nodeportann:": "nodeportvalue"},
 						},
 					},
 				},
 			},
 			want: &DatacenterConfig{
 				Meta: api.EmbeddedObjectMeta{
-					Metadata: meta.CassandraDatacenterMeta{
-						CommonLabels: map[string]string{
-							"common": "label",
-						},
-						ServiceConfig: meta.CassandraDatacenterServicesMeta{
-							DatacenterService: meta.Tags{
-								Labels:      map[string]string{"dclabel": "dcvalue"},
-								Annotations: map[string]string{"dcannotation:": "dcvalue"},
-							},
-							SeedService: meta.Tags{
-								Labels:      map[string]string{"seedlabel": "seedvalue"},
-								Annotations: map[string]string{"seedannotation:": "seedvalue"},
-							},
-							AdditionalSeedService: meta.Tags{
-								Labels:      map[string]string{"aslabel": "asvalue"},
-								Annotations: map[string]string{"asannotation:": "asvalue"},
-							},
-							AllPodsService: meta.Tags{
-								Labels:      map[string]string{"aplabel": "apvalue"},
-								Annotations: map[string]string{"apannotation:": "apvalue"},
-							},
-							NodePortService: meta.Tags{
-								Labels:      map[string]string{"nodeportlabel": "nodeportval"},
-								Annotations: map[string]string{"nodeportann:": "nodeportvalue"},
-							},
+					CommonLabels: map[string]string{
+						"common": "label",
+					},
+					ServiceConfig: meta.CassandraDatacenterServicesMeta{
+						DatacenterService: meta.Tags{
+							Labels:      map[string]string{"dclabel": "dcvalue"},
+							Annotations: map[string]string{"dcannotation:": "dcvalue"},
+						},
+						SeedService: meta.Tags{
+							Labels:      map[string]string{"seedlabel": "seedvalue"},
+							Annotations: map[string]string{"seedannotation:": "seedvalue"},
+						},
+						AdditionalSeedService: meta.Tags{
+							Labels:      map[string]string{"aslabel": "asvalue"},
+							Annotations: map[string]string{"asannotation:": "asvalue"},
+						},
+						AllPodsService: meta.Tags{
+							Labels:      map[string]string{"aplabel": "apvalue"},
+							Annotations: map[string]string{"apannotation:": "apvalue"},
+						},
+						NodePortService: meta.Tags{
+							Labels:      map[string]string{"nodeportlabel": "nodeportval"},
+							Annotations: map[string]string{"nodeportann:": "nodeportvalue"},
 						},
 					},
 				},
@@ -1215,7 +1187,7 @@ func TestCoalesce(t *testing.T) {
 			name: "Set Cluster & DC Service Tags",
 			clusterTemplate: &api.CassandraClusterTemplate{
 				DatacenterOptions: api.DatacenterOptions{},
-				Meta: meta.CassandraDatacenterMeta{
+				Meta: meta.CassandraClusterMeta{
 					ServiceConfig: meta.CassandraDatacenterServicesMeta{
 						DatacenterService: meta.Tags{
 							Labels:      map[string]string{"dclabel": "cl_value"},
@@ -1243,56 +1215,52 @@ func TestCoalesce(t *testing.T) {
 			dcTemplate: &api.CassandraDatacenterTemplate{
 				DatacenterOptions: api.DatacenterOptions{},
 				Meta: api.EmbeddedObjectMeta{
-					Metadata: meta.CassandraDatacenterMeta{
-						ServiceConfig: meta.CassandraDatacenterServicesMeta{
-							DatacenterService: meta.Tags{
-								Labels:      map[string]string{"dclabel": "dcvalue"},
-								Annotations: map[string]string{"dcannotation:": "dcvalue"},
-							},
-							SeedService: meta.Tags{
-								Labels:      map[string]string{"seedlabel": "seedvalue"},
-								Annotations: map[string]string{"seedannotation:": "seedvalue"},
-							},
-							AdditionalSeedService: meta.Tags{
-								Labels:      map[string]string{"aslabel": "asvalue"},
-								Annotations: map[string]string{"asannotation:": "asvalue"},
-							},
-							AllPodsService: meta.Tags{
-								Labels:      map[string]string{"aplabel": "apvalue"},
-								Annotations: map[string]string{"apannotation:": "apvalue"},
-							},
-							NodePortService: meta.Tags{
-								Labels:      map[string]string{"nodeportlabel": "nodeportval"},
-								Annotations: map[string]string{"nodeportann:": "nodeportvalue"},
-							},
+					ServiceConfig: meta.CassandraDatacenterServicesMeta{
+						DatacenterService: meta.Tags{
+							Labels:      map[string]string{"dclabel": "dcvalue"},
+							Annotations: map[string]string{"dcannotation:": "dcvalue"},
+						},
+						SeedService: meta.Tags{
+							Labels:      map[string]string{"seedlabel": "seedvalue"},
+							Annotations: map[string]string{"seedannotation:": "seedvalue"},
+						},
+						AdditionalSeedService: meta.Tags{
+							Labels:      map[string]string{"aslabel": "asvalue"},
+							Annotations: map[string]string{"asannotation:": "asvalue"},
+						},
+						AllPodsService: meta.Tags{
+							Labels:      map[string]string{"aplabel": "apvalue"},
+							Annotations: map[string]string{"apannotation:": "apvalue"},
+						},
+						NodePortService: meta.Tags{
+							Labels:      map[string]string{"nodeportlabel": "nodeportval"},
+							Annotations: map[string]string{"nodeportann:": "nodeportvalue"},
 						},
 					},
 				},
 			},
 			want: &DatacenterConfig{
 				Meta: api.EmbeddedObjectMeta{
-					Metadata: meta.CassandraDatacenterMeta{
-						ServiceConfig: meta.CassandraDatacenterServicesMeta{
-							DatacenterService: meta.Tags{
-								Labels:      map[string]string{"dclabel": "dcvalue"},
-								Annotations: map[string]string{"dcannotation:": "dcvalue"},
-							},
-							SeedService: meta.Tags{
-								Labels:      map[string]string{"seedlabel": "seedvalue"},
-								Annotations: map[string]string{"seedannotation:": "seedvalue"},
-							},
-							AdditionalSeedService: meta.Tags{
-								Labels:      map[string]string{"aslabel": "asvalue"},
-								Annotations: map[string]string{"asannotation:": "asvalue"},
-							},
-							AllPodsService: meta.Tags{
-								Labels:      map[string]string{"aplabel": "apvalue"},
-								Annotations: map[string]string{"apannotation:": "apvalue"},
-							},
-							NodePortService: meta.Tags{
-								Labels:      map[string]string{"nodeportlabel": "nodeportval", "cl_nodeportlabel": "nodeportval"},
-								Annotations: map[string]string{"nodeportann:": "nodeportvalue", "cl_nodeportann:": "nodeportvalue"},
-							},
+					ServiceConfig: meta.CassandraDatacenterServicesMeta{
+						DatacenterService: meta.Tags{
+							Labels:      map[string]string{"dclabel": "dcvalue"},
+							Annotations: map[string]string{"dcannotation:": "dcvalue"},
+						},
+						SeedService: meta.Tags{
+							Labels:      map[string]string{"seedlabel": "seedvalue"},
+							Annotations: map[string]string{"seedannotation:": "seedvalue"},
+						},
+						AdditionalSeedService: meta.Tags{
+							Labels:      map[string]string{"aslabel": "asvalue"},
+							Annotations: map[string]string{"asannotation:": "asvalue"},
+						},
+						AllPodsService: meta.Tags{
+							Labels:      map[string]string{"aplabel": "apvalue"},
+							Annotations: map[string]string{"apannotation:": "apvalue"},
+						},
+						NodePortService: meta.Tags{
+							Labels:      map[string]string{"nodeportlabel": "nodeportval", "cl_nodeportlabel": "nodeportval"},
+							Annotations: map[string]string{"nodeportann:": "nodeportvalue", "cl_nodeportann:": "nodeportvalue"},
 						},
 					},
 				},
@@ -1509,11 +1477,9 @@ func GetDatacenterConfig() DatacenterConfig {
 		Meta: api.EmbeddedObjectMeta{
 			Namespace: "k8ssandra",
 			Name:      "dc1",
-			Metadata: meta.CassandraDatacenterMeta{
-				Tags: meta.Tags{
-					Labels: map[string]string{
-						"env": "dev",
-					},
+			Tags: meta.Tags{
+				Labels: map[string]string{
+					"env": "dev",
 				},
 			},
 		},