Skip to content

[Feature] JobScheduler Coverage #1606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- (Bugfix) Fix Resources Copy mechanism to prevent invalid pod creation
- (Bugfix) Wait for ImageStatus in ImageDiscover
- (Bugfix) Fix Image Error Propagation
- (Feature) JobScheduler Coverage

## [1.2.38](https://github.com/arangodb/kube-arangodb/tree/1.2.38) (2024-02-22)
- (Feature) Extract GRPC Server
Expand Down
310 changes: 155 additions & 155 deletions docs/api/ArangoMLExtension.V1Alpha1.md

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions docs/api/ArangoMLStorage.V1Alpha1.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Default Value: `9202`

### .spec.mode.sidecar.env

Type: `core.EnvVar` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/environments.go#L33)</sup>
Type: `core.EnvVar` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/environments.go#L36)</sup>

Env keeps the information about environment variables provided to the container

Expand All @@ -127,7 +127,7 @@ Links:

### .spec.mode.sidecar.envFrom

Type: `core.EnvFromSource` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/environments.go#L38)</sup>
Type: `core.EnvFromSource` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/environments.go#L41)</sup>

EnvFrom keeps the information about environment variable sources provided to the container

Expand All @@ -138,15 +138,15 @@ Links:

### .spec.mode.sidecar.image

Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/image.go#L34)</sup>
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/image.go#L37)</sup>

Image define image details

***

### .spec.mode.sidecar.imagePullPolicy

Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/image.go#L38)</sup>
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/image.go#L41)</sup>

ImagePullPolicy define Image pull policy

Expand All @@ -156,7 +156,7 @@ Default Value: `IfNotPresent`

### .spec.mode.sidecar.imagePullSecrets

Type: `array` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/image.go#L41)</sup>
Type: `array` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/image.go#L44)</sup>

ImagePullSecrets define Secrets used to pull Image from registry

Expand All @@ -174,7 +174,7 @@ Default Value: `9201`

### .spec.mode.sidecar.resources

Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/resources.go#L34)</sup>
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/resources.go#L37)</sup>

Resources holds resource requests & limits for container

Expand All @@ -185,9 +185,9 @@ Links:

### .spec.mode.sidecar.securityContext

Type: `core.SecurityContext` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/security.go#L31)</sup>
Type: `core.SecurityContext` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.38/pkg/apis/scheduler/v1alpha1/container/resources/security.go#L35)</sup>

PodSecurityContext holds pod-level security attributes and common container settings.
SecurityContext holds container-level security attributes and common container settings.

Links:
* [Kubernetes docs](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
Expand Down
13 changes: 7 additions & 6 deletions pkg/apis/ml/v1alpha1/storage_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,22 @@ func Test_ArangoMLStorageSpec(t *testing.T) {
expectedRequirements := core.ResourceRequirements{
Requests: assignedRequirements.Requests,
Limits: core.ResourceList{
core.ResourceCPU: resource.MustParse("100m"),
core.ResourceMemory: resource.MustParse("128Mi"),
core.ResourceCPU: resource.MustParse("200m"),
core.ResourceMemory: resource.MustParse("256Mi"),
},
}

actualRequirements := s.Mode.Sidecar.GetResources().With(&schedulerContainerResourcesApi.Resources{Resources: &core.ResourceRequirements{
Limits: core.ResourceList{
core.ResourceCPU: resource.MustParse("100m"),
core.ResourceMemory: resource.MustParse("128Mi"),
},
Requests: core.ResourceList{
core.ResourceCPU: resource.MustParse("200m"),
core.ResourceMemory: resource.MustParse("256Mi"),
},
Requests: core.ResourceList{
core.ResourceCPU: resource.MustParse("100m"),
core.ResourceMemory: resource.MustParse("128Mi"),
},
}})

require.Equal(t, expectedRequirements, actualRequirements.GetResources())
})
}
20 changes: 17 additions & 3 deletions pkg/apis/scheduler/v1alpha1/container/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import (
core "k8s.io/api/core/v1"

schedulerContainerResourcesApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1/container/resources"
"github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1/interfaces"
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/container"
)

