mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
[Bugfix] Fix resource propagation to InitContainers (#1418)
This commit is contained in:
parent
fdc6608321
commit
50a672c4e9
14 changed files with 267 additions and 134 deletions
|
@ -23,6 +23,7 @@
|
|||
- (Feature) Add --deployment.feature.init-containers-copy-resources (default enabled)
|
||||
- (Feature) Add maxBackups option to ArangoBackupPolicy
|
||||
- (Improvement) Better detection for AllInSync condition for DC2DC sync status
|
||||
- (Bugfix) Fix resource propagation to InitContainers
|
||||
|
||||
## [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
|
||||
|
|
|
@ -358,7 +358,7 @@ func TestEnsurePod_ArangoDB_Core(t *testing.T) {
|
|||
Image: testImage,
|
||||
Command: createTestCommandForDBServer(firstDBServerStatus.ID, false, false, false),
|
||||
Ports: createTestPorts(api.ServerGroupDBServers),
|
||||
Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered),
|
||||
Resources: k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered),
|
||||
VolumeMounts: []core.VolumeMount{
|
||||
k8sutil.ArangodVolumeMount(),
|
||||
},
|
||||
|
@ -415,7 +415,7 @@ func TestEnsurePod_ArangoDB_Core(t *testing.T) {
|
|||
Image: testImage,
|
||||
Command: createTestCommandForDBServer(firstDBServerStatus.ID, false, false, false),
|
||||
Ports: createTestPorts(api.ServerGroupDBServers),
|
||||
Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered),
|
||||
Resources: k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered),
|
||||
VolumeMounts: []core.VolumeMount{
|
||||
k8sutil.ArangodVolumeMount(),
|
||||
},
|
||||
|
@ -475,7 +475,7 @@ func TestEnsurePod_ArangoDB_Core(t *testing.T) {
|
|||
Image: testImage,
|
||||
Command: createTestCommandForDBServer(firstDBServerStatus.ID, false, false, false),
|
||||
Ports: createTestPorts(api.ServerGroupDBServers),
|
||||
Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered),
|
||||
Resources: k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered),
|
||||
VolumeMounts: []core.VolumeMount{
|
||||
k8sutil.ArangodVolumeMount(),
|
||||
},
|
||||
|
@ -1009,7 +1009,7 @@ func TestEnsurePod_ArangoDB_Core(t *testing.T) {
|
|||
ImagePullPolicy: core.PullIfNotPresent,
|
||||
SecurityContext: securityContext.NewSecurityContext(),
|
||||
},
|
||||
testArangodbInternalExporterContainer(false, true, k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered)),
|
||||
testArangodbInternalExporterContainer(false, true, k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered)),
|
||||
},
|
||||
RestartPolicy: core.RestartPolicyNever,
|
||||
TerminationGracePeriodSeconds: &defaultDBServerTerminationTimeout,
|
||||
|
@ -1064,7 +1064,7 @@ func TestEnsurePod_ArangoDB_Core(t *testing.T) {
|
|||
k8sutil.LifecycleVolume(),
|
||||
},
|
||||
InitContainers: []core.Container{
|
||||
createTestLifecycleContainer(k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered)),
|
||||
createTestLifecycleContainer(k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered)),
|
||||
},
|
||||
Containers: []core.Container{
|
||||
{
|
||||
|
|
|
@ -134,7 +134,7 @@ func TestEnsurePod_ArangoDB_Resources(t *testing.T) {
|
|||
Image: testImage,
|
||||
Command: createTestCommandForDBServer(firstDBServerStatus.ID, false, false, false),
|
||||
Ports: createTestPorts(api.ServerGroupAgents),
|
||||
Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered),
|
||||
Resources: k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered),
|
||||
VolumeMounts: []core.VolumeMount{
|
||||
k8sutil.ArangodVolumeMount(),
|
||||
},
|
||||
|
@ -194,7 +194,7 @@ func TestEnsurePod_ArangoDB_Resources(t *testing.T) {
|
|||
Image: testImage,
|
||||
Command: createTestCommandForDBServer(firstDBServerStatus.ID, false, false, false),
|
||||
Ports: createTestPorts(api.ServerGroupAgents),
|
||||
Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered),
|
||||
Resources: k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered),
|
||||
VolumeMounts: []core.VolumeMount{
|
||||
k8sutil.ArangodVolumeMount(),
|
||||
},
|
||||
|
@ -252,7 +252,7 @@ func TestEnsurePod_ArangoDB_Resources(t *testing.T) {
|
|||
Image: testImage,
|
||||
Command: createTestCommandForDBServer(firstDBServerStatus.ID, false, false, false),
|
||||
Ports: createTestPorts(api.ServerGroupAgents),
|
||||
Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered),
|
||||
Resources: k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered),
|
||||
VolumeMounts: []core.VolumeMount{
|
||||
k8sutil.ArangodVolumeMount(),
|
||||
},
|
||||
|
|
|
@ -1304,7 +1304,7 @@ func TestEnsurePod_Sync_Worker(t *testing.T) {
|
|||
},
|
||||
ImagePullPolicy: core.PullIfNotPresent,
|
||||
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
|
||||
Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered),
|
||||
Resources: k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered),
|
||||
SecurityContext: securityContext.NewSecurityContext(),
|
||||
VolumeMounts: []core.VolumeMount{
|
||||
k8sutil.LifecycleVolumeMount(),
|
||||
|
@ -1399,7 +1399,7 @@ func TestEnsurePod_Sync_Worker(t *testing.T) {
|
|||
},
|
||||
ImagePullPolicy: core.PullIfNotPresent,
|
||||
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
|
||||
Resources: k8sutil.ExtractPodResourceRequirement(resourcesUnfiltered),
|
||||
Resources: k8sutil.ExtractPodAcceptedResourceRequirement(resourcesUnfiltered),
|
||||
SecurityContext: securityContext.NewSecurityContext(),
|
||||
VolumeMounts: []core.VolumeMount{
|
||||
k8sutil.LifecycleVolumeMount(),
|
||||
|
|
|
@ -54,7 +54,7 @@ func ArangodbInternalExporterContainer(image string, args []string, livenessProb
|
|||
Protocol: core.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
Resources: k8sutil.ExtractPodResourceRequirement(resources),
|
||||
Resources: k8sutil.ExtractPodAcceptedResourceRequirement(resources),
|
||||
SecurityContext: k8sutil.CreateSecurityContext(groupSpec.SecurityContext),
|
||||
ImagePullPolicy: core.PullIfNotPresent,
|
||||
VolumeMounts: []core.VolumeMount{k8sutil.LifecycleVolumeMount()},
|
||||
|
|
|
@ -281,7 +281,7 @@ func (a *ArangoDContainer) GetEnvs() ([]core.EnvVar, []core.EnvFromSource) {
|
|||
}
|
||||
|
||||
func (a *ArangoDContainer) GetResourceRequirements() core.ResourceRequirements {
|
||||
return k8sutil.ExtractPodResourceRequirement(a.arangoMember.Spec.Overrides.GetResources(&a.groupSpec))
|
||||
return k8sutil.ExtractPodAcceptedResourceRequirement(a.arangoMember.Spec.Overrides.GetResources(&a.groupSpec))
|
||||
}
|
||||
|
||||
func (a *ArangoDContainer) GetLifecycle() (*core.Lifecycle, error) {
|
||||
|
@ -513,7 +513,7 @@ func (m *MemberArangoDPod) GetInitContainers(cachedStatus interfaces.Inspector)
|
|||
}
|
||||
}
|
||||
|
||||
return applyInitContainersResourceResources(initContainers, &m.groupSpec.Resources), nil
|
||||
return applyInitContainersResourceResources(initContainers, k8sutil.ExtractPodInitContainerAcceptedResourceRequirement(m.GetContainerCreator().GetResourceRequirements())), nil
|
||||
}
|
||||
|
||||
func (m *MemberArangoDPod) GetFinalizers() []string {
|
||||
|
|
|
@ -148,7 +148,7 @@ func (a *ArangoSyncContainer) GetProbes() (*core.Probe, *core.Probe, *core.Probe
|
|||
}
|
||||
|
||||
func (a *ArangoSyncContainer) GetResourceRequirements() core.ResourceRequirements {
|
||||
return k8sutil.ExtractPodResourceRequirement(a.arangoMember.Spec.Overrides.GetResources(&a.groupSpec))
|
||||
return k8sutil.ExtractPodAcceptedResourceRequirement(a.arangoMember.Spec.Overrides.GetResources(&a.groupSpec))
|
||||
}
|
||||
|
||||
func (a *ArangoSyncContainer) GetLifecycle() (*core.Lifecycle, error) {
|
||||
|
@ -300,7 +300,7 @@ func (m *MemberSyncPod) GetInitContainers(cachedStatus interfaces.Inspector) ([]
|
|||
initContainers = append(initContainers, c)
|
||||
}
|
||||
|
||||
return applyInitContainersResourceResources(initContainers, &m.groupSpec.Resources), nil
|
||||
return applyInitContainersResourceResources(initContainers, k8sutil.ExtractPodInitContainerAcceptedResourceRequirement(m.GetContainerCreator().GetResourceRequirements())), nil
|
||||
}
|
||||
|
||||
func (m *MemberSyncPod) GetFinalizers() []string {
|
||||
|
|
|
@ -30,18 +30,17 @@ import (
|
|||
|
||||
// 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 {
|
||||
func applyInitContainersResourceResources(initContainers []core.Container, mainContainerResources core.ResourceRequirements) []core.Container {
|
||||
if !features.InitContainerCopyResources().Enabled() {
|
||||
return initContainers
|
||||
}
|
||||
|
||||
for i, c := range initContainers {
|
||||
if !api.IsReservedServerGroupInitContainerName(c.Name) {
|
||||
for i := range initContainers {
|
||||
if !api.IsReservedServerGroupInitContainerName(initContainers[i].Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
k8sutil.EnsureAllResourcesNotEmpty(mainContainerResources.Limits, &initContainers[i].Resources.Limits)
|
||||
k8sutil.EnsureAllResourcesNotEmpty(mainContainerResources.Requests, &initContainers[i].Resources.Requests)
|
||||
k8sutil.ApplyContainerResourceRequirements(&initContainers[i], mainContainerResources)
|
||||
}
|
||||
return initContainers
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func InitLifecycleContainer(image string, resources *core.ResourceRequirements,
|
|||
}
|
||||
|
||||
if resources != nil {
|
||||
c.Resources = ExtractPodResourceRequirement(*resources)
|
||||
c.Resources = ExtractPodAcceptedResourceRequirement(*resources)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
|
|
@ -532,38 +532,6 @@ func operatorInitContainer(name, operatorImage string, command []string, securit
|
|||
return c
|
||||
}
|
||||
|
||||
// ExtractPodResourceRequirement filters resource requirements for Pods.
|
||||
func ExtractPodResourceRequirement(resources core.ResourceRequirements) core.ResourceRequirements {
|
||||
filter := PodResourceRequirementsFilter(core.ResourceCPU, core.ResourceMemory, core.ResourceEphemeralStorage)
|
||||
|
||||
return core.ResourceRequirements{
|
||||
Limits: filter(resources.Limits),
|
||||
Requests: filter(resources.Requests),
|
||||
}
|
||||
}
|
||||
|
||||
func PodResourceRequirementsFilter(filters ...core.ResourceName) func(in core.ResourceList) core.ResourceList {
|
||||
return func(in core.ResourceList) core.ResourceList {
|
||||
filtered := map[core.ResourceName]bool{}
|
||||
|
||||
for _, k := range filters {
|
||||
filtered[k] = true
|
||||
}
|
||||
|
||||
n := core.ResourceList{}
|
||||
|
||||
for k, v := range in {
|
||||
if _, ok := filtered[k]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
n[k] = v
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
// NewContainer creates a container for specified creator
|
||||
func NewContainer(containerCreator interfaces.ContainerCreator) (core.Container, error) {
|
||||
|
||||
|
|
|
@ -22,17 +22,14 @@ package k8sutil
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
core "k8s.io/api/core/v1"
|
||||
resource "k8s.io/apimachinery/pkg/api/resource"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/handlers/utils"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/constants"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
|
||||
)
|
||||
|
@ -419,61 +416,3 @@ func Test_EnsureFinalizer(t *testing.T) {
|
|||
require.NotContains(t, pod.Finalizers, f)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ExtractPodResourceRequirement(t *testing.T) {
|
||||
v, err := resource.ParseQuantity("1Gi")
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Filter Storage", func(t *testing.T) {
|
||||
in := core.ResourceRequirements{
|
||||
Limits: map[core.ResourceName]resource.Quantity{
|
||||
core.ResourceCPU: v,
|
||||
core.ResourceStorage: v,
|
||||
},
|
||||
}
|
||||
require.Len(t, in.Limits, 2)
|
||||
require.Len(t, in.Requests, 0)
|
||||
|
||||
out := ExtractPodResourceRequirement(in)
|
||||
require.Len(t, out.Limits, 1)
|
||||
require.Contains(t, out.Limits, core.ResourceCPU)
|
||||
require.NotContains(t, out.Limits, core.ResourceStorage)
|
||||
require.Len(t, out.Requests, 0)
|
||||
})
|
||||
|
||||
t.Run("Ensure that all required Resources are filtered", func(t *testing.T) {
|
||||
resources := map[core.ResourceName]bool{
|
||||
core.ResourceCPU: true,
|
||||
core.ResourceMemory: true,
|
||||
core.ResourceStorage: false,
|
||||
core.ResourceEphemeralStorage: true,
|
||||
}
|
||||
|
||||
in := core.ResourceRequirements{
|
||||
Limits: core.ResourceList{},
|
||||
Requests: core.ResourceList{},
|
||||
}
|
||||
|
||||
for k := range resources {
|
||||
in.Limits[k] = v
|
||||
in.Requests[k] = v
|
||||
}
|
||||
|
||||
out := ExtractPodResourceRequirement(in)
|
||||
|
||||
for k, v := range resources {
|
||||
t.Run(fmt.Sprintf("Resource %s should be %s", k, util.BoolSwitch(v, "present", "missing")), func(t *testing.T) {
|
||||
require.Contains(t, in.Requests, k)
|
||||
require.Contains(t, in.Limits, k)
|
||||
|
||||
if v {
|
||||
require.Contains(t, out.Requests, k)
|
||||
require.Contains(t, out.Limits, k)
|
||||
} else {
|
||||
require.NotContains(t, out.Requests, k)
|
||||
require.NotContains(t, out.Limits, k)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -60,17 +60,7 @@ func IsPersistentVolumeClaimResizing(pvc *core.PersistentVolumeClaim) bool {
|
|||
|
||||
// ExtractStorageResourceRequirement filters resource requirements for Pods.
|
||||
func ExtractStorageResourceRequirement(resources core.ResourceRequirements) core.ResourceRequirements {
|
||||
|
||||
filterStorage := func(list core.ResourceList) core.ResourceList {
|
||||
newlist := make(core.ResourceList)
|
||||
for k, v := range list {
|
||||
if k != core.ResourceStorage && k != "iops" {
|
||||
continue
|
||||
}
|
||||
newlist[k] = v
|
||||
}
|
||||
return newlist
|
||||
}
|
||||
filterStorage := NewPodResourceListFilter(core.ResourceStorage, "iops")
|
||||
|
||||
return core.ResourceRequirements{
|
||||
Limits: filterStorage(resources.Limits),
|
||||
|
|
|
@ -24,15 +24,89 @@ 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
|
||||
func ApplyContainerResourceRequirements(container *core.Container, resources core.ResourceRequirements) {
|
||||
if container == nil {
|
||||
return
|
||||
}
|
||||
for k, v := range src {
|
||||
if _, ok := (*dst)[k]; !ok {
|
||||
(*dst)[k] = v.DeepCopy()
|
||||
|
||||
container.Resources.Limits = ApplyContainerResourceList(container.Resources.Limits, resources.Limits)
|
||||
container.Resources.Requests = ApplyContainerResourceList(container.Resources.Requests, resources.Requests)
|
||||
}
|
||||
|
||||
// ApplyContainerResourceList adds non-existing resources from `from` to `to` ResourceList
|
||||
func ApplyContainerResourceList(to core.ResourceList, from core.ResourceList) core.ResourceList {
|
||||
if len(from) == 0 {
|
||||
return to
|
||||
}
|
||||
|
||||
if to == nil {
|
||||
to = core.ResourceList{}
|
||||
}
|
||||
|
||||
for k, v := range from {
|
||||
if _, ok := to[k]; !ok {
|
||||
to[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return to
|
||||
}
|
||||
|
||||
// ExtractPodInitContainerAcceptedResourceRequirement filters resource requirements for InitContainers.
|
||||
func ExtractPodInitContainerAcceptedResourceRequirement(resources core.ResourceRequirements) core.ResourceRequirements {
|
||||
return NewPodResourceRequirementsFilter(PodResourceRequirementsInitContainersAcceptedResourceRequirements()...)(resources)
|
||||
}
|
||||
|
||||
// PodResourceRequirementsInitContainersAcceptedResourceRequirements returns struct if accepted Pod resource types
|
||||
func PodResourceRequirementsInitContainersAcceptedResourceRequirements() []core.ResourceName {
|
||||
return []core.ResourceName{core.ResourceCPU, core.ResourceMemory, core.ResourceEphemeralStorage}
|
||||
}
|
||||
|
||||
// ExtractPodAcceptedResourceRequirement filters resource requirements for Pods.
|
||||
func ExtractPodAcceptedResourceRequirement(resources core.ResourceRequirements) core.ResourceRequirements {
|
||||
return NewPodResourceRequirementsFilter(PodResourceRequirementsPodAcceptedResourceRequirements()...)(resources)
|
||||
}
|
||||
|
||||
// PodResourceRequirementsPodAcceptedResourceRequirements returns struct if accepted Pod resource types
|
||||
func PodResourceRequirementsPodAcceptedResourceRequirements() []core.ResourceName {
|
||||
return []core.ResourceName{core.ResourceCPU, core.ResourceMemory, core.ResourceEphemeralStorage}
|
||||
}
|
||||
|
||||
type PodResourceRequirementsFilter func(in core.ResourceRequirements) core.ResourceRequirements
|
||||
|
||||
// NewPodResourceRequirementsFilter returns function which filter out not accepted resources from resource requirements
|
||||
func NewPodResourceRequirementsFilter(filters ...core.ResourceName) PodResourceRequirementsFilter {
|
||||
return func(in core.ResourceRequirements) core.ResourceRequirements {
|
||||
filter := NewPodResourceListFilter(filters...)
|
||||
|
||||
return core.ResourceRequirements{
|
||||
Limits: filter(in.Limits),
|
||||
Requests: filter(in.Requests),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type PodResourceListFilter func(in core.ResourceList) core.ResourceList
|
||||
|
||||
// NewPodResourceListFilter returns function which filter out not accepted resources from list
|
||||
func NewPodResourceListFilter(filters ...core.ResourceName) PodResourceListFilter {
|
||||
return func(in core.ResourceList) core.ResourceList {
|
||||
filtered := map[core.ResourceName]bool{}
|
||||
|
||||
for _, k := range filters {
|
||||
filtered[k] = true
|
||||
}
|
||||
|
||||
n := core.ResourceList{}
|
||||
|
||||
for k, v := range in {
|
||||
if _, ok := filtered[k]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
n[k] = v
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
|
162
pkg/util/k8sutil/resources_test.go
Normal file
162
pkg/util/k8sutil/resources_test.go
Normal file
|
@ -0,0 +1,162 @@
|
|||
//
|
||||
// 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 (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
core "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
)
|
||||
|
||||
func Test_ExtractPodAcceptedResourceRequirement(t *testing.T) {
|
||||
v, err := resource.ParseQuantity("1Gi")
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Filter Storage", func(t *testing.T) {
|
||||
in := core.ResourceRequirements{
|
||||
Limits: map[core.ResourceName]resource.Quantity{
|
||||
core.ResourceCPU: v,
|
||||
core.ResourceStorage: v,
|
||||
},
|
||||
}
|
||||
require.Len(t, in.Limits, 2)
|
||||
require.Len(t, in.Requests, 0)
|
||||
|
||||
out := ExtractPodAcceptedResourceRequirement(in)
|
||||
require.Len(t, out.Limits, 1)
|
||||
require.Contains(t, out.Limits, core.ResourceCPU)
|
||||
require.NotContains(t, out.Limits, core.ResourceStorage)
|
||||
require.Len(t, out.Requests, 0)
|
||||
})
|
||||
|
||||
t.Run("Ensure that all required Resources are filtered", func(t *testing.T) {
|
||||
resources := map[core.ResourceName]bool{
|
||||
core.ResourceCPU: true,
|
||||
core.ResourceMemory: true,
|
||||
core.ResourceStorage: false,
|
||||
core.ResourceEphemeralStorage: true,
|
||||
}
|
||||
|
||||
in := core.ResourceRequirements{
|
||||
Limits: core.ResourceList{},
|
||||
Requests: core.ResourceList{},
|
||||
}
|
||||
|
||||
for k := range resources {
|
||||
in.Limits[k] = v
|
||||
in.Requests[k] = v
|
||||
}
|
||||
|
||||
out := ExtractPodAcceptedResourceRequirement(in)
|
||||
|
||||
for k, v := range resources {
|
||||
t.Run(fmt.Sprintf("Resource %s should be %s", k, util.BoolSwitch(v, "present", "missing")), func(t *testing.T) {
|
||||
require.Contains(t, in.Requests, k)
|
||||
require.Contains(t, in.Limits, k)
|
||||
|
||||
if v {
|
||||
require.Contains(t, out.Requests, k)
|
||||
require.Contains(t, out.Limits, k)
|
||||
} else {
|
||||
require.NotContains(t, out.Requests, k)
|
||||
require.NotContains(t, out.Limits, k)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
func Test_ApplyContainerResourceRequirements(t *testing.T) {
|
||||
v1, err := resource.ParseQuantity("1Gi")
|
||||
require.NoError(t, err)
|
||||
|
||||
v2, err := resource.ParseQuantity("4Gi")
|
||||
require.NoError(t, err)
|
||||
|
||||
var container core.Container
|
||||
|
||||
t.Run("Ensure limits are copied", func(t *testing.T) {
|
||||
ApplyContainerResourceRequirements(&container, core.ResourceRequirements{
|
||||
Limits: core.ResourceList{
|
||||
core.ResourceMemory: v1,
|
||||
},
|
||||
Requests: core.ResourceList{
|
||||
core.ResourceMemory: v1,
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, container.Resources.Requests, 1)
|
||||
require.Contains(t, container.Resources.Requests, core.ResourceMemory)
|
||||
require.Equal(t, v1, container.Resources.Requests[core.ResourceMemory])
|
||||
|
||||
require.Len(t, container.Resources.Limits, 1)
|
||||
require.Contains(t, container.Resources.Limits, core.ResourceMemory)
|
||||
require.Equal(t, v1, container.Resources.Limits[core.ResourceMemory])
|
||||
})
|
||||
|
||||
t.Run("Ensure limits are not overridden", func(t *testing.T) {
|
||||
ApplyContainerResourceRequirements(&container, core.ResourceRequirements{
|
||||
Limits: core.ResourceList{
|
||||
core.ResourceMemory: v2,
|
||||
},
|
||||
Requests: core.ResourceList{
|
||||
core.ResourceMemory: v2,
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, container.Resources.Requests, 1)
|
||||
require.Contains(t, container.Resources.Requests, core.ResourceMemory)
|
||||
require.Equal(t, v1, container.Resources.Requests[core.ResourceMemory])
|
||||
|
||||
require.Len(t, container.Resources.Limits, 1)
|
||||
require.Contains(t, container.Resources.Limits, core.ResourceMemory)
|
||||
require.Equal(t, v1, container.Resources.Limits[core.ResourceMemory])
|
||||
})
|
||||
|
||||
t.Run("Ensure limits are appended", func(t *testing.T) {
|
||||
ApplyContainerResourceRequirements(&container, core.ResourceRequirements{
|
||||
Limits: core.ResourceList{
|
||||
core.ResourceCPU: v2,
|
||||
},
|
||||
Requests: core.ResourceList{
|
||||
core.ResourceStorage: v2,
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, container.Resources.Requests, 2)
|
||||
require.Contains(t, container.Resources.Requests, core.ResourceMemory)
|
||||
require.Equal(t, v1, container.Resources.Requests[core.ResourceMemory])
|
||||
|
||||
require.Contains(t, container.Resources.Requests, core.ResourceStorage)
|
||||
require.Equal(t, v2, container.Resources.Requests[core.ResourceStorage])
|
||||
|
||||
require.Len(t, container.Resources.Limits, 2)
|
||||
require.Contains(t, container.Resources.Limits, core.ResourceMemory)
|
||||
require.Equal(t, v1, container.Resources.Limits[core.ResourceMemory])
|
||||
|
||||
require.Contains(t, container.Resources.Limits, core.ResourceCPU)
|
||||
require.Equal(t, v2, container.Resources.Limits[core.ResourceCPU])
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue