From 494d52f236e00d2dfd69ff05380bbdfba0040106 Mon Sep 17 00:00:00 2001 From: Nikita Vaniasin Date: Fri, 8 Sep 2023 12:18:04 +0200 Subject: [PATCH 1/5] Add --deployment.feature.init-containers-copy-limits (default enabled) Copy resource limits to init containers if they are not specified --- CHANGELOG.md | 1 + README.md | 1 + internal/features.yaml | 7 ++ .../deployment_pod_resources_test.go | 63 ++++++++++++ pkg/deployment/deployment_pod_sync_test.go | 95 +++++++++++++++++++ pkg/deployment/deployment_run_test.go | 27 ++++-- pkg/deployment/deployment_suite_test.go | 17 ++-- pkg/deployment/features/init_containers.go | 38 ++++++++ .../resources/pod_creator_arangod.go | 2 +- pkg/deployment/resources/pod_creator_sync.go | 2 +- .../resources/pod_init_containers.go | 41 ++++++++ 11 files changed, 280 insertions(+), 14 deletions(-) create mode 100644 pkg/deployment/features/init_containers.go create mode 100644 pkg/deployment/resources/pod_init_containers.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 866ecc501..81e1b8aa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - (Improvement) Remove PodSchedulingFailure condition instead of setting to false, restart pod if it could not be scheduled - (Feature) Add ArangoMember overrides - (Feature) ArangoMember Removal Priority +- (Feature) Add --deployment.feature.init-containers-copy-limits (default enabled) ## [1.2.32](https://github.com/arangodb/kube-arangodb/tree/1.2.32) (2023-08-07) - (Feature) Backup lifetime - remove Backup once its lifetime has been reached diff --git a/README.md b/README.md index 89c9d8399..3e9554dd1 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ covers individual newer features separately. | Feature | Operator Version | Introduced | ArangoDB Version | ArangoDB Edition | State | Enabled | Flag | Remarks | |:-------------------------------------------------------------------------------------|:-----------------|:-----------|:-----------------|:----------------------|:-------------|:--------|:------------------------------------------------------|:-------------------------------------------------------------------------| +| init-containers-copy-limits | 1.2.33 | 1.2.33 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.init-containers-copy-limits | Copy resource limits to init containers if they are not specified | | [Rebalancer V2](docs/design/features/rebalancer_v2.md) | 1.2.31 | 1.2.31 | >= 3.10.0 | Community, Enterprise | Alpha | False | --deployment.feature.rebalancer-v2 | N/A | | [Secured containers](docs/design/features/secured_containers.md) | 1.2.31 | 1.2.31 | >= 3.8.0 | Community, Enterprise | Alpha | False | --deployment.feature.secured-containers | If set to True Operator will run containers in secure mode | | Version Check V2 | 1.2.31 | 1.2.31 | >= 3.8.0 | Community, Enterprise | Alpha | False | --deployment.feature.upgrade-version-check-V2 | N/A | diff --git a/internal/features.yaml b/internal/features.yaml index f956f3d23..93c1ef349 100644 --- a/internal/features.yaml +++ b/internal/features.yaml @@ -213,3 +213,10 @@ features: state: Alpha - operatorVersion: 1.2.25 state: Production + - name: init-containers-copy-limits + enabled: true + remarks: Copy resource limits to init containers if they are not specified + flag: --deployment.feature.init-containers-copy-limits + releases: + - operatorVersion: 1.2.33 + state: Production diff --git a/pkg/deployment/deployment_pod_resources_test.go b/pkg/deployment/deployment_pod_resources_test.go index 7a6aa66f3..db89bb40c 100644 --- a/pkg/deployment/deployment_pod_resources_test.go +++ b/pkg/deployment/deployment_pod_resources_test.go @@ -120,6 +120,69 @@ func TestEnsurePod_ArangoDB_Resources(t *testing.T) { testCase.createTestPodData(deployment, api.ServerGroupDBServers, firstDBServerStatus) }, ExpectedEvent: "member dbserver is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.CreateVolumeEmptyDir(shared.ArangodVolumeName), + }, + InitContainers: []core.Container{ + createTestLifecycleContainer(emptyResources), + }, + Containers: []core.Container{ + { + Name: shared.ServerContainerName, + Image: testImage, + Command: createTestCommandForDBServer(firstDBServerStatus.ID, false, false, false), + Ports: createTestPorts(api.ServerGroupAgents), + Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered), + VolumeMounts: []core.VolumeMount{ + k8sutil.ArangodVolumeMount(), + }, + LivenessProbe: createTestLivenessProbe(httpProbe, false, "", shared.ServerPortName), + ImagePullPolicy: core.PullIfNotPresent, + SecurityContext: securityContext.NewSecurityContext(), + Env: withDefaultEnvs(t, resourcesUnfiltered), + }, + }, + RestartPolicy: core.RestartPolicyNever, + TerminationGracePeriodSeconds: &defaultDBServerTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupDBServersString + "-" + + firstDBServerStatus.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupDBServersString, + false, ""), + }, + }, + }, + { + Name: "DBserver POD with resource requirements, init-container-copy-limits feature false", + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewType[string](testImage), + Authentication: noAuthentication, + TLS: noTLS, + DBServers: api.ServerGroupSpec{ + Resources: resourcesUnfiltered, + }, + }, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.currentObjectStatus = &api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + DBServers: api.MemberStatusList{ + firstDBServerStatus, + }, + }, + Images: createTestImages(false), + } + deployment.currentObjectStatus.Members.DBServers[0].IsInitialized = true + + testCase.createTestPodData(deployment, api.ServerGroupDBServers, firstDBServerStatus) + }, + ExpectedEvent: "member dbserver is created", + Features: testCaseFeatures{ + InitContainersCopyLimits: util.NewType(false), + }, ExpectedPod: core.Pod{ Spec: core.PodSpec{ Volumes: []core.Volume{ diff --git a/pkg/deployment/deployment_pod_sync_test.go b/pkg/deployment/deployment_pod_sync_test.go index 8621b922b..90f5dc9c7 100644 --- a/pkg/deployment/deployment_pod_sync_test.go +++ b/pkg/deployment/deployment_pod_sync_test.go @@ -1325,6 +1325,101 @@ func TestEnsurePod_Sync_Worker(t *testing.T) { }, }, }, + { + DropInit: true, + Name: "Sync Worker Pod with monitoring, service account, node selector, lifecycle, license " + + "liveness probe, priority class name, resource requirements without alpine, with init-containers-copy-limits feature off", + Features: testCaseFeatures{ + InitContainersCopyLimits: util.NewType(false), + }, + config: Config{ + OperatorImage: testImageOperator, + }, + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewType[string](testImage), + Authentication: noAuthentication, + Sync: api.SyncSpec{ + Enabled: util.NewType[bool](true), + }, + SyncWorkers: api.ServerGroupSpec{ + ServiceAccountName: util.NewType[string](testServiceAccountName), + NodeSelector: nodeSelectorTest, + PriorityClassName: testPriorityClassName, + Resources: resourcesUnfiltered, + }, + License: api.LicenseSpec{ + SecretName: util.NewType[string](testLicense), + }, + }, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.currentObjectStatus = &api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + SyncWorkers: api.MemberStatusList{ + firstSyncWorker, + }, + }, + Images: createTestImages(true), + } + + testCase.createTestPodData(deployment, api.ServerGroupSyncWorkers, firstSyncWorker) + + name := testCase.ArangoDeployment.Spec.Sync.Monitoring.GetTokenSecretName() + auth, err := k8sutil.GetTokenSecret(context.Background(), deployment.GetCachedStatus().Secret().V1().Read(), name) + require.NoError(t, err) + + testCase.ExpectedPod.Spec.Containers[0].LivenessProbe = createTestLivenessProbe("", true, "bearer "+auth, shared.ServerPortName) + }, + ExpectedEvent: "member syncworker is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.LifecycleVolume(), + k8sutil.CreateVolumeWithSecret(shared.MasterJWTSecretVolumeName, testDeploymentName+"-sync-jwt"), + }, + InitContainers: []core.Container{ + createTestLifecycleContainer(emptyResources), + }, + Containers: []core.Container{ + { + Name: shared.ServerContainerName, + Image: testImage, + Command: createTestCommandForSyncWorker(firstSyncWorker.ID, true, true), + Ports: createTestPorts(api.ServerGroupSyncWorkers), + Env: []core.EnvVar{ + k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoSyncMonitoringToken, + testDeploymentName+"-sync-mt", constants.SecretKeyToken), + k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey, + testLicense, constants.SecretKeyToken), + k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodName, "metadata.name"), + k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodNamespace, "metadata.namespace"), + k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeName, "spec.nodeName"), + k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeNameArango, "spec.nodeName"), + }, + ImagePullPolicy: core.PullIfNotPresent, + Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters), + Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered), + SecurityContext: securityContext.NewSecurityContext(), + VolumeMounts: []core.VolumeMount{ + k8sutil.LifecycleVolumeMount(), + k8sutil.MasterJWTVolumeMount(), + }, + }, + }, + PriorityClassName: testPriorityClassName, + RestartPolicy: core.RestartPolicyNever, + ServiceAccountName: testServiceAccountName, + NodeSelector: nodeSelectorTest, + TerminationGracePeriodSeconds: &defaultSyncWorkerTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupSyncWorkersString + "-" + + firstSyncWorker.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupSyncWorkersString, + false, api.ServerGroupDBServersString), + }, + }, + }, } runTestCases(t, testCases...) diff --git a/pkg/deployment/deployment_run_test.go b/pkg/deployment/deployment_run_test.go index 36e3464da..9f667c17e 100644 --- a/pkg/deployment/deployment_run_test.go +++ b/pkg/deployment/deployment_run_test.go @@ -41,7 +41,7 @@ import ( ) func runTestCases(t *testing.T, testCases ...testCaseStruct) { - // This esure idempotency in generated outputs + // This ensures idempotency in generated outputs for i := 0; i < 25; i++ { t.Run(fmt.Sprintf("Iteration %d", i), func(t *testing.T) { for _, testCase := range testCases { @@ -101,6 +101,16 @@ func runTestCase(t *testing.T, testCase testCaseStruct) { f[0].Group), podDataSort()) } + if util.TypeOrDefault(testCase.Features.InitContainersCopyLimits, features.InitContainerCopyLimits().EnabledByDefault()) { + pSpec := &testCase.ExpectedPod.Spec + // ensure all init containers have limits set + for i, c := range pSpec.InitContainers { + if len(c.Resources.Limits) == 0 { + mainContainer := pSpec.Containers[0] + pSpec.InitContainers[i].Resources.Limits = mainContainer.Resources.Limits.DeepCopy() + } + } + } // Create custom resource in the fake kubernetes API _, err := d.deps.Client.Arango().DatabaseV1().ArangoDeployments(testNamespace).Create(context.Background(), d.currentObject, meta.CreateOptions{}) @@ -117,12 +127,17 @@ func runTestCase(t *testing.T, testCase testCaseStruct) { require.Equal(t, testCase.Features.EncryptionRotation, *features.EncryptionRotation().EnabledPointer()) *features.JWTRotation().EnabledPointer() = testCase.Features.JWTRotation *features.TLSSNI().EnabledPointer() = testCase.Features.TLSSNI - if g := testCase.Features.Graceful; g != nil { - *features.GracefulShutdown().EnabledPointer() = *g - } else { - *features.GracefulShutdown().EnabledPointer() = features.GracefulShutdown().EnabledByDefault() - } *features.TLSRotation().EnabledPointer() = testCase.Features.TLSRotation + + fromPtr := func(f features.Feature, b *bool) { + if b != nil { + *f.EnabledPointer() = *b + } else { + *f.EnabledPointer() = f.EnabledByDefault() + } + } + fromPtr(features.GracefulShutdown(), testCase.Features.Graceful) + fromPtr(features.InitContainerCopyLimits(), testCase.Features.InitContainersCopyLimits) } // Set Pending phase diff --git a/pkg/deployment/deployment_suite_test.go b/pkg/deployment/deployment_suite_test.go index 498677dd6..c5170667b 100644 --- a/pkg/deployment/deployment_suite_test.go +++ b/pkg/deployment/deployment_suite_test.go @@ -79,7 +79,7 @@ const ( type testCaseFeatures struct { TLSSNI, TLSRotation, JWTRotation, EncryptionRotation, Version310 bool - Graceful *bool + Graceful, InitContainersCopyLimits *bool } type testCaseStruct struct { @@ -864,7 +864,6 @@ func podDataSort() func(t *testing.T, p *core.Pod) { func addLifecycle(name string, uuidRequired bool, license string, group api.ServerGroup) func(t *testing.T, p *core.Pod) { return func(t *testing.T, p *core.Pod) { if group.IsArangosync() { - return } @@ -894,15 +893,21 @@ func addLifecycle(name string, uuidRequired bool, license string, group api.Serv } if _, ok := k8sutil.GetAnyContainerByName(p.Spec.InitContainers, "init-lifecycle"); !ok { - p.Spec.InitContainers = append([]core.Container{createTestLifecycleContainer(emptyResources)}, p.Spec.InitContainers...) - + p.Spec.InitContainers = append( + []core.Container{createTestLifecycleContainer(emptyResources)}, + p.Spec.InitContainers..., + ) } } if _, ok := k8sutil.GetAnyContainerByName(p.Spec.InitContainers, "uuid"); !ok { binaryPath, _ := os.Executable() - p.Spec.InitContainers = append([]core.Container{k8sutil.ArangodInitContainer("uuid", name, "rocksdb", binaryPath, testImageOperator, uuidRequired, securityContext.NewSecurityContext())}, p.Spec.InitContainers...) - + p.Spec.InitContainers = append( + []core.Container{ + k8sutil.ArangodInitContainer("uuid", name, "rocksdb", binaryPath, testImageOperator, uuidRequired, securityContext.NewSecurityContext()), + }, + p.Spec.InitContainers..., + ) } } } diff --git a/pkg/deployment/features/init_containers.go b/pkg/deployment/features/init_containers.go new file mode 100644 index 000000000..8d00dd7fc --- /dev/null +++ b/pkg/deployment/features/init_containers.go @@ -0,0 +1,38 @@ +// +// DISCLAIMER +// +// Copyright 2023 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 +// + +package features + +func init() { + registerFeature(initContainerCopyLimits) +} + +var initContainerCopyLimits = &feature{ + name: "init-containers-copy-limits", + description: "Copy resource limits to init containers if they are not specified", + version: "3.6.0", + enterpriseRequired: false, + enabledByDefault: true, + hidden: false, +} + +func InitContainerCopyLimits() Feature { + return initContainerCopyLimits +} diff --git a/pkg/deployment/resources/pod_creator_arangod.go b/pkg/deployment/resources/pod_creator_arangod.go index 60299ebed..50c16a3af 100644 --- a/pkg/deployment/resources/pod_creator_arangod.go +++ b/pkg/deployment/resources/pod_creator_arangod.go @@ -513,7 +513,7 @@ func (m *MemberArangoDPod) GetInitContainers(cachedStatus interfaces.Inspector) } } - return initContainers, nil + return applyInitContainersResourceLimits(initContainers, &m.groupSpec.Resources), nil } func (m *MemberArangoDPod) GetFinalizers() []string { diff --git a/pkg/deployment/resources/pod_creator_sync.go b/pkg/deployment/resources/pod_creator_sync.go index 010bcf07d..8dab97ef5 100644 --- a/pkg/deployment/resources/pod_creator_sync.go +++ b/pkg/deployment/resources/pod_creator_sync.go @@ -300,7 +300,7 @@ func (m *MemberSyncPod) GetInitContainers(cachedStatus interfaces.Inspector) ([] initContainers = append(initContainers, c) } - return initContainers, nil + return applyInitContainersResourceLimits(initContainers, &m.groupSpec.Resources), nil } func (m *MemberSyncPod) GetFinalizers() []string { diff --git a/pkg/deployment/resources/pod_init_containers.go b/pkg/deployment/resources/pod_init_containers.go new file mode 100644 index 000000000..e91a93159 --- /dev/null +++ b/pkg/deployment/resources/pod_init_containers.go @@ -0,0 +1,41 @@ +// +// DISCLAIMER +// +// Copyright 2023 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 +// + +package resources + +import ( + core "k8s.io/api/core/v1" + + "github.com/arangodb/kube-arangodb/pkg/deployment/features" +) + +// applyInitContainersResourceLimits updates all passed init containers to ensure that resource limits are set (if such feature is enabled) +func applyInitContainersResourceLimits(initContainers []core.Container, mainContainerResources *core.ResourceRequirements) []core.Container { + if !features.InitContainerCopyLimits().Enabled() || mainContainerResources == nil || len(mainContainerResources.Limits) == 0 { + return initContainers + } + + for i, c := range initContainers { + if len(c.Resources.Limits) == 0 { + initContainers[i].Resources.Limits = mainContainerResources.Limits.DeepCopy() + } + } + return initContainers +} From 225e870f50f207ff9a9d4d2085d6862d91026a41 Mon Sep 17 00:00:00 2001 From: Nikita Vaniasin Date: Wed, 13 Sep 2023 13:14:43 +0200 Subject: [PATCH 2/5] Copy full resources spec, not just limits --- CHANGELOG.md | 2 +- README.md | 2 +- internal/features.yaml | 6 +++--- pkg/deployment/deployment_pod_resources_test.go | 4 ++-- pkg/deployment/deployment_pod_sync_test.go | 4 ++-- pkg/deployment/deployment_run_test.go | 11 +++++++---- pkg/deployment/deployment_suite_test.go | 2 +- pkg/deployment/features/init_containers.go | 12 ++++++------ pkg/deployment/resources/pod_init_containers.go | 5 ++++- 9 files changed, 27 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81e1b8aa3..1266b9ec8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ - (Improvement) Remove PodSchedulingFailure condition instead of setting to false, restart pod if it could not be scheduled - (Feature) Add ArangoMember overrides - (Feature) ArangoMember Removal Priority -- (Feature) Add --deployment.feature.init-containers-copy-limits (default enabled) +- (Feature) Add --deployment.feature.init-containers-copy-resources (default enabled) ## [1.2.32](https://github.com/arangodb/kube-arangodb/tree/1.2.32) (2023-08-07) - (Feature) Backup lifetime - remove Backup once its lifetime has been reached diff --git a/README.md b/README.md index 3e9554dd1..bc1e5227d 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ covers individual newer features separately. | Feature | Operator Version | Introduced | ArangoDB Version | ArangoDB Edition | State | Enabled | Flag | Remarks | |:-------------------------------------------------------------------------------------|:-----------------|:-----------|:-----------------|:----------------------|:-------------|:--------|:------------------------------------------------------|:-------------------------------------------------------------------------| -| init-containers-copy-limits | 1.2.33 | 1.2.33 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.init-containers-copy-limits | Copy resource limits to init containers if they are not specified | +| Copy resources spec to init containers | 1.2.33 | 1.2.33 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.init-containers-copy-resources | Copy resources spec to init containers if they are not specified | | [Rebalancer V2](docs/design/features/rebalancer_v2.md) | 1.2.31 | 1.2.31 | >= 3.10.0 | Community, Enterprise | Alpha | False | --deployment.feature.rebalancer-v2 | N/A | | [Secured containers](docs/design/features/secured_containers.md) | 1.2.31 | 1.2.31 | >= 3.8.0 | Community, Enterprise | Alpha | False | --deployment.feature.secured-containers | If set to True Operator will run containers in secure mode | | Version Check V2 | 1.2.31 | 1.2.31 | >= 3.8.0 | Community, Enterprise | Alpha | False | --deployment.feature.upgrade-version-check-V2 | N/A | diff --git a/internal/features.yaml b/internal/features.yaml index 93c1ef349..582e4e168 100644 --- a/internal/features.yaml +++ b/internal/features.yaml @@ -213,10 +213,10 @@ features: state: Alpha - operatorVersion: 1.2.25 state: Production - - name: init-containers-copy-limits + - name: Copy resources spec to init containers enabled: true - remarks: Copy resource limits to init containers if they are not specified - flag: --deployment.feature.init-containers-copy-limits + remarks: Copy resources spec to init containers if they are not specified + flag: --deployment.feature.init-containers-copy-resources releases: - operatorVersion: 1.2.33 state: Production diff --git a/pkg/deployment/deployment_pod_resources_test.go b/pkg/deployment/deployment_pod_resources_test.go index db89bb40c..93cdd6487 100644 --- a/pkg/deployment/deployment_pod_resources_test.go +++ b/pkg/deployment/deployment_pod_resources_test.go @@ -155,7 +155,7 @@ func TestEnsurePod_ArangoDB_Resources(t *testing.T) { }, }, { - Name: "DBserver POD with resource requirements, init-container-copy-limits feature false", + Name: "DBserver POD with resource requirements, init-container-copy-resources feature false", ArangoDeployment: &api.ArangoDeployment{ Spec: api.DeploymentSpec{ Image: util.NewType[string](testImage), @@ -181,7 +181,7 @@ func TestEnsurePod_ArangoDB_Resources(t *testing.T) { }, ExpectedEvent: "member dbserver is created", Features: testCaseFeatures{ - InitContainersCopyLimits: util.NewType(false), + InitContainersCopyResources: util.NewType(false), }, ExpectedPod: core.Pod{ Spec: core.PodSpec{ diff --git a/pkg/deployment/deployment_pod_sync_test.go b/pkg/deployment/deployment_pod_sync_test.go index 90f5dc9c7..b07865880 100644 --- a/pkg/deployment/deployment_pod_sync_test.go +++ b/pkg/deployment/deployment_pod_sync_test.go @@ -1328,9 +1328,9 @@ func TestEnsurePod_Sync_Worker(t *testing.T) { { DropInit: true, Name: "Sync Worker Pod with monitoring, service account, node selector, lifecycle, license " + - "liveness probe, priority class name, resource requirements without alpine, with init-containers-copy-limits feature off", + "liveness probe, priority class name, resource requirements without alpine, with init-containers-copy-resources feature off", Features: testCaseFeatures{ - InitContainersCopyLimits: util.NewType(false), + InitContainersCopyResources: util.NewType(false), }, config: Config{ OperatorImage: testImageOperator, diff --git a/pkg/deployment/deployment_run_test.go b/pkg/deployment/deployment_run_test.go index 9f667c17e..f7b5aa9b6 100644 --- a/pkg/deployment/deployment_run_test.go +++ b/pkg/deployment/deployment_run_test.go @@ -101,14 +101,17 @@ func runTestCase(t *testing.T, testCase testCaseStruct) { f[0].Group), podDataSort()) } - if util.TypeOrDefault(testCase.Features.InitContainersCopyLimits, features.InitContainerCopyLimits().EnabledByDefault()) { + if util.TypeOrDefault(testCase.Features.InitContainersCopyResources, features.InitContainerCopyResources().EnabledByDefault()) { pSpec := &testCase.ExpectedPod.Spec - // ensure all init containers have limits set + // ensure all init containers have resources set for i, c := range pSpec.InitContainers { + mainContainer := pSpec.Containers[0] if len(c.Resources.Limits) == 0 { - mainContainer := pSpec.Containers[0] pSpec.InitContainers[i].Resources.Limits = mainContainer.Resources.Limits.DeepCopy() } + if len(c.Resources.Requests) == 0 { + pSpec.InitContainers[i].Resources.Requests = mainContainer.Resources.Requests.DeepCopy() + } } } @@ -137,7 +140,7 @@ func runTestCase(t *testing.T, testCase testCaseStruct) { } } fromPtr(features.GracefulShutdown(), testCase.Features.Graceful) - fromPtr(features.InitContainerCopyLimits(), testCase.Features.InitContainersCopyLimits) + fromPtr(features.InitContainerCopyResources(), testCase.Features.InitContainersCopyResources) } // Set Pending phase diff --git a/pkg/deployment/deployment_suite_test.go b/pkg/deployment/deployment_suite_test.go index c5170667b..466c34572 100644 --- a/pkg/deployment/deployment_suite_test.go +++ b/pkg/deployment/deployment_suite_test.go @@ -79,7 +79,7 @@ const ( type testCaseFeatures struct { TLSSNI, TLSRotation, JWTRotation, EncryptionRotation, Version310 bool - Graceful, InitContainersCopyLimits *bool + Graceful, InitContainersCopyResources *bool } type testCaseStruct struct { diff --git a/pkg/deployment/features/init_containers.go b/pkg/deployment/features/init_containers.go index 8d00dd7fc..8d5efdd40 100644 --- a/pkg/deployment/features/init_containers.go +++ b/pkg/deployment/features/init_containers.go @@ -21,18 +21,18 @@ package features func init() { - registerFeature(initContainerCopyLimits) + registerFeature(initContainerCopyResources) } -var initContainerCopyLimits = &feature{ - name: "init-containers-copy-limits", - description: "Copy resource limits to init containers if they are not specified", +var initContainerCopyResources = &feature{ + name: "init-containers-copy-resources", + description: "Copy resources spec to init containers if they are not specified", version: "3.6.0", enterpriseRequired: false, enabledByDefault: true, hidden: false, } -func InitContainerCopyLimits() Feature { - return initContainerCopyLimits +func InitContainerCopyResources() Feature { + return initContainerCopyResources } diff --git a/pkg/deployment/resources/pod_init_containers.go b/pkg/deployment/resources/pod_init_containers.go index e91a93159..2da19cf72 100644 --- a/pkg/deployment/resources/pod_init_containers.go +++ b/pkg/deployment/resources/pod_init_containers.go @@ -28,7 +28,7 @@ import ( // applyInitContainersResourceLimits updates all passed init containers to ensure that resource limits are set (if such feature is enabled) func applyInitContainersResourceLimits(initContainers []core.Container, mainContainerResources *core.ResourceRequirements) []core.Container { - if !features.InitContainerCopyLimits().Enabled() || mainContainerResources == nil || len(mainContainerResources.Limits) == 0 { + if !features.InitContainerCopyResources().Enabled() || mainContainerResources == nil || len(mainContainerResources.Limits) == 0 { return initContainers } @@ -36,6 +36,9 @@ func applyInitContainersResourceLimits(initContainers []core.Container, mainCont if len(c.Resources.Limits) == 0 { initContainers[i].Resources.Limits = mainContainerResources.Limits.DeepCopy() } + if len(c.Resources.Requests) == 0 { + initContainers[i].Resources.Requests = mainContainerResources.Requests.DeepCopy() + } } return initContainers } From 3008160f6bb22e24b7a92e8873feac1f99f51918 Mon Sep 17 00:00:00 2001 From: Nikita Vaniasin Date: Wed, 13 Sep 2023 13:20:46 +0200 Subject: [PATCH 3/5] Rename func --- pkg/deployment/resources/pod_creator_arangod.go | 2 +- pkg/deployment/resources/pod_creator_sync.go | 2 +- pkg/deployment/resources/pod_init_containers.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/deployment/resources/pod_creator_arangod.go b/pkg/deployment/resources/pod_creator_arangod.go index 50c16a3af..ac04f4293 100644 --- a/pkg/deployment/resources/pod_creator_arangod.go +++ b/pkg/deployment/resources/pod_creator_arangod.go @@ -513,7 +513,7 @@ func (m *MemberArangoDPod) GetInitContainers(cachedStatus interfaces.Inspector) } } - return applyInitContainersResourceLimits(initContainers, &m.groupSpec.Resources), nil + return applyInitContainersResourceResources(initContainers, &m.groupSpec.Resources), nil } func (m *MemberArangoDPod) GetFinalizers() []string { diff --git a/pkg/deployment/resources/pod_creator_sync.go b/pkg/deployment/resources/pod_creator_sync.go index 8dab97ef5..1194214d9 100644 --- a/pkg/deployment/resources/pod_creator_sync.go +++ b/pkg/deployment/resources/pod_creator_sync.go @@ -300,7 +300,7 @@ func (m *MemberSyncPod) GetInitContainers(cachedStatus interfaces.Inspector) ([] initContainers = append(initContainers, c) } - return applyInitContainersResourceLimits(initContainers, &m.groupSpec.Resources), nil + return applyInitContainersResourceResources(initContainers, &m.groupSpec.Resources), nil } func (m *MemberSyncPod) GetFinalizers() []string { diff --git a/pkg/deployment/resources/pod_init_containers.go b/pkg/deployment/resources/pod_init_containers.go index 2da19cf72..08cfcf3b2 100644 --- a/pkg/deployment/resources/pod_init_containers.go +++ b/pkg/deployment/resources/pod_init_containers.go @@ -26,8 +26,8 @@ import ( "github.com/arangodb/kube-arangodb/pkg/deployment/features" ) -// applyInitContainersResourceLimits updates all passed init containers to ensure that resource limits are set (if such feature is enabled) -func applyInitContainersResourceLimits(initContainers []core.Container, mainContainerResources *core.ResourceRequirements) []core.Container { +// applyInitContainersResourceResources updates all passed init containers to ensure that resources are set (if such feature is enabled) +func applyInitContainersResourceResources(initContainers []core.Container, mainContainerResources *core.ResourceRequirements) []core.Container { if !features.InitContainerCopyResources().Enabled() || mainContainerResources == nil || len(mainContainerResources.Limits) == 0 { return initContainers } From 57650f6ea62ccfdaee86ae41d9383150740833f4 Mon Sep 17 00:00:00 2001 From: Nikita Vaniasin Date: Thu, 14 Sep 2023 16:23:00 +0200 Subject: [PATCH 4/5] Apply only to containers added by operator itself --- README.md | 52 +++++++++---------- internal/features.yaml | 2 +- pkg/deployment/deployment_run_test.go | 5 +- pkg/deployment/features/init_containers.go | 2 +- .../resources/pod_init_containers.go | 22 ++++++-- 5 files changed, 50 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index bc1e5227d..3f32a719e 100644 --- a/README.md +++ b/README.md @@ -58,32 +58,32 @@ covers individual newer features separately. #### Operator Features -| Feature | Operator Version | Introduced | ArangoDB Version | ArangoDB Edition | State | Enabled | Flag | Remarks | -|:-------------------------------------------------------------------------------------|:-----------------|:-----------|:-----------------|:----------------------|:-------------|:--------|:------------------------------------------------------|:-------------------------------------------------------------------------| -| Copy resources spec to init containers | 1.2.33 | 1.2.33 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.init-containers-copy-resources | Copy resources spec to init containers if they are not specified | -| [Rebalancer V2](docs/design/features/rebalancer_v2.md) | 1.2.31 | 1.2.31 | >= 3.10.0 | Community, Enterprise | Alpha | False | --deployment.feature.rebalancer-v2 | N/A | -| [Secured containers](docs/design/features/secured_containers.md) | 1.2.31 | 1.2.31 | >= 3.8.0 | Community, Enterprise | Alpha | False | --deployment.feature.secured-containers | If set to True Operator will run containers in secure mode | -| Version Check V2 | 1.2.31 | 1.2.31 | >= 3.8.0 | Community, Enterprise | Alpha | False | --deployment.feature.upgrade-version-check-V2 | N/A | -| [Operator Ephemeral Volumes](docs/design/features/ephemeral_volumes.md) | 1.2.31 | 1.2.2 | >= 3.8.0 | Community, Enterprise | Beta | False | --deployment.feature.ephemeral-volumes | N/A | -| [Force Rebuild Out Synced Shards](docs/design/features/rebuild_out_synced_shards.md) | 1.2.27 | 1.2.27 | >= 3.8.0 | Community, Enterprise | Production | False | --deployment.feature.force-rebuild-out-synced-shards | It should be used only if user is aware of the risks. | -| [Spec Default Restore](docs/design/features/deployment_spec_defaults.md) | 1.2.25 | 1.2.21 | >= 3.8.0 | Community, Enterprise | Beta | True | --deployment.feature.deployment-spec-defaults-restore | If set to False Operator will not change ArangoDeployment Spec | -| Version Check | 1.2.23 | 1.1.4 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.upgrade-version-check | N/A | -| [Failover Leader service](docs/design/features/failover_leader_service.md) | 1.2.13 | 1.2.13 | >= 3.8.0 | Community, Enterprise | Production | False | --deployment.feature.failover-leadership | N/A | -| Graceful Restart | 1.2.5 | 1.0.7 | >= 3.8.0 | Community, Enterprise | Production | True | ---deployment.feature.graceful-shutdown | N/A | -| Optional Graceful Restart | 1.2.0 | 1.2.5 | >= 3.8.0 | Community, Enterprise | Production | False | --deployment.feature.optional-graceful-shutdown | N/A | -| Operator Internal Metrics Exporter | 1.2.0 | 1.2.0 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.metrics-exporter | N/A | -| Operator Maintenance Management Support | 1.2.0 | 1.0.7 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.maintenance | N/A | -| Encryption Key Rotation Support | 1.2.0 | 1.0.3 | >= 3.8.0 | Enterprise | NotSupported | False | --deployment.feature.encryption-rotation | N/A | -| TLS Runtime Rotation Support | 1.1.0 | 1.0.4 | >= 3.8.0 | Enterprise | Production | True | --deployment.feature.tls-rotation | N/A | -| JWT Rotation Support | 1.1.0 | 1.0.3 | >= 3.8.0 | Enterprise | Production | True | --deployment.feature.jwt-rotation | N/A | -| Operator Single Mode | 1.0.4 | 1.0.4 | >= 3.8.0 | Community, Enterprise | Production | False | --mode.single | Only 1 instance of Operator allowed in namespace when feature is enabled | -| TLS SNI Support | 1.0.3 | 1.0.3 | >= 3.8.0 | Enterprise | Production | True | --deployment.feature.tls-sni | N/A | -| Disabling of liveness probes | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | -| Pod Disruption Budgets | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | -| Prometheus Metrics Exporter | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | Prometheus required | -| Sidecar Containers | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | -| Volume Claim Templates | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | -| Volume Resizing | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | +| Feature | Operator Version | Introduced | ArangoDB Version | ArangoDB Edition | State | Enabled | Flag | Remarks | +|:-------------------------------------------------------------------------------------|:-----------------|:-----------|:-----------------|:----------------------|:-------------|:--------|:------------------------------------------------------|:--------------------------------------------------------------------------| +| Copy resources spec to init containers | 1.2.33 | 1.2.33 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.init-containers-copy-resources | Copy resources spec to built-in init containers if they are not specified | +| [Rebalancer V2](docs/design/features/rebalancer_v2.md) | 1.2.31 | 1.2.31 | >= 3.10.0 | Community, Enterprise | Alpha | False | --deployment.feature.rebalancer-v2 | N/A | +| [Secured containers](docs/design/features/secured_containers.md) | 1.2.31 | 1.2.31 | >= 3.8.0 | Community, Enterprise | Alpha | False | --deployment.feature.secured-containers | If set to True Operator will run containers in secure mode | +| Version Check V2 | 1.2.31 | 1.2.31 | >= 3.8.0 | Community, Enterprise | Alpha | False | --deployment.feature.upgrade-version-check-V2 | N/A | +| [Operator Ephemeral Volumes](docs/design/features/ephemeral_volumes.md) | 1.2.31 | 1.2.2 | >= 3.8.0 | Community, Enterprise | Beta | False | --deployment.feature.ephemeral-volumes | N/A | +| [Force Rebuild Out Synced Shards](docs/design/features/rebuild_out_synced_shards.md) | 1.2.27 | 1.2.27 | >= 3.8.0 | Community, Enterprise | Production | False | --deployment.feature.force-rebuild-out-synced-shards | It should be used only if user is aware of the risks. | +| [Spec Default Restore](docs/design/features/deployment_spec_defaults.md) | 1.2.25 | 1.2.21 | >= 3.8.0 | Community, Enterprise | Beta | True | --deployment.feature.deployment-spec-defaults-restore | If set to False Operator will not change ArangoDeployment Spec | +| Version Check | 1.2.23 | 1.1.4 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.upgrade-version-check | N/A | +| [Failover Leader service](docs/design/features/failover_leader_service.md) | 1.2.13 | 1.2.13 | >= 3.8.0 | Community, Enterprise | Production | False | --deployment.feature.failover-leadership | N/A | +| Graceful Restart | 1.2.5 | 1.0.7 | >= 3.8.0 | Community, Enterprise | Production | True | ---deployment.feature.graceful-shutdown | N/A | +| Optional Graceful Restart | 1.2.0 | 1.2.5 | >= 3.8.0 | Community, Enterprise | Production | False | --deployment.feature.optional-graceful-shutdown | N/A | +| Operator Internal Metrics Exporter | 1.2.0 | 1.2.0 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.metrics-exporter | N/A | +| Operator Maintenance Management Support | 1.2.0 | 1.0.7 | >= 3.8.0 | Community, Enterprise | Production | True | --deployment.feature.maintenance | N/A | +| Encryption Key Rotation Support | 1.2.0 | 1.0.3 | >= 3.8.0 | Enterprise | NotSupported | False | --deployment.feature.encryption-rotation | N/A | +| TLS Runtime Rotation Support | 1.1.0 | 1.0.4 | >= 3.8.0 | Enterprise | Production | True | --deployment.feature.tls-rotation | N/A | +| JWT Rotation Support | 1.1.0 | 1.0.3 | >= 3.8.0 | Enterprise | Production | True | --deployment.feature.jwt-rotation | N/A | +| Operator Single Mode | 1.0.4 | 1.0.4 | >= 3.8.0 | Community, Enterprise | Production | False | --mode.single | Only 1 instance of Operator allowed in namespace when feature is enabled | +| TLS SNI Support | 1.0.3 | 1.0.3 | >= 3.8.0 | Enterprise | Production | True | --deployment.feature.tls-sni | N/A | +| Disabling of liveness probes | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | +| Pod Disruption Budgets | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | +| Prometheus Metrics Exporter | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | Prometheus required | +| Sidecar Containers | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | +| Volume Claim Templates | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | +| Volume Resizing | 0.3.11 | 0.3.10 | >= 3.8.0 | Community, Enterprise | Production | True | N/A | N/A | diff --git a/internal/features.yaml b/internal/features.yaml index 582e4e168..cbca81a4c 100644 --- a/internal/features.yaml +++ b/internal/features.yaml @@ -215,7 +215,7 @@ features: state: Production - name: Copy resources spec to init containers enabled: true - remarks: Copy resources spec to init containers if they are not specified + remarks: Copy resources spec to built-in init containers if they are not specified flag: --deployment.feature.init-containers-copy-resources releases: - operatorVersion: 1.2.33 diff --git a/pkg/deployment/deployment_run_test.go b/pkg/deployment/deployment_run_test.go index f7b5aa9b6..848c1f21a 100644 --- a/pkg/deployment/deployment_run_test.go +++ b/pkg/deployment/deployment_run_test.go @@ -103,8 +103,11 @@ func runTestCase(t *testing.T, testCase testCaseStruct) { } if util.TypeOrDefault(testCase.Features.InitContainersCopyResources, features.InitContainerCopyResources().EnabledByDefault()) { pSpec := &testCase.ExpectedPod.Spec - // ensure all init containers have resources set + // ensure all "built-in" init containers have resources set for i, c := range pSpec.InitContainers { + if !api.IsReservedServerGroupInitContainerName(c.Name) { + continue + } mainContainer := pSpec.Containers[0] if len(c.Resources.Limits) == 0 { pSpec.InitContainers[i].Resources.Limits = mainContainer.Resources.Limits.DeepCopy() diff --git a/pkg/deployment/features/init_containers.go b/pkg/deployment/features/init_containers.go index 8d5efdd40..27722f7df 100644 --- a/pkg/deployment/features/init_containers.go +++ b/pkg/deployment/features/init_containers.go @@ -26,7 +26,7 @@ func init() { var initContainerCopyResources = &feature{ name: "init-containers-copy-resources", - description: "Copy resources spec to init containers if they are not specified", + description: "Copy resources spec to built-in init containers if they are not specified", version: "3.6.0", enterpriseRequired: false, enabledByDefault: true, diff --git a/pkg/deployment/resources/pod_init_containers.go b/pkg/deployment/resources/pod_init_containers.go index 08cfcf3b2..b386857fa 100644 --- a/pkg/deployment/resources/pod_init_containers.go +++ b/pkg/deployment/resources/pod_init_containers.go @@ -23,21 +23,35 @@ package resources import ( core "k8s.io/api/core/v1" + api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" "github.com/arangodb/kube-arangodb/pkg/deployment/features" ) -// applyInitContainersResourceResources updates all passed init containers to ensure that resources are set (if such feature is enabled) +// applyInitContainersResourceResources updates passed init containers to ensure that resources are set (if such feature is enabled) +// This is applied only to containers added by operator itself func applyInitContainersResourceResources(initContainers []core.Container, mainContainerResources *core.ResourceRequirements) []core.Container { - if !features.InitContainerCopyResources().Enabled() || mainContainerResources == nil || len(mainContainerResources.Limits) == 0 { + if !features.InitContainerCopyResources().Enabled() || mainContainerResources == nil { return initContainers } for i, c := range initContainers { + if !api.IsReservedServerGroupInitContainerName(c.Name) { + continue + } + if len(c.Resources.Limits) == 0 { - initContainers[i].Resources.Limits = mainContainerResources.Limits.DeepCopy() + if mainContainerResources.Limits == nil { + initContainers[i].Resources.Limits = make(core.ResourceList) + } else { + initContainers[i].Resources.Limits = mainContainerResources.Limits.DeepCopy() + } } if len(c.Resources.Requests) == 0 { - initContainers[i].Resources.Requests = mainContainerResources.Requests.DeepCopy() + if mainContainerResources.Requests == nil { + initContainers[i].Resources.Requests = make(core.ResourceList) + } else { + initContainers[i].Resources.Requests = mainContainerResources.Requests.DeepCopy() + } } } return initContainers From 824ae1efa2ee221012f4af1be4640072f9d029f1 Mon Sep 17 00:00:00 2001 From: Nikita Vaniasin Date: Tue, 19 Sep 2023 13:32:44 +0200 Subject: [PATCH 5/5] Ensure all resource types are present --- .../resources/pod_init_containers.go | 19 ++-------- pkg/util/k8sutil/resources.go | 38 +++++++++++++++++++ 2 files changed, 42 insertions(+), 15 deletions(-) create mode 100644 pkg/util/k8sutil/resources.go diff --git a/pkg/deployment/resources/pod_init_containers.go b/pkg/deployment/resources/pod_init_containers.go index b386857fa..90e732ed5 100644 --- a/pkg/deployment/resources/pod_init_containers.go +++ b/pkg/deployment/resources/pod_init_containers.go @@ -25,9 +25,10 @@ import ( api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" ) -// applyInitContainersResourceResources updates passed init containers to ensure that resources are set (if such feature is enabled) +// applyInitContainersResourceResources updates passed init containers to ensure that all resources are set (if such feature is enabled) // This is applied only to containers added by operator itself func applyInitContainersResourceResources(initContainers []core.Container, mainContainerResources *core.ResourceRequirements) []core.Container { if !features.InitContainerCopyResources().Enabled() || mainContainerResources == nil { @@ -39,20 +40,8 @@ func applyInitContainersResourceResources(initContainers []core.Container, mainC continue } - if len(c.Resources.Limits) == 0 { - if mainContainerResources.Limits == nil { - initContainers[i].Resources.Limits = make(core.ResourceList) - } else { - initContainers[i].Resources.Limits = mainContainerResources.Limits.DeepCopy() - } - } - if len(c.Resources.Requests) == 0 { - if mainContainerResources.Requests == nil { - initContainers[i].Resources.Requests = make(core.ResourceList) - } else { - initContainers[i].Resources.Requests = mainContainerResources.Requests.DeepCopy() - } - } + k8sutil.EnsureAllResourcesNotEmpty(mainContainerResources.Limits, &initContainers[i].Resources.Limits) + k8sutil.EnsureAllResourcesNotEmpty(mainContainerResources.Requests, &initContainers[i].Resources.Requests) } return initContainers } diff --git a/pkg/util/k8sutil/resources.go b/pkg/util/k8sutil/resources.go new file mode 100644 index 000000000..e2dc14819 --- /dev/null +++ b/pkg/util/k8sutil/resources.go @@ -0,0 +1,38 @@ +// +// DISCLAIMER +// +// Copyright 2023 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 +// + +package k8sutil + +import ( + core "k8s.io/api/core/v1" +) + +// EnsureAllResourcesNotEmpty copies resource specifications from src to dst if such resource is not defined in dst +func EnsureAllResourcesNotEmpty(src core.ResourceList, dst *core.ResourceList) { + if dst == nil { + l := make(core.ResourceList) + dst = &l + } + for k, v := range src { + if _, ok := (*dst)[k]; !ok { + (*dst)[k] = v.DeepCopy() + } + } +}