Expand Down Expand Up @@ -89,6 +91,18 @@ func (c Containers) With(other Containers) Containers {
return ret
}

func (c Containers) Validate() error {
for name, container := range c {
if err := container.Validate(); err != nil {
return errors.Wrapf(err, "Container %s failed", name)
}
}

return nil
}

var _ interfaces.Container[Container] = &Container{}

type Container struct {
// Security keeps the security settings for Container
*schedulerContainerResourcesApi.Security `json:",inline"`
Expand All @@ -109,10 +123,10 @@ func (c *Container) Apply(template *core.PodTemplateSpec, container *core.Contai
}

return shared.WithErrors(
c.Security.Apply(container),
c.Environments.Apply(container),
c.Security.Apply(template, container),
c.Environments.Apply(template, container),
c.Image.Apply(template, container),
c.Resources.Apply(container),
c.Resources.Apply(template, container),
)
}

Expand Down
236 changes: 236 additions & 0 deletions pkg/apis/scheduler/v1alpha1/container/definition_container_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
//
// DISCLAIMER
//
// Copyright 2024 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 container

import (
"testing"

"github.com/stretchr/testify/require"
core "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/yaml"

schedulerContainerResourcesApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1/container/resources"
"github.com/arangodb/kube-arangodb/pkg/util"
)

func applyContainer(t *testing.T, template *core.PodTemplateSpec, container *core.Container, ns ...*Container) func(in func(t *testing.T, pod *core.PodTemplateSpec, container *core.Container, spec *Container)) {
var i *Container

for _, n := range ns {
require.NoError(t, n.Validate())

i = i.With(n)

require.NoError(t, i.Validate())
}

template = template.DeepCopy()

if template == nil {
template = &core.PodTemplateSpec{}
}

container = container.DeepCopy()
if container == nil {
container = &core.Container{}
}

template.Spec.Containers = append(template.Spec.Containers, *container)

container = &template.Spec.Containers[0]

require.NoError(t, i.Apply(template, container))

return func(in func(t *testing.T, pod *core.PodTemplateSpec, container *core.Container, spec *Container)) {
t.Run("Validate", func(t *testing.T) {
if i != nil {
in(t, template, container, i)
} else {
in(t, template, container, &Container{})
}
})
}
}

func applyContainerYAML(t *testing.T, template *core.PodTemplateSpec, container *core.Container, ns ...string) func(in func(t *testing.T, pod *core.PodTemplateSpec, container *core.Container, spec *Container)) {
elements := make([]*Container, len(ns))

for id := range ns {
var p Container
require.NoError(t, yaml.Unmarshal([]byte(ns[id]), &p))
elements[id] = p.DeepCopy()
}

return applyContainer(t, template, container, elements...)
}

func Test_Container(t *testing.T) {
t.Run("Nil", func(t *testing.T) {
applyContainer(t, nil, nil)(func(t *testing.T, pod *core.PodTemplateSpec, container *core.Container, spec *Container) {
require.Nil(t, spec.Resources)
require.Nil(t, spec.Image)
require.Nil(t, spec.Security)
require.Nil(t, spec.Environments)

require.Len(t, container.Env, 0)
})
})
t.Run("Empty template", func(t *testing.T) {
applyContainer(t, &core.PodTemplateSpec{}, &core.Container{})(func(t *testing.T, pod *core.PodTemplateSpec, container *core.Container, spec *Container) {
require.Nil(t, spec.Resources)
require.Nil(t, spec.Image)
require.Nil(t, spec.Security)
require.Nil(t, spec.Environments)

require.Len(t, container.Env, 0)
})
})
t.Run("With fields", func(t *testing.T) {
applyContainer(t, &core.PodTemplateSpec{}, &core.Container{}, &Container{
Security: &schedulerContainerResourcesApi.Security{
SecurityContext: &core.SecurityContext{
RunAsUser: util.NewType[int64](50),
},
},
Environments: &schedulerContainerResourcesApi.Environments{
Env: []core.EnvVar{
{
Name: "key1",
Value: "value1",
},
},
},
Image: &schedulerContainerResourcesApi.Image{
Image: util.NewType("test"),
},
Resources: &schedulerContainerResourcesApi.Resources{
Resources: &core.ResourceRequirements{
Limits: map[core.ResourceName]resource.Quantity{
core.ResourceCPU: resource.MustParse("1"),
},
},
},
})(func(t *testing.T, pod *core.PodTemplateSpec, container *core.Container, spec *Container) {
// Spec
require.NotNil(t, spec.Resources)
require.NotNil(t, spec.Resources.Resources)
require.Contains(t, spec.Resources.Resources.Limits, core.ResourceCPU)
require.EqualValues(t, resource.MustParse("1"), spec.Resources.Resources.Limits[core.ResourceCPU])

require.NotNil(t, spec.Image)
require.NotNil(t, spec.Image.Image)
require.EqualValues(t, "test", *spec.Image.Image)

require.NotNil(t, spec.Security)
require.NotNil(t, spec.Security.SecurityContext)
require.NotNil(t, spec.Security.SecurityContext.RunAsUser)
require.EqualValues(t, 50, *spec.Security.SecurityContext.RunAsUser)

require.NotNil(t, spec.Environments)
require.Len(t, spec.Environments.Env, 1)
require.EqualValues(t, "key1", spec.Environments.Env[0].Name)
require.EqualValues(t, "value1", spec.Environments.Env[0].Value)
})
})
}

