diff --git a/pkg/deployment/deployment_pod_probe_test.go b/pkg/deployment/deployment_pod_probe_test.go new file mode 100644 index 000000000..93efc1782 --- /dev/null +++ b/pkg/deployment/deployment_pod_probe_test.go @@ -0,0 +1,419 @@ +// +// DISCLAIMER +// +// Copyright 2020 ArangoDB GmbH, Cologne, Germany +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// +// Author Adam Janikowski +// + +package deployment + +import ( + "testing" + + api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" + "github.com/arangodb/kube-arangodb/pkg/util" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" + core "k8s.io/api/core/v1" +) + +func TestEnsurePod_ArangoDB_Probe(t *testing.T) { + testCases := []testCaseStruct{ + { + Name: "Agent Pod default probes", + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewString(testImage), + Authentication: noAuthentication, + TLS: noTLS, + }, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.status.last = api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + Agents: api.MemberStatusList{ + firstAgentStatus, + }, + }, + Images: createTestImages(false), + } + testCase.createTestPodData(deployment, api.ServerGroupAgents, firstAgentStatus) + }, + ExpectedEvent: "member agent is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.CreateVolumeEmptyDir(k8sutil.ArangodVolumeName), + }, + Containers: []core.Container{ + { + Name: k8sutil.ServerContainerName, + Image: testImage, + Command: createTestCommandForAgent(firstAgentStatus.ID, false, false, false), + Ports: createTestPorts(), + VolumeMounts: []core.VolumeMount{ + k8sutil.ArangodVolumeMount(), + }, + Resources: emptyResources, + LivenessProbe: createTestLivenessProbe(false, "", k8sutil.ArangoPort), + ImagePullPolicy: core.PullIfNotPresent, + SecurityContext: securityContext.NewSecurityContext(), + }, + }, + RestartPolicy: core.RestartPolicyNever, + TerminationGracePeriodSeconds: &defaultAgentTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupAgentsString + "-" + firstAgentStatus.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupAgentsString, + false, ""), + }, + }, + }, + { + Name: "Agent Pod customized probes", + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewString(testImage), + Authentication: noAuthentication, + TLS: noTLS, + Agents: api.ServerGroupSpec{ + Probes: &api.ServerGroupProbesSpec{ + LivenessProbeSpec: &api.ServerGroupProbeSpec{ + TimeoutSeconds: util.NewInt32(50), + }, + }, + }, + }, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.status.last = api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + Agents: api.MemberStatusList{ + firstAgentStatus, + }, + }, + Images: createTestImages(false), + } + testCase.createTestPodData(deployment, api.ServerGroupAgents, firstAgentStatus) + }, + ExpectedEvent: "member agent is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.CreateVolumeEmptyDir(k8sutil.ArangodVolumeName), + }, + Containers: []core.Container{ + { + Name: k8sutil.ServerContainerName, + Image: testImage, + Command: createTestCommandForAgent(firstAgentStatus.ID, false, false, false), + Ports: createTestPorts(), + VolumeMounts: []core.VolumeMount{ + k8sutil.ArangodVolumeMount(), + }, + Resources: emptyResources, + LivenessProbe: modTestLivenessProbe(false, "", k8sutil.ArangoPort, func(probe *core.Probe) { + probe.TimeoutSeconds = 50 + }), + ImagePullPolicy: core.PullIfNotPresent, + SecurityContext: securityContext.NewSecurityContext(), + }, + }, + RestartPolicy: core.RestartPolicyNever, + TerminationGracePeriodSeconds: &defaultAgentTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupAgentsString + "-" + firstAgentStatus.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupAgentsString, + false, ""), + }, + }, + }, + { + Name: "Agent Pod enabled probes", + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewString(testImage), + Authentication: noAuthentication, + TLS: noTLS, + Agents: api.ServerGroupSpec{ + Probes: &api.ServerGroupProbesSpec{ + LivenessProbeDisabled: util.NewBool(false), + ReadinessProbeDisabled: util.NewBool(false), + }, + }, + }, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.status.last = api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + Agents: api.MemberStatusList{ + firstAgentStatus, + }, + }, + Images: createTestImages(false), + } + testCase.createTestPodData(deployment, api.ServerGroupAgents, firstAgentStatus) + }, + ExpectedEvent: "member agent is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.CreateVolumeEmptyDir(k8sutil.ArangodVolumeName), + }, + Containers: []core.Container{ + { + Name: k8sutil.ServerContainerName, + Image: testImage, + Command: createTestCommandForAgent(firstAgentStatus.ID, false, false, false), + Ports: createTestPorts(), + VolumeMounts: []core.VolumeMount{ + k8sutil.ArangodVolumeMount(), + }, + Resources: emptyResources, + LivenessProbe: createTestLivenessProbe(false, "", k8sutil.ArangoPort), + ReadinessProbe: createTestReadinessSimpleProbe(false, "", k8sutil.ArangoPort), + ImagePullPolicy: core.PullIfNotPresent, + SecurityContext: securityContext.NewSecurityContext(), + }, + }, + RestartPolicy: core.RestartPolicyNever, + TerminationGracePeriodSeconds: &defaultAgentTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupAgentsString + "-" + firstAgentStatus.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupAgentsString, + false, ""), + }, + }, + }, + { + Name: "DBServer Pod default probes", + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewString(testImage), + Authentication: noAuthentication, + TLS: noTLS, + }, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.status.last = api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + DBServers: api.MemberStatusList{ + firstDBServerStatus, + }, + }, + Images: createTestImages(false), + } + testCase.createTestPodData(deployment, api.ServerGroupDBServers, firstDBServerStatus) + }, + ExpectedEvent: "member dbserver is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.CreateVolumeEmptyDir(k8sutil.ArangodVolumeName), + }, + Containers: []core.Container{ + { + Name: k8sutil.ServerContainerName, + Image: testImage, + Command: createTestCommandForDBServer(firstDBServerStatus.ID, false, false, false), + Ports: createTestPorts(), + VolumeMounts: []core.VolumeMount{ + k8sutil.ArangodVolumeMount(), + }, + Resources: emptyResources, + LivenessProbe: createTestLivenessProbe(false, "", k8sutil.ArangoPort), + ImagePullPolicy: core.PullIfNotPresent, + SecurityContext: securityContext.NewSecurityContext(), + }, + }, + RestartPolicy: core.RestartPolicyNever, + TerminationGracePeriodSeconds: &defaultDBServerTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupDBServersString + "-" + firstDBServerStatus.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupDBServersString, + false, ""), + }, + }, + }, + { + Name: "DBServer Pod enabled probes", + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewString(testImage), + Authentication: noAuthentication, + TLS: noTLS, + DBServers: api.ServerGroupSpec{ + Probes: &api.ServerGroupProbesSpec{ + LivenessProbeDisabled: util.NewBool(false), + ReadinessProbeDisabled: util.NewBool(false), + }, + }, + }, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.status.last = api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + DBServers: api.MemberStatusList{ + firstDBServerStatus, + }, + }, + Images: createTestImages(false), + } + testCase.createTestPodData(deployment, api.ServerGroupDBServers, firstDBServerStatus) + }, + ExpectedEvent: "member dbserver is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.CreateVolumeEmptyDir(k8sutil.ArangodVolumeName), + }, + Containers: []core.Container{ + { + Name: k8sutil.ServerContainerName, + Image: testImage, + Command: createTestCommandForDBServer(firstDBServerStatus.ID, false, false, false), + Ports: createTestPorts(), + VolumeMounts: []core.VolumeMount{ + k8sutil.ArangodVolumeMount(), + }, + Resources: emptyResources, + LivenessProbe: createTestLivenessProbe(false, "", k8sutil.ArangoPort), + ReadinessProbe: createTestReadinessSimpleProbe(false, "", k8sutil.ArangoPort), + ImagePullPolicy: core.PullIfNotPresent, + SecurityContext: securityContext.NewSecurityContext(), + }, + }, + RestartPolicy: core.RestartPolicyNever, + TerminationGracePeriodSeconds: &defaultDBServerTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupDBServersString + "-" + firstDBServerStatus.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupDBServersString, + false, ""), + }, + }, + }, + { + Name: "Coordinator Pod default probes", + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewString(testImage), + Authentication: noAuthentication, + TLS: noTLS, + }, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.status.last = api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + Coordinators: api.MemberStatusList{ + firstCoordinatorStatus, + }, + }, + Images: createTestImages(false), + } + testCase.createTestPodData(deployment, api.ServerGroupCoordinators, firstCoordinatorStatus) + }, + ExpectedEvent: "member coordinator is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.CreateVolumeEmptyDir(k8sutil.ArangodVolumeName), + }, + Containers: []core.Container{ + { + Name: k8sutil.ServerContainerName, + Image: testImage, + Command: createTestCommandForCoordinator(firstCoordinatorStatus.ID, false, false, false), + Ports: createTestPorts(), + VolumeMounts: []core.VolumeMount{ + k8sutil.ArangodVolumeMount(), + }, + Resources: emptyResources, + ReadinessProbe: createTestReadinessProbe(false, ""), + ImagePullPolicy: core.PullIfNotPresent, + SecurityContext: securityContext.NewSecurityContext(), + }, + }, + RestartPolicy: core.RestartPolicyNever, + TerminationGracePeriodSeconds: &defaultCoordinatorTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupCoordinatorsString + "-" + firstCoordinatorStatus.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupCoordinatorsString, + false, ""), + }, + }, + }, + { + Name: "Coordinator Pod enabled probes", + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewString(testImage), + Authentication: noAuthentication, + TLS: noTLS, + Coordinators: api.ServerGroupSpec{ + Probes: &api.ServerGroupProbesSpec{ + LivenessProbeDisabled: util.NewBool(false), + ReadinessProbeDisabled: util.NewBool(false), + }, + }, + }, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.status.last = api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + Coordinators: api.MemberStatusList{ + firstCoordinatorStatus, + }, + }, + Images: createTestImages(false), + } + testCase.createTestPodData(deployment, api.ServerGroupCoordinators, firstCoordinatorStatus) + }, + ExpectedEvent: "member coordinator is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.CreateVolumeEmptyDir(k8sutil.ArangodVolumeName), + }, + Containers: []core.Container{ + { + Name: k8sutil.ServerContainerName, + Image: testImage, + Command: createTestCommandForCoordinator(firstCoordinatorStatus.ID, false, false, false), + Ports: createTestPorts(), + VolumeMounts: []core.VolumeMount{ + k8sutil.ArangodVolumeMount(), + }, + Resources: emptyResources, + LivenessProbe: createTestLivenessProbe(false, "", k8sutil.ArangoPort), + ReadinessProbe: createTestReadinessProbe(false, ""), + ImagePullPolicy: core.PullIfNotPresent, + SecurityContext: securityContext.NewSecurityContext(), + }, + }, + RestartPolicy: core.RestartPolicyNever, + TerminationGracePeriodSeconds: &defaultCoordinatorTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupCoordinatorsString + "-" + firstCoordinatorStatus.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupCoordinatorsString, + false, ""), + }, + }, + }, + } + + runTestCases(t, testCases...) +} diff --git a/pkg/deployment/deployment_suite_test.go b/pkg/deployment/deployment_suite_test.go index 0b67cd5cd..f9ba9fe39 100644 --- a/pkg/deployment/deployment_suite_test.go +++ b/pkg/deployment/deployment_suite_test.go @@ -91,6 +91,23 @@ func createTestToken(deployment *Deployment, testCase *testCaseStruct, paths []s return jwt.CreateArangodJwtAuthorizationHeaderAllowedPaths(s, "kube-arangodb", paths) } +func modTestLivenessProbe(secure bool, authorization string, port int, mod func(*core.Probe)) *core.Probe { + probe := createTestLivenessProbe(secure, authorization, port) + + mod(probe) + + return probe +} + +func createTestReadinessSimpleProbe(secure bool, authorization string, port int) *core.Probe { + probe := createTestLivenessProbe(secure, authorization, port) + + probe.InitialDelaySeconds = 15 + probe.PeriodSeconds = 10 + + return probe +} + func createTestLivenessProbe(secure bool, authorization string, port int) *core.Probe { return k8sutil.HTTPProbeConfig{ LocalPath: "/_api/version", diff --git a/pkg/deployment/pod/probes.go b/pkg/deployment/pod/probes.go index 890198eb2..0e266c5fe 100644 --- a/pkg/deployment/pod/probes.go +++ b/pkg/deployment/pod/probes.go @@ -55,14 +55,14 @@ var probeMap = map[api.ServerGroup]probes{ }, api.ServerGroupAgents: { liveness: newProbe(true, true), - readiness: newProbe(false, false), + readiness: newProbe(true, false), }, api.ServerGroupDBServers: { liveness: newProbe(true, true), - readiness: newProbe(false, false), + readiness: newProbe(true, false), }, api.ServerGroupCoordinators: { - liveness: newProbe(false, false), + liveness: newProbe(true, false), readiness: newProbe(true, true), }, api.ServerGroupSyncMasters: { diff --git a/pkg/deployment/resources/pod_creator_probes.go b/pkg/deployment/resources/pod_creator_probes.go index 755187957..0bc39ef33 100644 --- a/pkg/deployment/resources/pod_creator_probes.go +++ b/pkg/deployment/resources/pod_creator_probes.go @@ -144,14 +144,14 @@ func (r *Resources) probeBuilders() map[api.ServerGroup]probeCheckBuilder { }, api.ServerGroupAgents: { liveness: r.probeBuilderLivenessCore, - readiness: nilProbeBuilder, + readiness: r.probeBuilderReadinessSimpleCore, }, api.ServerGroupDBServers: { liveness: r.probeBuilderLivenessCore, - readiness: nilProbeBuilder, + readiness: r.probeBuilderReadinessSimpleCore, }, api.ServerGroupCoordinators: { - liveness: nilProbeBuilder, + liveness: r.probeBuilderLivenessCore, readiness: r.probeBuilderReadinessCore, }, api.ServerGroupSyncMasters: { @@ -184,6 +184,22 @@ func (r *Resources) probeBuilderLivenessCore(spec api.DeploymentSpec, group api. }, nil } +func (r *Resources) probeBuilderReadinessSimpleCore(spec api.DeploymentSpec, group api.ServerGroup, version driver.Version) (*k8sutil.HTTPProbeConfig, error) { + p, err := r.probeBuilderLivenessCore(spec, group, version) + if err != nil { + return nil, err + } + + if p == nil { + return nil, nil + } + + p.InitialDelaySeconds = 15 + p.PeriodSeconds = 10 + + return p, nil +} + func (r *Resources) probeBuilderReadinessCore(spec api.DeploymentSpec, group api.ServerGroup, version driver.Version) (*k8sutil.HTTPProbeConfig, error) { localPath := "/_api/version" switch spec.GetMode() {