Repository: m3db/m3db-operator
Pull request #209 (2020-04-08 03:12:16)

[api] Support custom InitContainers in cluster spec
As mentioned in the chat this morning, this allows user's to kick an initContainer prior to starting up the dbnode.  This allows for things such as getting credentials, or setting up ACLs or network topology or custom storage provisioning.


xmcqueen: this pr looks wrong. I see a commit up there from the previous PR.  Anyway, its good for discussion.
codecov[bot]: # [Codecov](https://codecov.io/gh/m3db/m3db-operator/pull/209?src=pr&el=h1) Report
> Merging [#209](https://codecov.io/gh/m3db/m3db-operator/pull/209?src=pr&el=desc) into [master](https://codecov.io/gh/m3db/m3db-operator/commit/da3587c5a7ab3e531dad04eb3382fff369ab1922&el=desc) will **increase** coverage by `0.02%`.
> The diff coverage is `50.00%`.


[![Impacted file tree graph](https://codecov.io/gh/m3db/m3db-operator/pull/209/graphs/tree.svg?width=650&height=150&src=pr&token=jtHDyWhsto)](https://codecov.io/gh/m3db/m3db-operator/pull/209?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #209      +/-   ##
==========================================
+ Coverage   75.30%   75.33%   +0.02%     
==========================================
  Files          30       30              
  Lines        2098     2104       +6     
==========================================
+ Hits         1580     1585       +5     
- Misses        391      392       +1     
  Partials      127      127              
```


------

[Continue to review full report at Codecov](https://codecov.io/gh/m3db/m3db-operator/pull/209?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/m3db/m3db-operator/pull/209?src=pr&el=footer). Last update [da3587c...d9a7f22](https://codecov.io/gh/m3db/m3db-operator/pull/209?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/docs/api.md b/docs/api.md
index 831950e..0825196 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -63,6 +63,8 @@ ClusterSpec defines the desired state for a M3 cluster to be converge to.
 | hostNetwork | HostNetwork indicates whether M3DB pods should run in the same network namespace as the node its on. This option should be used sparingly due to security concerns outlined in the linked documentation. https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces | bool | false |
 | dnsPolicy | DNSPolicy allows the user to set the pod's DNSPolicy. This is often used in conjunction with HostNetwork.+optional | *corev1.DNSPolicy | false |
 | externalCoordinatorSelector | Specify a \"controlling\" coordinator for the cluster It is expected that there is a separate standalone coordinator cluster It is externally managed - not managed by this operator It is expected to have a service endpoint Setup this db cluster, but do not assume a co-located coordinator Instead provide a selector here so we can point to a separate coordinator service Specify here the labels required for the selector | map[string]string | false |
+| initContainers | Custom setup for db nodes can be done via initContainers Provide the complete spec for the initContainer here If any storage volumes are needed in the initContainer see InitVolumes below | []corev1.Container | false |
+| initVolumes | If the InitContainers require any storage volumes Provide the complete specification for the required Volumes here | []corev1.Volume | false |
 
 [Back to TOC](#table-of-contents)
 
diff --git a/pkg/apis/m3dboperator/v1alpha1/cluster.go b/pkg/apis/m3dboperator/v1alpha1/cluster.go
index 91eefab..66b044f 100644
--- a/pkg/apis/m3dboperator/v1alpha1/cluster.go
+++ b/pkg/apis/m3dboperator/v1alpha1/cluster.go
@@ -286,6 +286,15 @@ type ClusterSpec struct {
 	// Instead provide a selector here so we can point to a separate coordinator service
 	// Specify here the labels required for the selector
 	ExternalCoordinatorSelector map[string]string `json:"externalCoordinatorSelector,omitempty"`
+
+	// Custom setup for db nodes can be done via initContainers
+	// Provide the complete spec for the initContainer here
+	// If any storage volumes are needed in the initContainer see InitVolumes below
+	InitContainers []corev1.Container `json:"initContainers,omitempty"`
+
+	// If the InitContainers require any storage volumes
+	// Provide the complete specification for the required Volumes here
+	InitVolumes []corev1.Volume `json:"initVolumes,omitempty"`
 }
 
 // NodeAffinityTerm represents a node label and a set of label values, any of
diff --git a/pkg/k8sops/m3db/generators.go b/pkg/k8sops/m3db/generators.go
index 6afff29..331e518 100644
--- a/pkg/k8sops/m3db/generators.go
+++ b/pkg/k8sops/m3db/generators.go
@@ -195,6 +195,16 @@ func GenerateStatefulSet(
 		m3dbContainer.Env = append(m3dbContainer.Env, cluster.Spec.EnvVars...)
 	}
 
+	if cluster.Spec.InitContainers != nil && len(cluster.Spec.InitContainers) > 0 {
+		cluster := cluster.DeepCopy()
+		statefulSet.Spec.Template.Spec.InitContainers = append(statefulSet.Spec.Template.Spec.InitContainers, cluster.Spec.InitContainers...)
+	}
+
+	if cluster.Spec.InitVolumes != nil && len(cluster.Spec.InitVolumes) > 0 {
+		cluster := cluster.DeepCopy()
+		statefulSet.Spec.Template.Spec.Volumes = append(statefulSet.Spec.Template.Spec.Volumes, cluster.Spec.InitVolumes...)
+	}
+
 	return statefulSet, nil
 }
 


Test patch:
diff --git a/pkg/k8sops/m3db/generators_test.go b/pkg/k8sops/m3db/generators_test.go
index d0ee669..771652d 100644
--- a/pkg/k8sops/m3db/generators_test.go
+++ b/pkg/k8sops/m3db/generators_test.go
@@ -466,6 +466,28 @@ func TestGenerateStatefulSet(t *testing.T) {
 		diff, _ := messagediff.PrettyDiff(ss, newSS)
 		t.Log(diff)
 	}
+
+	// Test init containers
+	fixture = getFixture("testM3DBCluster.yaml", t)
+	fixture.Spec.InitContainers = []v1.Container{
+		{
+			Name: "init0",
+		},
+	}
+
+	ss = baseSS.DeepCopy()
+	ss.Spec.Template.Spec.InitContainers = []v1.Container{
+		{
+			Name: "init0",
+		},
+	}
+	newSS, err = GenerateStatefulSet(fixture, isolationGroup, *instanceAmount)
+	assert.NoError(t, err)
+	assert.NotNil(t, newSS)
+	if !assert.Equal(t, ss, newSS) {
+		diff, _ := messagediff.PrettyDiff(ss, newSS)
+		t.Log(diff)
+	}
 }
 
 func TestGenerateM3DBService(t *testing.T) {