func Test_Container_YAML(t *testing.T) {
t.Run("With Override", func(t *testing.T) {
applyContainerYAML(t, &core.PodTemplateSpec{}, &core.Container{}, `
---
securityContext:
runAsUser: 50

env:
- name: key1
value: value1

image: test

resources:
limits:
cpu: 1
`, `
---

securityContext:
runAsUser: 10
`)(func(t *testing.T, pod *core.PodTemplateSpec, container *core.Container, spec *Container) {
// Spec
require.NotNil(t, spec.Resources)
require.NotNil(t, spec.Resources.Resources)
require.Contains(t, spec.Resources.Resources.Limits, core.ResourceCPU)
require.EqualValues(t, resource.MustParse("1"), spec.Resources.Resources.Limits[core.ResourceCPU])

require.NotNil(t, spec.Image)
require.NotNil(t, spec.Image.Image)
require.EqualValues(t, "test", *spec.Image.Image)

require.NotNil(t, spec.Security)
require.NotNil(t, spec.Security.SecurityContext)
require.NotNil(t, spec.Security.SecurityContext.RunAsUser)
require.EqualValues(t, 10, *spec.Security.SecurityContext.RunAsUser)

require.NotNil(t, spec.Environments)
require.Len(t, spec.Environments.Env, 1)
require.EqualValues(t, "key1", spec.Environments.Env[0].Name)
require.EqualValues(t, "value1", spec.Environments.Env[0].Value)
})
})
t.Run("With fields", func(t *testing.T) {
applyContainerYAML(t, &core.PodTemplateSpec{}, &core.Container{}, `
---
securityContext:
runAsUser: 50

env:
- name: key1
value: value1

image: test

resources:
limits:
cpu: 1
`)(func(t *testing.T, pod *core.PodTemplateSpec, container *core.Container, spec *Container) {
// Spec
require.NotNil(t, spec.Resources)
require.NotNil(t, spec.Resources.Resources)
require.Contains(t, spec.Resources.Resources.Limits, core.ResourceCPU)
require.EqualValues(t, resource.MustParse("1"), spec.Resources.Resources.Limits[core.ResourceCPU])

require.NotNil(t, spec.Image)
require.NotNil(t, spec.Image.Image)
require.EqualValues(t, "test", *spec.Image.Image)

require.NotNil(t, spec.Security)
require.NotNil(t, spec.Security.SecurityContext)
require.NotNil(t, spec.Security.SecurityContext.RunAsUser)
require.EqualValues(t, 50, *spec.Security.SecurityContext.RunAsUser)

require.NotNil(t, spec.Environments)
require.Len(t, spec.Environments.Env, 1)
require.EqualValues(t, "key1", spec.Environments.Env[0].Name)
require.EqualValues(t, "value1", spec.Environments.Env[0].Value)
})
})
}
Loading