From e5ad0e8c3b2517232d12b73bafddc887b8f2fbc0 Mon Sep 17 00:00:00 2001 From: mariogiuffrida Date: Tue, 24 May 2022 16:02:39 +0200 Subject: [PATCH] [CDAP-19300] Added Containers Injection, ports overwrite, Dockerfile.test and updated the README --- .gitignore | 1 + Dockerfile.test | 25 ++ README.md | 11 + api/v1alpha1/cdapmaster_types.go | 8 + api/v1alpha1/zz_generated.deepcopy.go | 22 + controllers/cdapmaster_controller.go | 40 +- controllers/deployment.go | 51 ++- controllers/deployment_test.go | 125 ++++++ controllers/spec.go | 19 + .../additional_appfabric_container_a.json | 31 ++ .../additional_appfabric_container_b.json | 31 ++ .../additional_router_container_a.json | 31 ++ .../additional_router_container_b.json | 31 ++ .../testdata/appfabric_multi_container.json | 395 +++++++++++++++++ ...master_cr_multi_additional_containers.json | 416 ++++++++++++++++++ .../testdata/router_multi_container.json | 324 ++++++++++++++ go.mod | 2 + go.sum | 4 + templates/cdap-deployment.yaml | 148 ++++++- templates/cdap-sts.yaml | 133 ++++++ 20 files changed, 1828 insertions(+), 20 deletions(-) create mode 100644 Dockerfile.test create mode 100644 controllers/testdata/additional_appfabric_container_a.json create mode 100644 controllers/testdata/additional_appfabric_container_b.json create mode 100644 controllers/testdata/additional_router_container_a.json create mode 100644 controllers/testdata/additional_router_container_b.json create mode 100644 controllers/testdata/appfabric_multi_container.json create mode 100644 controllers/testdata/cdap_master_cr_multi_additional_containers.json create mode 100644 controllers/testdata/router_multi_container.json diff --git a/.gitignore b/.gitignore index 3864b6dc..d65f29ea 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ anaconda-mode/ *.dylib # Test binary, build with 'go test -c' *.test +!Dockerfile.test # Output of the go coverage tool, specifically when used with LiteIDE *.out ### Vim ### diff --git a/Dockerfile.test b/Dockerfile.test new file mode 100644 index 00000000..f9e54765 --- /dev/null +++ b/Dockerfile.test @@ -0,0 +1,25 @@ +# Build the manager binary +FROM golang:1.16 as tester + +ENV version 1.0.8 +ENV arch amd64 + +# Copy everything in the go src +WORKDIR /go/src/cdap.io/cdap-operator +COPY ./ ./ + +# Install Kubebuilder +RUN curl -L -O "https://github.com/kubernetes-sigs/kubebuilder/releases/download/v${version}/kubebuilder_${version}_linux_${arch}.tar.gz" && \ + tar -zxvf kubebuilder_${version}_linux_${arch}.tar.gz && \ + mv kubebuilder_${version}_linux_${arch} /usr/local/kubebuilder && \ + cp /usr/local/kubebuilder/bin/* /usr/local/bin + +# Install setup-envtest +RUN go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest + +# download envtest 1.19.x for kubebuilder and to set KUBEBUILDER_ASSETS environment variable +RUN $(go env GOPATH)/bin/setup-envtest use -p env 1.19.x > /tmp/setup_envtest.sh && \ + eval `$(go env GOPATH)/bin/setup-envtest use -p env 1.19.x` && \ + rm /tmp/setup_envtest.sh + +CMD make test diff --git a/README.md b/README.md index 07ebc19b..ed7a090f 100644 --- a/README.md +++ b/README.md @@ -82,3 +82,14 @@ rm /tmp/setup_envtest.sh ``` 4. Run `make test` + +#### Running Unit Tests in a Docker image + +From the project root folder build the test image by running the following +``` +docker build -f Dockerfile.test . -t test +``` +Execute the image with +``` +docker run test +``` \ No newline at end of file diff --git a/api/v1alpha1/cdapmaster_types.go b/api/v1alpha1/cdapmaster_types.go index c4e0397f..c6f7285d 100644 --- a/api/v1alpha1/cdapmaster_types.go +++ b/api/v1alpha1/cdapmaster_types.go @@ -172,6 +172,10 @@ type CDAPScalableServiceSpec struct { CDAPServiceSpec `json:",inline"` // Replicas is number of replicas for the service. Replicas *int32 `json:"replicas,omitempty"` + // Containers define any additional containers a service has + // This is a list of containers and can be left blank + // A typical use is to add sidecars for a deployment + Containers []*corev1.Container `json:"containers,omitempty"` } // CDAPExternalServiceSpec defines the base specification for master services that expose to outside of the cluster. @@ -194,6 +198,10 @@ type CDAPStatefulServiceSpec struct { StorageSize string `json:"storageSize,omitempty"` // StorageClassName is the name of the StorageClass for the persistent volume used by the service. StorageClassName *string `json:"storageClassName,omitempty"` + // Containers define any additional containers a service has + // This is a list of containers and can be left blank + // A typical use is to add sidecars for a stateful set + Containers []*corev1.Container `json:"containers,omitempty"` } // AppFabricSpec defines the specification for the AppFabric service. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ac077cfb..edf32df3 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -298,6 +298,17 @@ func (in *CDAPScalableServiceSpec) DeepCopyInto(out *CDAPScalableServiceSpec) { *out = new(int32) **out = **in } + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = make([]*v1.Container, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(v1.Container) + (*in).DeepCopyInto(*out) + } + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CDAPScalableServiceSpec. @@ -407,6 +418,17 @@ func (in *CDAPStatefulServiceSpec) DeepCopyInto(out *CDAPStatefulServiceSpec) { *out = new(string) **out = **in } + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = make([]*v1.Container, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(v1.Container) + (*in).DeepCopyInto(*out) + } + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CDAPStatefulServiceSpec. diff --git a/controllers/cdapmaster_controller.go b/controllers/cdapmaster_controller.go index 2779f5b5..f99423e5 100644 --- a/controllers/cdapmaster_controller.go +++ b/controllers/cdapmaster_controller.go @@ -127,9 +127,43 @@ func ApplyDefaults(resource interface{}) { } // Set the configMapCConf entry for the router and UI service and ports - spec.Config[confRouterServerAddress] = fmt.Sprintf("cdap-%s-%s", r.Name, strings.ToLower(string(serviceRouter))) - spec.Config[confRouterBindPort] = strconv.Itoa(int(*spec.Router.ServicePort)) - spec.Config[confUserInterfaceBindPort] = strconv.Itoa(int(*spec.UserInterface.ServicePort)) + if spec.Config[confRouterServerAddress] == "" { + spec.Config[confRouterServerAddress] = fmt.Sprintf("cdap-%s-%s", r.Name, strings.ToLower(string(serviceRouter))) + } + + if spec.Config[confRouterBindPort] == "" { + spec.Config[confRouterBindPort] = strconv.Itoa(int(*spec.Router.ServicePort)) + } + + if spec.Config[confUserInterfaceBindPort] == "" { + spec.Config[confUserInterfaceBindPort] = strconv.Itoa(int(*spec.UserInterface.ServicePort)) + } + + // Set the default local data directory if it is not set in cdap-cr. + if _, ok := spec.Config[confLocalDataDirKey]; !ok { + spec.Config[confLocalDataDirKey] = confLocalDataDirVal + } + + // Set security secret disk names to be consistent with securitySecret if not overwritten. + if _, ok := spec.Config[confTwillSecurityMasterSecretDiskName]; !ok && spec.SecuritySecret != "" { + spec.Config[confTwillSecurityMasterSecretDiskName] = spec.SecuritySecret + } + if _, ok := spec.Config[confTwillSecurityMasterSecretDiskPath]; !ok && spec.SecuritySecret != "" { + spec.Config[confTwillSecurityMasterSecretDiskPath] = defaultSecuritySecretPath + } + // This configuration makes the default securitySecret available to the workers by default. + // TODO: Add support for secure-by-default configurations. + if _, ok := spec.Config[confTwillSecurityWorkerSecretDiskName]; !ok && spec.SecuritySecret != "" { + spec.Config[confTwillSecurityWorkerSecretDiskName] = spec.SecuritySecret + } + if _, ok := spec.Config[confTwillSecurityWorkerSecretDiskPath]; !ok && spec.SecuritySecret != "" { + spec.Config[confTwillSecurityWorkerSecretDiskPath] = defaultSecuritySecretPath + } + + // Set the default JMX server port if not set and system metrics exporter sidecar is enabled + if _, ok := spec.Config[confJMXServerPort]; spec.SystemMetricsExporter != nil && !ok { + spec.Config[confJMXServerPort] = fmt.Sprint(defaultJMXport) + } // Set the default local data directory if it is not set in cdap-cr. if _, ok := spec.Config[confLocalDataDirKey]; !ok { diff --git a/controllers/deployment.go b/controllers/deployment.go index a36c4808..b384a043 100644 --- a/controllers/deployment.go +++ b/controllers/deployment.go @@ -177,22 +177,30 @@ func buildStatefulSets(master *v1alpha1.CDAPMaster, name string, services Servic // Add each service as a container for _, s := range services { - ss, err := getCDAPServiceSpec(master, s) + statefulSet, err := getCDAPStatefulServiceSpec(master, s) if err != nil { return nil, err } // This happens when the service is optional and disabled in CR // (i.e. service spec is set to nil) - if ss == nil { + if statefulSet == nil { continue } - c, err := serviceContainerSpec(ss, master, dataDir, s) + c, err := serviceContainerSpec(&statefulSet.CDAPServiceSpec, master, dataDir, s) if err != nil { return nil, err } spec = spec.withContainer(c) - if err := addSystemMetricsServiceIfEnabled(spec, master, ss, dataDir, c); err != nil { + + if statefulSet.Containers != nil { + for _, container := range statefulSet.Containers { + additionalContainer := containerSpecFromContainer(container, dataDir) + spec = spec.withContainer(additionalContainer) + } + } + + if err := addSystemMetricsServiceIfEnabled(spec, master, &statefulSet.CDAPServiceSpec, dataDir, c); err != nil { return nil, err } @@ -200,16 +208,16 @@ func buildStatefulSets(master *v1alpha1.CDAPMaster, name string, services Servic spec = spec.addLabel(labelContainerKeyPrefix+s, master.Name) // Mount extra volumes from ConfigMap and Secret - if _, err := spec.addConfigMapVolumes(ss.ConfigMapVolumes); err != nil { + if _, err := spec.addConfigMapVolumes(statefulSet.CDAPServiceSpec.ConfigMapVolumes); err != nil { return nil, err } - if _, err := spec.addSecretVolumes(ss.SecretVolumes); err != nil { + if _, err := spec.addSecretVolumes(statefulSet.CDAPServiceSpec.SecretVolumes); err != nil { return nil, err } - if _, err := spec.addAdditionalVolumes(ss.AdditionalVolumes); err != nil { + if _, err := spec.addAdditionalVolumes(statefulSet.CDAPServiceSpec.AdditionalVolumes); err != nil { return nil, err } - if _, err := spec.addAdditionalVolumeMounts(ss.AdditionalVolumeMounts); err != nil { + if _, err := spec.addAdditionalVolumeMounts(statefulSet.CDAPServiceSpec.AdditionalVolumeMounts); err != nil { return nil, err } } @@ -313,36 +321,49 @@ func buildDeployment(master *v1alpha1.CDAPMaster, name string, services ServiceG // Add each service as a container for _, s := range services { - ss, err := getCDAPServiceSpec(master, s) + scalableSpec, err := getCDAPScalableServiceSpec(master, s) if err != nil { return nil, err } // This happens when the service is optional and disabled in CR // (i.e. service spec is set to nil) - if ss == nil { + if scalableSpec == nil { continue } - c, err := serviceContainerSpec(ss, master, dataDir, s) + c, err := serviceContainerSpec(&scalableSpec.CDAPServiceSpec, master, dataDir, s) if err != nil { return nil, err } spec = spec.withContainer(c) + if scalableSpec.Containers != nil { + for _, container := range scalableSpec.Containers { + additionalContainer := containerSpecFromContainer(container, dataDir) + spec = spec.withContainer(additionalContainer) + } + } + // Adding a label to allow k8s service selector to easily find the pod spec = spec.addLabel(labelContainerKeyPrefix+s, master.Name) // Mount extra volumes from ConfigMap and Secret - if _, err := spec.addConfigMapVolumes(ss.ConfigMapVolumes); err != nil { + if _, err := spec.addConfigMapVolumes(scalableSpec.CDAPServiceSpec.ConfigMapVolumes); err != nil { + return nil, err + } + if _, err := spec.addSecretVolumes(scalableSpec.CDAPServiceSpec.SecretVolumes); err != nil { + return nil, err + } + if _, err := spec.addAdditionalVolumes(scalableSpec.CDAPServiceSpec.AdditionalVolumes); err != nil { return nil, err } - if _, err := spec.addSecretVolumes(ss.SecretVolumes); err != nil { + if _, err := spec.addAdditionalVolumeMounts(scalableSpec.CDAPServiceSpec.AdditionalVolumeMounts); err != nil { return nil, err } - if _, err := spec.addAdditionalVolumes(ss.AdditionalVolumes); err != nil { + if _, err := spec.addAdditionalVolumes(scalableSpec.CDAPServiceSpec.AdditionalVolumes); err != nil { return nil, err } - if _, err := spec.addAdditionalVolumeMounts(ss.AdditionalVolumeMounts); err != nil { + if _, err := spec.addAdditionalVolumeMounts(scalableSpec.CDAPServiceSpec.AdditionalVolumeMounts); err != nil { return nil, err } } diff --git a/controllers/deployment_test.go b/controllers/deployment_test.go index c00bf180..4557c413 100644 --- a/controllers/deployment_test.go +++ b/controllers/deployment_test.go @@ -256,6 +256,131 @@ var _ = Describe("Controller Suite", func() { } }) }) + + Describe("Add additional generic container", func() { + readMaster := func(fileName string) *v1alpha1.CDAPMaster { + master := &v1alpha1.CDAPMaster{} + err := fromJson(fileName, master) + Expect(err).To(BeNil()) + return master + } + readExpectedJson := func(fileName string) []byte { + json, err := ioutil.ReadFile("testdata/" + fileName) + Expect(err).To(BeNil()) + return json + } + diffJson := func(expected, actual []byte) { + opts := jsondiff.DefaultConsoleOptions() + diff, text := jsondiff.Compare(expected, actual, &opts) + Expect(diff.String()).To(Equal(jsondiff.SupersetMatch.String()), text) + } + diffAdditionalContainers := func(containers []corev1.Container, containerName, expectedJsonFilename string) { + var additionalContainer *corev1.Container + for _, c := range containers { + if c.Name == containerName { + additionalContainer = &c + break + } + } + + actualContainerJson, _ := json.Marshal(additionalContainer) + expectedContainerJson := readExpectedJson(expectedJsonFilename) + diffJson(actualContainerJson, expectedContainerJson) + } + It("Multiple Additional containers for Router", func() { + master := readMaster("testdata/cdap_master_cr_multi_additional_containers.json") + emptyLabels := make(map[string]string) + spec, err := buildDeploymentPlanSpec(master, emptyLabels) + Expect(err).To(BeNil()) + objs, err := buildObjectsForDeploymentPlan(spec) + Expect(err).To(BeNil()) + + var strategyHandler DeploymentPlan + strategyHandler.Init() + + for _, obj := range objs { + if o, ok := obj.Obj.(*k8s.Object).Obj.(*appsv1.Deployment); ok { + + if o.Name == getObjName(master, "router") { + containers := o.Spec.Template.Spec.Containers + + Expect(len(containers)).To(BeIdenticalTo(3)) + + diffAdditionalContainers(containers, "test-router-container-a", "additional_router_container_a.json") + diffAdditionalContainers(containers, "test-router-container-b", "additional_router_container_b.json") + } + } + } + }) + It("Multiple Additional container for AppFabric", func() { + master := readMaster("testdata/cdap_master_cr_multi_additional_containers.json") + emptyLabels := make(map[string]string) + spec, err := buildDeploymentPlanSpec(master, emptyLabels) + Expect(err).To(BeNil()) + objs, err := buildObjectsForDeploymentPlan(spec) + Expect(err).To(BeNil()) + + var strategyHandler DeploymentPlan + strategyHandler.Init() + + for _, obj := range objs { + if o, ok := obj.Obj.(*k8s.Object).Obj.(*appsv1.StatefulSet); ok { + if o.Name == getObjName(master, "appFabric") { + containers := o.Spec.Template.Spec.Containers + + Expect(len(containers)).To(BeIdenticalTo(3)) + + diffAdditionalContainers(containers, "test-appfabric-container-a", "additional_appfabric_container_a.json") + diffAdditionalContainers(containers, "test-appfabric-container-b", "additional_appfabric_container_b.json") + } + } + } + }) + It("No Additional container for Router", func() { + master := readMaster("testdata/cdap_master_cr.json") + emptyLabels := make(map[string]string) + spec, err := buildDeploymentPlanSpec(master, emptyLabels) + Expect(err).To(BeNil()) + objs, err := buildObjectsForDeploymentPlan(spec) + Expect(err).To(BeNil()) + + var strategyHandler DeploymentPlan + strategyHandler.Init() + + for _, obj := range objs { + if o, ok := obj.Obj.(*k8s.Object).Obj.(*appsv1.Deployment); ok { + if o.Name == getObjName(master, "router") { + containers := o.Spec.Template.Spec.Containers + + Expect(len(containers)).To(BeIdenticalTo(1)) + Expect(containers[0].Name).To(BeIdenticalTo("router")) + } + } + } + }) + It("No Additional container for AppFabric", func() { + master := readMaster("testdata/cdap_master_cr.json") + emptyLabels := make(map[string]string) + spec, err := buildDeploymentPlanSpec(master, emptyLabels) + Expect(err).To(BeNil()) + objs, err := buildObjectsForDeploymentPlan(spec) + Expect(err).To(BeNil()) + + var strategyHandler DeploymentPlan + strategyHandler.Init() + + for _, obj := range objs { + if o, ok := obj.Obj.(*k8s.Object).Obj.(*appsv1.StatefulSet); ok { + if o.Name == getObjName(master, "appFabric") { + containers := o.Spec.Template.Spec.Containers + + Expect(len(containers)).To(BeIdenticalTo(1)) + Expect(containers[0].Name).To(BeIdenticalTo("appfabric")) + } + } + } + }) + }) }) func TestMergeEnvVars(t *testing.T) { diff --git a/controllers/spec.go b/controllers/spec.go index ac5c99f4..9f0e4991 100644 --- a/controllers/spec.go +++ b/controllers/spec.go @@ -46,6 +46,25 @@ type ContainerSpec struct { ResourceLimits map[string]*resource.Quantity `json:"resourceLimits,omitempty"` DataDir string `json:"dataDir,omitempty"` Lifecycle *corev1.Lifecycle `json:"lifecycle,omitempty"` + Ports []corev1.ContainerPort `json:"ports,omitempty" patchStrategy:"merge" patchMergeKey:"containerPort" protobuf:"bytes,6,rep,name=ports"` + LivenessProbe *corev1.Probe `json:"livenessProbe,omitempty" protobuf:"bytes,10,opt,name=livenessProbe"` + ReadinessProbe *corev1.Probe `json:"readinessProbe,omitempty" protobuf:"bytes,11,opt,name=readinessProbe"` +} + +func containerSpecFromContainer(container *corev1.Container, dataDir string) *ContainerSpec { + additionalContainer := new(ContainerSpec) + additionalContainer.Name = strings.ToLower(container.Name) + additionalContainer.Image = container.Image + additionalContainer.ImagePullPolicy = container.ImagePullPolicy + additionalContainer.WorkingDir = container.WorkingDir + additionalContainer.Args = container.Args + additionalContainer.Env = container.Env + additionalContainer.DataDir = dataDir + additionalContainer.LivenessProbe = container.LivenessProbe + additionalContainer.ReadinessProbe = container.ReadinessProbe + additionalContainer.Ports = container.Ports + + return additionalContainer } func newContainerSpec(master *v1alpha1.CDAPMaster, name, dataDir string) *ContainerSpec { diff --git a/controllers/testdata/additional_appfabric_container_a.json b/controllers/testdata/additional_appfabric_container_a.json new file mode 100644 index 00000000..4e3e75a5 --- /dev/null +++ b/controllers/testdata/additional_appfabric_container_a.json @@ -0,0 +1,31 @@ +{ + "image":"gcr.io/google-samples/hello-app:2.0", + "name":"test-appfabric-container-a", + "readinessProbe":{ + "exec":{ + "command":[ + "ls" + ] + }, + "failureThreshold":3, + "periodSeconds":10, + "successThreshold":1, + "timeoutSeconds":1 + }, + "livenessProbe":{ + "httpGet":{ + "path":"/_authn/200", + "port":3000, + "scheme":"HTTP" + }, + "initialDelaySeconds":30, + "timeoutSeconds":5 + }, + "ports":[ + { + "containerPort":3000, + "name":"test-port", + "protocol":"test-protocol" + } + ] + } \ No newline at end of file diff --git a/controllers/testdata/additional_appfabric_container_b.json b/controllers/testdata/additional_appfabric_container_b.json new file mode 100644 index 00000000..8887d082 --- /dev/null +++ b/controllers/testdata/additional_appfabric_container_b.json @@ -0,0 +1,31 @@ +{ + "image":"gcr.io/google-samples/hello-app:2.0", + "name":"test-appfabric-container-b", + "readinessProbe":{ + "exec":{ + "command":[ + "ls" + ] + }, + "failureThreshold":3, + "periodSeconds":10, + "successThreshold":1, + "timeoutSeconds":1 + }, + "livenessProbe":{ + "httpGet":{ + "path":"/_authn/200", + "port":3000, + "scheme":"HTTP" + }, + "initialDelaySeconds":30, + "timeoutSeconds":5 + }, + "ports":[ + { + "containerPort":3000, + "name":"test-port", + "protocol":"test-protocol" + } + ] + } \ No newline at end of file diff --git a/controllers/testdata/additional_router_container_a.json b/controllers/testdata/additional_router_container_a.json new file mode 100644 index 00000000..e00218db --- /dev/null +++ b/controllers/testdata/additional_router_container_a.json @@ -0,0 +1,31 @@ +{ + "image":"gcr.io/google-samples/hello-app:2.0", + "name":"test-router-container-a", + "readinessProbe":{ + "exec":{ + "command":[ + "ls" + ] + }, + "failureThreshold":3, + "periodSeconds":10, + "successThreshold":1, + "timeoutSeconds":1 + }, + "livenessProbe":{ + "httpGet":{ + "path":"/_authn/200", + "port":3000, + "scheme":"HTTP" + }, + "initialDelaySeconds":30, + "timeoutSeconds":5 + }, + "ports":[ + { + "containerPort":3000, + "name":"test-port", + "protocol":"test-protocol" + } + ] + } \ No newline at end of file diff --git a/controllers/testdata/additional_router_container_b.json b/controllers/testdata/additional_router_container_b.json new file mode 100644 index 00000000..344f0b93 --- /dev/null +++ b/controllers/testdata/additional_router_container_b.json @@ -0,0 +1,31 @@ +{ + "image":"gcr.io/google-samples/hello-app:2.0", + "name":"test-router-container-b", + "readinessProbe":{ + "exec":{ + "command":[ + "ls" + ] + }, + "failureThreshold":3, + "periodSeconds":10, + "successThreshold":1, + "timeoutSeconds":1 + }, + "livenessProbe":{ + "httpGet":{ + "path":"/_authn/200", + "port":3000, + "scheme":"HTTP" + }, + "initialDelaySeconds":30, + "timeoutSeconds":5 + }, + "ports":[ + { + "containerPort":3000, + "name":"test-port", + "protocol":"test-protocol" + } + ] + } \ No newline at end of file diff --git a/controllers/testdata/appfabric_multi_container.json b/controllers/testdata/appfabric_multi_container.json new file mode 100644 index 00000000..d2620e9b --- /dev/null +++ b/controllers/testdata/appfabric_multi_container.json @@ -0,0 +1,395 @@ +{ + "apiVersion": "apps/v1", + "kind": "StatefulSet", + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "8" + }, + "creationTimestamp": null, + "generation": 535, + "labels": { + "cdap.container.AppFabric": "test", + "cdap.instance": "test", + "custom-resource": "v1alpha1.CDAPMaster", + "custom-resource-name": "test", + "custom-resource-namespace": "default", + "using": "controllers.ServiceHandler" + }, + "name": "cdap-test-appfabric", + "namespace": "default", + "ownerReferences": [ + { + "controller": true, + "kind": "*v1alpha1.CDAPMaster", + "name": "test", + "uid": "7aeaad53-4afe-11ea-8611-42010a800022", + "apiVersion": "cdap.cdap.io/v1alpha1", + "blockOwnerDeletion": true + } + ], + "resourceVersion": "1912414", + "selfLink": "/apis/extensions/v1beta1/namespaces/default/deployments/cdap-test-appfabric", + "uid": "7b7154a1-4afe-11ea-8611-42010a800022" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "cdap.container.AppFabric": "test", + "cdap.instance": "test", + "custom-resource": "v1alpha1.CDAPMaster", + "custom-resource-name": "test", + "custom-resource-namespace": "default", + "using": "controllers.ServiceHandler" + } + }, + "serviceName": "cdap-test-appfabric", + "strategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "cdap.container.AppFabric": "test", + "cdap.instance": "test", + "custom-resource": "v1alpha1.CDAPMaster", + "custom-resource-name": "test", + "custom-resource-namespace": "default", + "using": "controllers.ServiceHandler" + } + }, + "spec": { + "containers": [ + { + "args": [ + "io.cdap.cdap.master.environment.k8s.AppFabricServiceMain", + "--env=k8s" + ], + "env": [ + { + "name": "JAVA_HEAPMAX", + "value": "-Xmx62914560" + } + ], + "image": "gcr.io/cloud-data-fusion-images/cloud-data-fusion:6.1.0.5", + "imagePullPolicy": "IfNotPresent", + "name": "appfabric", + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/etc/podinfo", + "name": "podinfo", + "readOnly": true + }, + { + "mountPath": "/etc/cdap/conf", + "name": "cdap-conf", + "readOnly": true + }, + { + "mountPath": "/etc/hadoop/conf", + "name": "hadoop-conf", + "readOnly": true + }, + { + "mountPath": "/opt/cdap/master/system-app-config", + "name": "cdap-sysappconf", + "readOnly": true + }, + { + "mountPath": "/data", + "name": "cdap-test-appfabric-data", + "readOnly": true + }, + { + "mountPath": "/etc/cdap/security", + "name": "cdap-security", + "readOnly": true + }, + { + "mountPath": "/my/config/map/1", + "name": "cdap-cm-vol-my-config-map-1" + }, + { + "mountPath": "/my/config/map/2", + "name": "cdap-cm-vol-my-config-map-2" + }, + { + "mountPath": "/my/secret/1", + "name": "cdap-se-vol-my-secret-1" + } + ] + }, + { + "env": [ + { + "name": "PORT", + "value": "8070" + } + ], + "image": "gcr.io/google-samples/hello-app:2.0", + "imagePullPolicy": "IfNotPresent", + "name": "test-hello", + "readinessProbe": { + "timeoutSeconds": 1, + "exec": { + "command": [ + "ls" + ] + }, + "failureThreshold": 3, + "periodSeconds": 10, + "successThreshold": 1 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/etc/podinfo", + "name": "podinfo", + "readOnly": true + }, + { + "mountPath": "/etc/cdap/conf", + "name": "cdap-conf", + "readOnly": true + }, + { + "mountPath": "/etc/hadoop/conf", + "name": "hadoop-conf", + "readOnly": true + }, + { + "mountPath": "/opt/cdap/master/system-app-config", + "name": "cdap-sysappconf", + "readOnly": true + }, + { + "mountPath": "/data", + "name": "cdap-test-appfabric-data", + "readOnly": true + }, + { + "mountPath": "/etc/cdap/security", + "name": "cdap-security", + "readOnly": true + }, + { + "mountPath": "/my/config/map/1", + "name": "cdap-cm-vol-my-config-map-1" + }, + { + "mountPath": "/my/config/map/2", + "name": "cdap-cm-vol-my-config-map-2" + }, + { + "mountPath": "/my/secret/1", + "name": "cdap-se-vol-my-secret-1" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "initContainers": [ + { + "args": [ + "io.cdap.cdap.master.environment.k8s.StorageMain" + ], + "image": "gcr.io/cloud-data-fusion-images/cloud-data-fusion:6.1.0.5", + "name": "storageinit", + "resources": {}, + "volumeMounts": [ + { + "mountPath": "/etc/podinfo", + "name": "podinfo", + "readOnly": true + }, + { + "mountPath": "/etc/cdap/conf", + "name": "cdap-conf", + "readOnly": true + }, + { + "mountPath": "/etc/hadoop/conf", + "name": "hadoop-conf", + "readOnly": true + }, + { + "mountPath": "/opt/cdap/master/system-app-config", + "name": "cdap-sysappconf", + "readOnly": true + }, + { + "mountPath": "/data", + "name": "cdap-test-appfabric-data" + }, + { + "mountPath": "/etc/cdap/security", + "name": "cdap-security", + "readOnly": true + }, + { + "name": "cdap-cm-vol-my-config-map-1", + "mountPath": "/my/config/map/1" + }, + { + "mountPath": "/my/config/map/2", + "name": "cdap-cm-vol-my-config-map-2" + }, + { + "mountPath": "/my/secret/1", + "name": "cdap-se-vol-my-secret-1" + } + ] + } + ], + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "cdap", + "serviceAccountName": "cdap", + "terminationGracePeriodSeconds": 120, + "volumes": [ + { + "downwardAPI": { + "defaultMode": 420, + "items": [ + { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.labels" + }, + "path": "pod.labels.properties" + }, + { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.name" + }, + "path": "pod.name" + }, + { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.uid" + }, + "path": "pod.uid" + } + ] + }, + "name": "podinfo" + }, + { + "configMap": { + "defaultMode": 420, + "name": "cdap-test-cconf" + }, + "name": "cdap-conf" + }, + { + "configMap": { + "defaultMode": 420, + "name": "cdap-test-hconf" + }, + "name": "hadoop-conf" + }, + { + "configMap": { + "defaultMode": 420, + "name": "cdap-test-sysappconf" + }, + "name": "cdap-sysappconf" + }, + { + "name": "cdap-security", + "secret": { + "defaultMode": 420, + "secretName": "cdap-secret" + } + }, + { + "configMap": { + "defaultMode": 420, + "name": "my-config-map-1" + }, + "name": "cdap-cm-vol-my-config-map-1" + }, + { + "configMap": { + "defaultMode": 420, + "name": "my-config-map-2" + }, + "name": "cdap-cm-vol-my-config-map-2" + }, + { + "name": "cdap-se-vol-my-secret-1", + "secret": { + "defaultMode": 420, + "secretName": "my-secret-1" + } + } + ] + } + }, + "updateStrategy": {}, + "volumeClaimTemplates": [ + { + "metadata": { + "creationTimestamp": null, + "name": "cdap-test-appfabric-data" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "200Gi" + } + } + }, + "status": {} + } + ] + }, + "status": { + "availableReplicas": 1, + "conditions": [ + { + "message": "Deployment has minimum availability.", + "reason": "MinimumReplicasAvailable", + "status": "True", + "type": "Available", + "lastTransitionTime": "2020-02-09T05:39:28Z", + "lastUpdateTime": "2020-02-09T05:39:28Z" + }, + { + "lastTransitionTime": "2020-02-09T05:39:04Z", + "lastUpdateTime": "2020-02-09T08:58:40Z", + "message": "ReplicaSet \"cdap-test-appfabric-5fdddcfcb4\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + } + ], + "observedGeneration": 535, + "readyReplicas": 1, + "replicas": 0, + "updatedReplicas": 1 + } +} \ No newline at end of file diff --git a/controllers/testdata/cdap_master_cr_multi_additional_containers.json b/controllers/testdata/cdap_master_cr_multi_additional_containers.json new file mode 100644 index 00000000..9cde6c45 --- /dev/null +++ b/controllers/testdata/cdap_master_cr_multi_additional_containers.json @@ -0,0 +1,416 @@ +{ + "apiVersion": "cdap.cdap.io/v1alpha1", + "kind": "CDAPMaster", + "metadata": { + "annotations": { + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"cdap.cdap.io/v1alpha1\",\"kind\":\"CDAPMaster\",\"metadata\":{\"annotations\":{},\"name\":\"test\",\"namespace\":\"default\"},\"spec\":{\"appFabric\":{\"resources\":{\"requests\":{\"cpu\":\"100m\",\"memory\":\"100Mi\"}}},\"config\":{\"data.storage.implementation\":\"postgresql\",\"data.storage.sql.jdbc.connection.url\":\"jdbc:postgresql://postgres-postgresql:5432/cdap\",\"data.storage.sql.jdbc.driver.name\":\"org.postgresql.Driver\",\"enable.preview\":\"true\",\"hdfs.user\":\"root\",\"metadata.elasticsearch.cluster.hosts\":\"elasticsearch-master\",\"metadata.storage.implementation\":\"elastic\"},\"image\":\"gcr.io/cloud-data-fusion-images/cloud-data-fusion:6.1.0.0\",\"locationURI\":\"hdfs://hadoop:9000\",\"logs\":{\"resources\":{\"requests\":{\"cpu\":\"100m\",\"memory\":\"100Mi\"}},\"storageSize\":\"100Gi\"},\"messaging\":{\"resources\":{\"requests\":{\"cpu\":\"100m\",\"memory\":\"100Mi\"}},\"storageSize\":\"100Gi\"},\"metadata\":{\"resources\":{\"requests\":{\"cpu\":\"100m\",\"memory\":\"100Mi\"}}},\"metrics\":{\"resources\":{\"requests\":{\"cpu\":\"100m\",\"memory\":\"100Mi\"}},\"storageSize\":\"100Gi\"},\"numPods\":0,\"preview\":{\"resources\":{\"requests\":{\"cpu\":\"100m\",\"memory\":\"100Mi\"}},\"storageSize\":\"100Gi\"},\"router\":{\"resources\":{\"requests\":{\"cpu\":\"100m\",\"memory\":\"100Mi\"}}},\"securitySecret\":\"cdap-secret\",\"serviceAccountName\":\"cdap\",\"userInterface\":{\"resources\":{\"requests\":{\"cpu\":\"100m\",\"memory\":\"100Mi\"}}},\"userInterfaceImage\":\"gcr.io/cloud-data-fusion-images/cloud-data-fusion-ui:6.1.0.0\"}}\n" + }, + "creationTimestamp": "2020-02-09T05:39:03Z", + "finalizers": [ + "sigapps.k8s.io/cleanup" + ], + "generation": 39, + "labels": { + "cdap.instance": "test" + }, + "name": "test", + "namespace": "default", + "resourceVersion": "1897645", + "selfLink": "/apis/cdap.cdap.io/v1alpha1/namespaces/default/cdapmasters/test", + "uid": "7aeaad53-4afe-11ea-8611-42010a800022" + }, + "spec": { + "appFabric": { + "containers": [ + { + "name": "test-appfabric-container-a", + "image": "gcr.io/google-samples/hello-app:2.0", + "ports": [ + { + "containerPort": 3000, + "name": "test-port", + "protocol": "test-protocol" + } + ], + "livenessProbe": { + "httpGet": { + "path": "/_authn/200", + "port": 3000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "timeoutSeconds": 5 + }, + "readinessProbe": { + "exec": { + "command": [ + "ls" + ] + }, + "failureThreshold":3, + "periodSeconds":10, + "successThreshold":1, + "timeoutSeconds":1 + }, + "env": [ + { + "name": "PORT", + "value": "8070" + } + ] + }, + { + "name": "test-appfabric-container-b", + "image": "gcr.io/google-samples/hello-app:2.0", + "ports": [ + { + "containerPort": 3000, + "name": "test-port", + "protocol": "test-protocol" + } + ], + "livenessProbe": { + "httpGet": { + "path": "/_authn/200", + "port": 3000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "timeoutSeconds": 5 + }, + "readinessProbe": { + "exec": { + "command": [ + "ls" + ] + }, + "failureThreshold":3, + "periodSeconds":10, + "successThreshold":1, + "timeoutSeconds":1 + }, + "env": [ + { + "name": "PORT", + "value": "8070" + } + ] + } + ], + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + } + }, + "authentication": { + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + }, + "secretVolumes": { + "secret-key": "/my/secret/key" + } + }, + "config": { + "dashboard.bind.port": "11011", + "data.storage.implementation": "postgresql", + "data.storage.sql.jdbc.connection.url": "jdbc:postgresql://postgres-postgresql:5432/cdap", + "data.storage.sql.jdbc.driver.name": "org.postgresql.Driver", + "enable.preview": "true", + "explore.enabled": "false", + "hdfs.user": "root", + "local.data.dir": "/data", + "metadata.elasticsearch.cluster.hosts": "elasticsearch-master", + "metadata.storage.implementation": "elastic", + "router.bind.port": "11015", + "router.server.address": "cdap-test-router", + "security.authentication.handlerClassName": "io.cdap.cdap.security.server.BasicAuthenticationHandler", + "security.authentication.basic.realmfile": "/opt/cdap/basicauth/basicrealm" + }, + "configMapVolumes": { + "my-config-map-1": "/my/config/map/1", + "my-config-map-2": "/my/config/map/2" + }, + "secretVolumes": { + "my-secret-1": "/my/secret/1" + }, + "image": "gcr.io/cloud-data-fusion-images/cloud-data-fusion:6.1.0.5", + "locationURI": "hdfs://hadoop:9000", + "logs": { + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + }, + "storageSize": "100Gi" + }, + "messaging": { + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + }, + "storageSize": "100Gi" + }, + "metadata": { + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + } + }, + "metrics": { + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + }, + "storageSize": "100Gi" + }, + "preview": { + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + }, + "storageSize": "100Gi" + }, + "runtime": { + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + } + }, + "router": { + "containers": [ + { + "name": "test-router-container-a", + "image": "gcr.io/google-samples/hello-app:2.0", + "ports": [ + { + "containerPort": 3000, + "name": "test-port", + "protocol": "test-protocol" + } + ], + "livenessProbe": { + "httpGet": { + "path": "/_authn/200", + "port": 3000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "timeoutSeconds": 5 + }, + "readinessProbe": { + "exec": { + "command": [ + "ls" + ] + }, + "failureThreshold":3, + "periodSeconds":10, + "successThreshold":1, + "timeoutSeconds":1 + }, + "env": [ + { + "name": "PORT", + "value": "8070" + } + ] + }, + { + "name": "test-router-container-b", + "image": "gcr.io/google-samples/hello-app:2.0", + "ports": [ + { + "containerPort": 3000, + "name": "test-port", + "protocol": "test-protocol" + } + ], + "livenessProbe": { + "httpGet": { + "path": "/_authn/200", + "port": 3000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "timeoutSeconds": 5 + }, + "readinessProbe": { + "exec": { + "command": [ + "ls" + ] + }, + "failureThreshold":3, + "periodSeconds":10, + "successThreshold":1, + "timeoutSeconds":1 + }, + "env": [ + { + "name": "PORT", + "value": "8070" + } + ] + } + ], + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + }, + "secretVolumes": { + "secret-key": "/my/secret/key" + }, + "replicas": 2, + "servicePort": 11015 + }, + "securitySecret": "cdap-secret", + "serviceAccountName": "cdap", + "userInterface": { + "metadata": { + "creationTimestamp": null + }, + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + }, + "servicePort": 11011 + }, + "userInterfaceImage": "gcr.io/cloud-data-fusion-images/cloud-data-fusion-ui:6.1.0.5" + }, + "status": { + "conditions": [ + { + "lastTransitionTime": "2020-02-09T05:39:03Z", + "lastUpdateTime": "2020-02-09T05:39:03Z", + "message": "Not Observed", + "reason": "Init", + "status": "Unknown", + "type": "Ready" + }, + { + "lastTransitionTime": "2020-02-09T05:39:03Z", + "lastUpdateTime": "2020-02-09T05:39:03Z", + "message": "Not Observed", + "reason": "Init", + "status": "Unknown", + "type": "Settled" + }, + { + "lastTransitionTime": "2020-02-09T07:27:06Z", + "lastUpdateTime": "2020-02-09T07:27:06Z", + "message": "Operation cannot be fulfilled on statefulsets.apps \"cdap-test-messaging\": the object has been modified; please apply your changes to the latest version and try again", + "reason": "ErrorSeen", + "status": "True", + "type": "Error" + }, + { + "lastTransitionTime": "2020-02-09T08:59:55Z", + "lastUpdateTime": "2020-02-09T08:59:55Z", + "message": "Version update is inprogress", + "reason": "Start", + "status": "False", + "type": "VersionUpdateInprogress" + }, + { + "lastTransitionTime": "2020-02-09T08:58:22Z", + "lastUpdateTime": "2020-02-09T08:58:22Z", + "message": "Version to be used has been updated ", + "reason": "Start", + "status": "True", + "type": "VersionUpdated" + }, + { + "lastTransitionTime": "2020-02-09T08:58:21Z", + "lastUpdateTime": "2020-02-09T08:58:21Z", + "message": "Version pre-upgrade job is done", + "reason": "Start", + "status": "True", + "type": "VersionPreUpgradeJobDone" + }, + { + "lastTransitionTime": "2020-02-09T08:59:54Z", + "lastUpdateTime": "2020-02-09T08:59:54Z", + "message": "Version post-upgrade job done", + "reason": "Start", + "status": "True", + "type": "VersionPostUpgradeJobDone" + }, + { + "lastTransitionTime": "2020-02-09T08:59:55Z", + "lastUpdateTime": "2020-02-09T08:59:55Z", + "message": "Version upgrade has completed successfully", + "reason": "Start", + "status": "True", + "type": "VersionUpgradeSucceeded" + }, + { + "lastTransitionTime": "2020-02-09T05:50:04Z", + "lastUpdateTime": "2020-02-09T05:50:04Z", + "message": "Version upgrade has failed", + "reason": "Start", + "status": "False", + "type": "VersionUpgradeFailed" + }, + { + "lastTransitionTime": "2020-02-09T08:57:49Z", + "lastUpdateTime": "2020-02-09T08:57:49Z", + "message": "Version downgrade has succeeded", + "reason": "Start", + "status": "False", + "type": "VersionDowngradeSucceeded" + } + ], + "downgradeStartTimeMillis": 1581238652382, + "imageToUse": "gcr.io/cloud-data-fusion-images/cloud-data-fusion:6.1.0.5", + "upgradeStartTimeMillis": 1581238669880, + "userInterfaceImageToUse": "gcr.io/cloud-data-fusion-images/cloud-data-fusion-ui:6.1.0.5" + } +} + diff --git a/controllers/testdata/router_multi_container.json b/controllers/testdata/router_multi_container.json new file mode 100644 index 00000000..9fce2a95 --- /dev/null +++ b/controllers/testdata/router_multi_container.json @@ -0,0 +1,324 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "8" + }, + "creationTimestamp": null, + "generation": 538, + "labels": { + "cdap.container.Router": "test", + "cdap.instance": "test", + "custom-resource": "v1alpha1.CDAPMaster", + "custom-resource-name": "test", + "custom-resource-namespace": "default", + "using": "controllers.ServiceHandler" + }, + "name": "cdap-test-router", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "cdap.cdap.io/v1alpha1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "*v1alpha1.CDAPMaster", + "name": "test", + "uid": "7aeaad53-4afe-11ea-8611-42010a800022" + } + ], + "resourceVersion": "1912761", + "selfLink": "/apis/extensions/v1beta1/namespaces/default/deployments/cdap-test-router", + "uid": "7b58a4ca-4afe-11ea-8611-42010a800022" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 2, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "cdap.container.Router": "test", + "cdap.instance": "test", + "custom-resource": "v1alpha1.CDAPMaster", + "custom-resource-name": "test", + "custom-resource-namespace": "default", + "using": "controllers.ServiceHandler" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "cdap.container.Router": "test", + "cdap.instance": "test", + "custom-resource": "v1alpha1.CDAPMaster", + "custom-resource-name": "test", + "custom-resource-namespace": "default", + "using": "controllers.ServiceHandler" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "PORT", + "value": "8070" + } + ], + "image": "gcr.io/google-samples/hello-app:2.0", + "imagePullPolicy": "IfNotPresent", + "name": "test-hello", + "readinessProbe": { + "exec": { + "command": [ + "ls" + ] + }, + "failureThreshold": 3, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/etc/podinfo", + "name": "podinfo", + "readOnly": true + }, + { + "mountPath": "/etc/cdap/conf", + "name": "cdap-conf", + "readOnly": true + }, + { + "mountPath": "/etc/hadoop/conf", + "name": "hadoop-conf", + "readOnly": true + }, + { + "mountPath": "/opt/cdap/master/system-app-config", + "name": "cdap-sysappconf", + "readOnly": true + }, + { + "mountPath": "/etc/cdap/security", + "name": "cdap-security", + "readOnly": true + }, + { + "mountPath": "/my/config/map/1", + "name": "cdap-cm-vol-my-config-map-1" + }, + { + "name": "cdap-cm-vol-my-config-map-2", + "mountPath": "/my/config/map/2" + }, + { + "mountPath": "/my/secret/1", + "name": "cdap-se-vol-my-secret-1" + }, + { + "mountPath": "/my/secret/key", + "name": "cdap-se-vol-secret-key" + } + ] + }, + { + "args": [ + "io.cdap.cdap.master.environment.k8s.RouterServiceMain", + "--env=k8s" + ], + "env": [ + { + "name": "JAVA_HEAPMAX", + "value": "-Xmx62914560" + } + ], + "image": "gcr.io/cloud-data-fusion-images/cloud-data-fusion:6.1.0.5", + "imagePullPolicy": "IfNotPresent", + "name": "router", + "resources": { + "requests": { + "cpu": "100m", + "memory": "100Mi" + } + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/etc/podinfo", + "name": "podinfo", + "readOnly": true + }, + { + "mountPath": "/etc/cdap/conf", + "name": "cdap-conf", + "readOnly": true + }, + { + "mountPath": "/etc/hadoop/conf", + "name": "hadoop-conf", + "readOnly": true + }, + { + "mountPath": "/opt/cdap/master/system-app-config", + "name": "cdap-sysappconf", + "readOnly": true + }, + { + "mountPath": "/etc/cdap/security", + "name": "cdap-security", + "readOnly": true + }, + { + "mountPath": "/my/config/map/1", + "name": "cdap-cm-vol-my-config-map-1" + }, + { + "name": "cdap-cm-vol-my-config-map-2", + "mountPath": "/my/config/map/2" + }, + { + "mountPath": "/my/secret/1", + "name": "cdap-se-vol-my-secret-1" + }, + { + "mountPath": "/my/secret/key", + "name": "cdap-se-vol-secret-key" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "cdap", + "serviceAccountName": "cdap", + "terminationGracePeriodSeconds": 120, + "volumes": [ + { + "downwardAPI": { + "defaultMode": 420, + "items": [ + { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.labels" + }, + "path": "pod.labels.properties" + }, + { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.name" + }, + "path": "pod.name" + }, + { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.uid" + }, + "path": "pod.uid" + } + ] + }, + "name": "podinfo" + }, + { + "configMap": { + "defaultMode": 420, + "name": "cdap-test-cconf" + }, + "name": "cdap-conf" + }, + { + "configMap": { + "defaultMode": 420, + "name": "cdap-test-hconf" + }, + "name": "hadoop-conf" + }, + { + "configMap": { + "defaultMode": 420, + "name": "cdap-test-sysappconf" + }, + "name": "cdap-sysappconf" + }, + { + "name": "cdap-security", + "secret": { + "defaultMode": 420, + "secretName": "cdap-secret" + } + }, + { + "name": "cdap-cm-vol-my-config-map-1", + "configMap": { + "name": "my-config-map-1" + } + }, + { + "name": "cdap-cm-vol-my-config-map-2", + "configMap": { + "name": "my-config-map-2" + } + }, + { + "name": "cdap-se-vol-my-secret-1", + "secret": { + "defaultMode": 420, + "secretName": "my-secret-1" + } + }, + { + "name": "cdap-se-vol-secret-key", + "secret": { + "secretName": "secret-key" + } + } + ] + } + } + }, + "status": { + "availableReplicas": 2, + "conditions": [ + { + "lastTransitionTime": "2020-02-09T05:39:22Z", + "lastUpdateTime": "2020-02-09T05:39:22Z", + "message": "Deployment has minimum availability.", + "reason": "MinimumReplicasAvailable", + "status": "True", + "type": "Available" + }, + { + "lastTransitionTime": "2020-02-09T05:39:04Z", + "lastUpdateTime": "2020-02-09T08:58:27Z", + "message": "ReplicaSet \"cdap-test-router-79f988f6d7\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + } + ], + "observedGeneration": 538, + "readyReplicas": 2, + "replicas": 2, + "updatedReplicas": 2 + } +} \ No newline at end of file diff --git a/go.mod b/go.mod index 1749d84d..a5a296c8 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,13 @@ module cdap.io/cdap-operator go 1.12 require ( + github.com/coreos/etcd v3.3.15+incompatible // indirect github.com/go-logr/logr v0.1.0 github.com/google/go-cmp v0.5.7 github.com/nsf/jsondiff v0.0.0-20190712045011-8443391ee9b6 github.com/onsi/ginkgo v1.11.0 github.com/onsi/gomega v1.8.1 + github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect k8s.io/api v0.17.2 k8s.io/apimachinery v0.17.2 k8s.io/client-go v0.17.2 diff --git a/go.sum b/go.sum index 160a0652..d9a29bc6 100644 --- a/go.sum +++ b/go.sum @@ -296,11 +296,14 @@ github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= @@ -413,6 +416,7 @@ gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40 gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.5.0 h1:lj9SyhMzyoa38fgFF0oO2T6pjs5IzkLPKfVtxpyCRMM= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/templates/cdap-deployment.yaml b/templates/cdap-deployment.yaml index a4ed238a..9f0d7103 100644 --- a/templates/cdap-deployment.yaml +++ b/templates/cdap-deployment.yaml @@ -71,8 +71,8 @@ spec: priorityClassName: {{.Base.PriorityClassName}} {{end}} terminationGracePeriodSeconds: 120 - {{range $c := .Containers}} containers: + {{range $c := .Containers}} - name: {{$c.Name}} image: {{$c.Image}} workingDir: {{$c.WorkingDir}} @@ -97,7 +97,17 @@ spec: env: {{range $e := $c.Env }} - name: "{{$e.Name}}" - value: "{{$e.Value}}" + {{if $e.Value}} + value: "{{$e.Value}}" + {{end}} + {{if $e.ValueFrom}} + valueFrom: + {{if $e.ValueFrom.SecretKeyRef}} + secretKeyRef: + name: {{$e.ValueFrom.SecretKeyRef.LocalObjectReference.Name}} + key: {{$e.ValueFrom.SecretKeyRef.Key}} + {{end}} + {{end}} {{end}} resources: {{if $c.ResourceRequests}} @@ -112,6 +122,140 @@ spec: {{$k}}: {{$v.String}} {{end}} {{end}} + + {{if $c.LivenessProbe}} + livenessProbe: + {{if $c.LivenessProbe.InitialDelaySeconds }} + initialDelaySeconds: {{$c.LivenessProbe.InitialDelaySeconds }} + {{end}} + {{if $c.LivenessProbe.TimeoutSeconds }} + timeoutSeconds: {{$c.LivenessProbe.TimeoutSeconds }} + {{end}} + {{if $c.LivenessProbe.PeriodSeconds }} + periodSeconds: {{$c.LivenessProbe.PeriodSeconds }} + {{end}} + {{if $c.LivenessProbe.SuccessThreshold }} + successThreshold: {{$c.LivenessProbe.SuccessThreshold }} + {{end}} + {{if $c.LivenessProbe.FailureThreshold }} + failureThreshold: {{$c.LivenessProbe.FailureThreshold }} + {{end}} + + {{if $c.LivenessProbe.Handler}} + + {{if $c.LivenessProbe.Handler.HTTPGet}} + httpGet: + {{if $c.LivenessProbe.Handler.HTTPGet.Path}} + path: {{$c.LivenessProbe.Handler.HTTPGet.Path}} + {{end}} + port: {{$c.LivenessProbe.Handler.HTTPGet.Port}} + {{if $c.LivenessProbe.Handler.HTTPGet.Scheme}} + scheme: {{$c.LivenessProbe.Handler.HTTPGet.Scheme}} + {{end}} + {{if $c.LivenessProbe.Handler.HTTPGet.Host}} + host: {{$c.LivenessProbe.Handler.HTTPGet.Host}} + {{end}} + {{if $c.LivenessProbe.Handler.HTTPGet.HTTPHeaders}} + httpHeaders: + {{range $h := $c.LivenessProbe.Handler.HTTPGet.HTTPHeaders }} + - name: {{$h.Name}} + value: {{$h.Value}} + {{end}} + {{end}} + {{end}} + + {{if $c.LivenessProbe.Handler.Exec}} + exec: + command: + {{range $v := $c.LivenessProbe.Handler.Exec.Command }} + - {{$v}} + {{end}} + {{end}} + + {{if $c.LivenessProbe.Handler.TCPSocket}} + tcpSocket: + port: {{$c.LivenessProbe.Handler.TCPSocket.Port}} + {{end}} + + {{end}} + + {{end}} + + {{if $c.ReadinessProbe}} + readinessProbe: + {{if $c.ReadinessProbe.InitialDelaySeconds }} + initialDelaySeconds: {{$c.ReadinessProbe.InitialDelaySeconds }} + {{end}} + {{if $c.ReadinessProbe.TimeoutSeconds }} + timeoutSeconds: {{$c.ReadinessProbe.TimeoutSeconds }} + {{end}} + {{if $c.ReadinessProbe.PeriodSeconds }} + periodSeconds: {{$c.ReadinessProbe.PeriodSeconds }} + {{end}} + {{if $c.ReadinessProbe.SuccessThreshold }} + successThreshold: {{$c.ReadinessProbe.SuccessThreshold }} + {{end}} + {{if $c.ReadinessProbe.FailureThreshold }} + failureThreshold: {{$c.ReadinessProbe.FailureThreshold }} + {{end}} + {{if $c.ReadinessProbe.Handler}} + + {{if $c.ReadinessProbe.Handler.HTTPGet}} + httpGet: + {{if $c.ReadinessProbe.Handler.HTTPGet.Path}} + path: {{$c.ReadinessProbe.Handler.HTTPGet.Path}} + {{end}} + port: {{$c.ReadinessProbe.Handler.HTTPGet.Port}} + {{if $c.ReadinessProbe.Handler.HTTPGet.Scheme}} + scheme: {{$c.ReadinessProbe.Handler.HTTPGet.Scheme}} + {{end}} + {{if $c.ReadinessProbe.Handler.HTTPGet.Host}} + host: {{$c.ReadinessProbe.Handler.HTTPGet.Host}} + {{end}} + {{if $c.ReadinessProbe.Handler.HTTPGet.HTTPHeaders}} + httpHeaders: + {{range $h := $c.ReadinessProbe.Handler.HTTPGet.HTTPHeaders }} + - name: {{$h.Name}} + value: {{$h.Value}} + {{end}} + {{end}} + {{end}} + + {{if $c.ReadinessProbe.Handler.Exec}} + exec: + command: + {{range $v := $c.ReadinessProbe.Handler.Exec.Command }} + - {{$v}} + {{end}} + {{end}} + + {{if $c.ReadinessProbe.Handler.TCPSocket}} + tcpSocket: + port: {{$c.ReadinessProbe.Handler.TCPSocket.Port}} + {{end}} + + {{end}} + + {{end}} + + {{if $c.Ports}} + ports: + {{range $cp := $c.Ports}} + - containerPort: {{$cp.ContainerPort}} + {{if $cp.Name}} + name: {{$cp.Name}} + {{end}} + {{if $cp.Protocol}} + protocol: {{$cp.Protocol}} + {{end}} + {{if $cp.HostPort}} + hostPort: {{$cp.HostPort}} + {{end}} + {{if $cp.HostIP}} + hostIP: {{$cp.HostIP}} + {{end}} + {{end}} + {{end}} volumeMounts: - name: podinfo mountPath: /etc/podinfo diff --git a/templates/cdap-sts.yaml b/templates/cdap-sts.yaml index 9e62abc1..e271c18d 100644 --- a/templates/cdap-sts.yaml +++ b/templates/cdap-sts.yaml @@ -150,6 +150,139 @@ spec: {{$k}}: {{$v.String}} {{end}} {{end}} + {{if $c.LivenessProbe}} + livenessProbe: + {{if $c.LivenessProbe.InitialDelaySeconds }} + initialDelaySeconds: {{$c.LivenessProbe.InitialDelaySeconds }} + {{end}} + {{if $c.LivenessProbe.TimeoutSeconds }} + timeoutSeconds: {{$c.LivenessProbe.TimeoutSeconds }} + {{end}} + {{if $c.LivenessProbe.PeriodSeconds }} + periodSeconds: {{$c.LivenessProbe.PeriodSeconds }} + {{end}} + {{if $c.LivenessProbe.SuccessThreshold }} + successThreshold: {{$c.LivenessProbe.SuccessThreshold }} + {{end}} + {{if $c.LivenessProbe.FailureThreshold }} + failureThreshold: {{$c.LivenessProbe.FailureThreshold }} + {{end}} + + {{if $c.LivenessProbe.Handler}} + + {{if $c.LivenessProbe.Handler.HTTPGet}} + httpGet: + {{if $c.LivenessProbe.Handler.HTTPGet.Path}} + path: {{$c.LivenessProbe.Handler.HTTPGet.Path}} + {{end}} + port: {{$c.LivenessProbe.Handler.HTTPGet.Port}} + {{if $c.LivenessProbe.Handler.HTTPGet.Scheme}} + scheme: {{$c.LivenessProbe.Handler.HTTPGet.Scheme}} + {{end}} + {{if $c.LivenessProbe.Handler.HTTPGet.Host}} + host: {{$c.LivenessProbe.Handler.HTTPGet.Host}} + {{end}} + {{if $c.LivenessProbe.Handler.HTTPGet.HTTPHeaders}} + httpHeaders: + {{range $h := $c.LivenessProbe.Handler.HTTPGet.HTTPHeaders }} + - name: {{$h.Name}} + value: {{$h.Value}} + {{end}} + {{end}} + {{end}} + + {{if $c.LivenessProbe.Handler.Exec}} + exec: + command: + {{range $v := $c.LivenessProbe.Handler.Exec.Command }} + - {{$v}} + {{end}} + {{end}} + + {{if $c.LivenessProbe.Handler.TCPSocket}} + tcpSocket: + port: {{$c.LivenessProbe.Handler.TCPSocket.Port}} + {{end}} + + {{end}} + + {{end}} + + {{if $c.ReadinessProbe}} + readinessProbe: + {{if $c.ReadinessProbe.InitialDelaySeconds }} + initialDelaySeconds: {{$c.ReadinessProbe.InitialDelaySeconds }} + {{end}} + {{if $c.ReadinessProbe.TimeoutSeconds }} + timeoutSeconds: {{$c.ReadinessProbe.TimeoutSeconds }} + {{end}} + {{if $c.ReadinessProbe.PeriodSeconds }} + periodSeconds: {{$c.ReadinessProbe.PeriodSeconds }} + {{end}} + {{if $c.ReadinessProbe.SuccessThreshold }} + successThreshold: {{$c.ReadinessProbe.SuccessThreshold }} + {{end}} + {{if $c.ReadinessProbe.FailureThreshold }} + failureThreshold: {{$c.ReadinessProbe.FailureThreshold }} + {{end}} + {{if $c.ReadinessProbe.Handler}} + + {{if $c.ReadinessProbe.Handler.HTTPGet}} + httpGet: + {{if $c.ReadinessProbe.Handler.HTTPGet.Path}} + path: {{$c.ReadinessProbe.Handler.HTTPGet.Path}} + {{end}} + port: {{$c.ReadinessProbe.Handler.HTTPGet.Port}} + {{if $c.ReadinessProbe.Handler.HTTPGet.Scheme}} + scheme: {{$c.ReadinessProbe.Handler.HTTPGet.Scheme}} + {{end}} + {{if $c.ReadinessProbe.Handler.HTTPGet.Host}} + host: {{$c.ReadinessProbe.Handler.HTTPGet.Host}} + {{end}} + {{if $c.ReadinessProbe.Handler.HTTPGet.HTTPHeaders}} + httpHeaders: + {{range $h := $c.ReadinessProbe.Handler.HTTPGet.HTTPHeaders }} + - name: {{$h.Name}} + value: {{$h.Value}} + {{end}} + {{end}} + {{end}} + + {{if $c.ReadinessProbe.Handler.Exec}} + exec: + command: + {{range $v := $c.ReadinessProbe.Handler.Exec.Command }} + - {{$v}} + {{end}} + {{end}} + + {{if $c.ReadinessProbe.Handler.TCPSocket}} + tcpSocket: + port: {{$c.ReadinessProbe.Handler.TCPSocket.Port}} + {{end}} + + {{end}} + + {{end}} + + {{if $c.Ports}} + ports: + {{range $cp := $c.Ports}} + - containerPort: {{$cp.ContainerPort}} + {{if $cp.Name}} + name: {{$cp.Name}} + {{end}} + {{if $cp.Protocol}} + protocol: {{$cp.Protocol}} + {{end}} + {{if $cp.HostPort}} + hostPort: {{$cp.HostPort}} + {{end}} + {{if $cp.HostIP}} + hostIP: {{$cp.HostIP}} + {{end}} + {{end}} + {{end}} volumeMounts: - name: podinfo mountPath: /etc/podinfo