1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Feature] ArangoProfile Selectors (#1627)

This commit is contained in:
Adam Janikowski 2024-03-22 22:25:33 +01:00 committed by GitHub
parent 8be3599cd6
commit fe5419c404
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 808 additions and 8 deletions

View file

@ -9,6 +9,7 @@
- (Feature) Discover Namespace in DebugPackage from K8S
- (Feature) Expose Force CRD Install option
- (Maintenance) Move Container utils functions
- (Feature) ArangoProfile Selectors
## [1.2.39](https://github.com/arangodb/kube-arangodb/tree/1.2.39) (2024-03-11)
- (Feature) Extract Scheduler API

View file

@ -71,6 +71,14 @@ Default Value: `false`
***
### .spec.deployment.imagePullSecrets
Type: `array` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.39/pkg/apis/scheduler/v1alpha1/pod/resources/image.go#L36)</sup>
ImagePullSecrets define Secrets used to pull Image from registry
***
### .spec.deployment.labels
Type: `object` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.39/pkg/apis/scheduler/v1alpha1/pod/resources/metadata.go#L39)</sup>

View file

@ -8,6 +8,14 @@ title: ArangoProfile V1Alpha1
## Spec
### .spec.selectors.label
Type: `meta.LabelSelector` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.39/pkg/apis/scheduler/v1alpha1/profile_selectors.go#L32)</sup>
Label keeps information about label selector
***
### .spec.template.container.all.env
Type: `core.EnvVar` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.39/pkg/apis/scheduler/v1alpha1/container/resources/environments.go#L36)</sup>
@ -281,6 +289,14 @@ Default Value: `false`
***
### .spec.template.pod.imagePullSecrets
Type: `array` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.39/pkg/apis/scheduler/v1alpha1/pod/resources/image.go#L36)</sup>
ImagePullSecrets define Secrets used to pull Image from registry
***
### .spec.template.pod.labels
Type: `object` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.39/pkg/apis/scheduler/v1alpha1/pod/resources/metadata.go#L39)</sup>

View file

@ -42,7 +42,10 @@ func (r *Resources) Apply(_ *core.PodTemplateSpec, template *core.Container) err
return nil
}
template.Resources = r.GetResources()
res := r.GetResources()
template.Resources.Limits = kresources.UpscaleContainerResourceList(template.Resources.Limits, res.Limits)
template.Resources.Requests = kresources.UpscaleContainerResourceList(template.Resources.Requests, res.Requests)
return nil
}

View file

@ -42,7 +42,7 @@ func (v *VolumeMounts) Apply(_ *core.PodTemplateSpec, container *core.Container)
obj := v.DeepCopy()
container.VolumeMounts = obj.VolumeMounts
container.VolumeMounts = kresources.MergeVolumeMounts(container.VolumeMounts, obj.VolumeMounts...)
return nil
}

View file

@ -34,6 +34,9 @@ type Pod struct {
// Metadata keeps the metadata settings for Pod
*schedulerPodResourcesApi.Metadata `json:",inline"`
// Image keeps the image information
*schedulerPodResourcesApi.Image `json:",inline"`
// Scheduling keeps the scheduling information
*schedulerPodResourcesApi.Scheduling `json:",inline"`
@ -65,6 +68,7 @@ func (a *Pod) With(other *Pod) *Pod {
return &Pod{
Scheduling: a.Scheduling.With(other.Scheduling),
Image: a.Image.With(other.Image),
Namespace: a.Namespace.With(other.Namespace),
Security: a.Security.With(other.Security),
Volumes: a.Volumes.With(other.Volumes),
@ -80,6 +84,7 @@ func (a *Pod) Apply(template *core.PodTemplateSpec) error {
return shared.WithErrors(
a.Scheduling.Apply(template),
a.Image.Apply(template),
a.Namespace.Apply(template),
a.Security.Apply(template),
a.Volumes.Apply(template),
@ -96,6 +101,14 @@ func (a *Pod) GetSecurity() *schedulerPodResourcesApi.Security {
return a.Security
}
func (a *Pod) GetImage() *schedulerPodResourcesApi.Image {
if a == nil {
return nil
}
return a.Image
}
func (a *Pod) GetScheduling() *schedulerPodResourcesApi.Scheduling {
if a == nil {
return nil
@ -142,6 +155,7 @@ func (a *Pod) Validate() error {
}
return shared.WithErrors(
a.Scheduling.Validate(),
a.Image.Validate(),
a.Namespace.Validate(),
a.Security.Validate(),
a.Volumes.Validate(),

View file

@ -0,0 +1,87 @@
//
// 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 resources
import (
core "k8s.io/api/core/v1"
"github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1/interfaces"
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
)
type ImagePullSecrets []string
var _ interfaces.Pod[Image] = &Image{}
type Image struct {
// ImagePullSecrets define Secrets used to pull Image from registry
ImagePullSecrets ImagePullSecrets `json:"imagePullSecrets,omitempty"`
}
func (i *Image) Apply(pod *core.PodTemplateSpec) error {
if i == nil {
return nil
}
for _, secret := range i.ImagePullSecrets {
if hasImagePullSecret(pod.Spec.ImagePullSecrets, secret) {
continue
}
pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, core.LocalObjectReference{
Name: secret,
})
}
return nil
}
func (i *Image) With(other *Image) *Image {
if i == nil && other == nil {
return nil
}
if other == nil {
return i.DeepCopy()
}
return other.DeepCopy()
}
func (i *Image) Validate() error {
if i == nil {
return nil
}
return shared.WithErrors(
shared.PrefixResourceErrors("pullSecrets", shared.ValidateList(i.ImagePullSecrets, shared.ValidateResourceName)),
)
}
func hasImagePullSecret(secrets []core.LocalObjectReference, secret string) bool {
for _, sec := range secrets {
if sec.Name == secret {
return true
}
}
return false
}

View file

@ -0,0 +1,88 @@
//
// 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 resources
import (
"testing"
"github.com/stretchr/testify/require"
core "k8s.io/api/core/v1"
)
func applyImage(t *testing.T, template *core.PodTemplateSpec, ns ...*Image) func(in func(t *testing.T, pod *core.PodTemplateSpec)) {
var i *Image
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{}
}
require.NoError(t, i.Apply(template))
return func(in func(t *testing.T, spec *core.PodTemplateSpec)) {
t.Run("Validate", func(t *testing.T) {
in(t, template)
})
}
}
func Test_Image(t *testing.T) {
t.Run("With Nil", func(t *testing.T) {
applyImage(t, nil, nil)(func(t *testing.T, pod *core.PodTemplateSpec) {
require.Len(t, pod.Spec.ImagePullSecrets, 0)
})
})
t.Run("With Empty", func(t *testing.T) {
applyImage(t, &core.PodTemplateSpec{})(func(t *testing.T, pod *core.PodTemplateSpec) {
require.Len(t, pod.Spec.ImagePullSecrets, 0)
})
})
t.Run("With PS", func(t *testing.T) {
applyImage(t, &core.PodTemplateSpec{}, &Image{
ImagePullSecrets: []string{
"secret",
},
})(func(t *testing.T, pod *core.PodTemplateSpec) {
require.Len(t, pod.Spec.ImagePullSecrets, 1)
require.Equal(t, "secret", pod.Spec.ImagePullSecrets[0].Name)
})
})
t.Run("With PS2", func(t *testing.T) {
applyImage(t, &core.PodTemplateSpec{}, &Image{
ImagePullSecrets: []string{
"secret",
"secret",
},
})(func(t *testing.T, pod *core.PodTemplateSpec) {
require.Len(t, pod.Spec.ImagePullSecrets, 1)
require.Equal(t, "secret", pod.Spec.ImagePullSecrets[0].Name)
})
})
}

View file

@ -46,7 +46,9 @@ func (s *ServiceAccount) Apply(template *core.PodTemplateSpec) error {
c := s.DeepCopy()
template.Spec.ServiceAccountName = c.ServiceAccountName
template.Spec.AutomountServiceAccountToken = c.AutomountServiceAccountToken
if c.AutomountServiceAccountToken != nil {
template.Spec.AutomountServiceAccountToken = c.AutomountServiceAccountToken
}
return nil
}

View file

@ -43,7 +43,7 @@ func (v *Volumes) Apply(template *core.PodTemplateSpec) error {
obj := v.DeepCopy()
template.Spec.Volumes = obj.Volumes
template.Spec.Volumes = kresources.MergeVolumes(template.Spec.Volumes, obj.Volumes...)
return nil
}

View file

@ -30,6 +30,47 @@ import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Image) DeepCopyInto(out *Image) {
*out = *in
if in.ImagePullSecrets != nil {
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
*out = make(ImagePullSecrets, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image.
func (in *Image) DeepCopy() *Image {
if in == nil {
return nil
}
out := new(Image)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in ImagePullSecrets) DeepCopyInto(out *ImagePullSecrets) {
{
in := &in
*out = make(ImagePullSecrets, len(*in))
copy(*out, *in)
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImagePullSecrets.
func (in ImagePullSecrets) DeepCopy() ImagePullSecrets {
if in == nil {
return nil
}
out := new(ImagePullSecrets)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Metadata) DeepCopyInto(out *Metadata) {
*out = *in

View file

@ -37,6 +37,11 @@ func (in *Pod) DeepCopyInto(out *Pod) {
*out = new(resources.Metadata)
(*in).DeepCopyInto(*out)
}
if in.Image != nil {
in, out := &in.Image, &out.Image
*out = new(resources.Image)
(*in).DeepCopyInto(*out)
}
if in.Scheduling != nil {
in, out := &in.Scheduling, &out.Scheduling
*out = new(resources.Scheduling)

View file

@ -0,0 +1,49 @@
//
// 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 v1alpha1
import (
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
kresources "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/resources"
)
type ProfileSelectors struct {
// Label keeps information about label selector
// +doc/type: meta.LabelSelector
Label *meta.LabelSelector `json:"label,omitempty"`
}
func (p *ProfileSelectors) Validate() error {
if p == nil {
return nil
}
return nil
}
func (p *ProfileSelectors) Select(labels map[string]string) bool {
if p == nil || p.Label == nil {
return false
}
return kresources.SelectLabels(p.Label, labels)
}

View file

@ -20,7 +20,25 @@
package v1alpha1
import (
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
)
type ProfileSpec struct {
// Selectors keeps information about ProfileSelectors
Selectors *ProfileSelectors `json:"selectors,omitempty"`
// Template keeps the Profile Template
Template *ProfileTemplate `json:"template,omitempty"`
}
func (p *ProfileSpec) Validate() error {
if p == nil {
return nil
}
return shared.WithErrors(
shared.PrefixResourceErrors("selectors", p.Selectors.Validate()),
shared.PrefixResourceErrors("template", p.Template.Validate()),
)
}

View file

@ -33,7 +33,7 @@ type ProfileTemplates []*ProfileTemplate
func (p ProfileTemplates) Sort() ProfileTemplates {
sort.Slice(p, func(i, j int) bool {
if a, b := p[i].GetPriority(), p[j].GetPriority(); a != b {
return a < b
return a > b
}
return false
@ -45,8 +45,8 @@ func (p ProfileTemplates) Sort() ProfileTemplates {
func (p ProfileTemplates) Merge() *ProfileTemplate {
var z *ProfileTemplate
for _, q := range p {
z = z.With(q)
for id := len(p) - 1; id >= 0; id-- {
z = z.With(p[id])
}
return z

View file

@ -28,6 +28,7 @@ package v1alpha1
import (
container "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1/container"
pod "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1/pod"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
@ -120,9 +121,35 @@ func (in *ProfileContainerTemplate) DeepCopy() *ProfileContainerTemplate {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProfileSelectors) DeepCopyInto(out *ProfileSelectors) {
*out = *in
if in.Label != nil {
in, out := &in.Label, &out.Label
*out = new(v1.LabelSelector)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProfileSelectors.
func (in *ProfileSelectors) DeepCopy() *ProfileSelectors {
if in == nil {
return nil
}
out := new(ProfileSelectors)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProfileSpec) DeepCopyInto(out *ProfileSpec) {
*out = *in
if in.Selectors != nil {
in, out := &in.Selectors, &out.Selectors
*out = new(ProfileSelectors)
(*in).DeepCopyInto(*out)
}
if in.Template != nil {
in, out := &in.Template, &out.Template
*out = new(ProfileTemplate)

View file

@ -349,6 +349,10 @@ v1alpha1:
type: boolean
hostPID:
type: boolean
imagePullSecrets:
items:
type: string
type: array
labels:
additionalProperties:
type: string

View file

@ -3,6 +3,31 @@ v1alpha1:
properties:
spec:
properties:
selectors:
description: Selectors keeps information about ProfileSelectors
properties:
label:
description: Label keeps information about label selector
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
type: object
template:
description: Template keeps the Profile Template
properties:
@ -930,6 +955,10 @@ v1alpha1:
type: boolean
hostPID:
type: boolean
imagePullSecrets:
items:
type: string
type: array
labels:
additionalProperties:
type: string

View file

@ -0,0 +1,76 @@
//
// 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 resources
import (
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/arangodb/kube-arangodb/pkg/util/strings"
)
func SelectLabels(selector *meta.LabelSelector, labels map[string]string) bool {
if selector == nil {
return false
}
for k, v := range selector.MatchLabels {
if v2, ok := labels[k]; !ok || v2 != v {
return false
}
}
for _, req := range selector.MatchExpressions {
switch req.Operator {
case meta.LabelSelectorOpIn:
if len(req.Values) == 0 {
return false
}
if v, ok := labels[req.Key]; !ok {
return false
} else if !strings.ListContains(req.Values, v) {
return false
}
case meta.LabelSelectorOpNotIn:
if len(req.Values) == 0 {
return false
}
if v, ok := labels[req.Key]; ok {
if strings.ListContains(req.Values, v) {
return false
}
}
case meta.LabelSelectorOpExists:
if _, ok := labels[req.Key]; !ok {
return false
}
case meta.LabelSelectorOpDoesNotExist:
if _, ok := labels[req.Key]; ok {
return false
}
default:
return false
}
}
return true
}

View file

@ -0,0 +1,249 @@
//
// 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 resources
import (
"testing"
"github.com/stretchr/testify/require"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func Test_Selectors_Labels(t *testing.T) {
labels := map[string]string{
"A": "B",
"C": "D",
"E": "F",
}
t.Run("Match", func(t *testing.T) {
t.Run("Do not match with nil", func(t *testing.T) {
require.False(t, SelectLabels(nil, nil))
})
t.Run("Match with any", func(t *testing.T) {
require.True(t, SelectLabels(&meta.LabelSelector{}, nil))
})
t.Run("Match with dedicated labels select", func(t *testing.T) {
require.True(t, SelectLabels(&meta.LabelSelector{
MatchLabels: map[string]string{
"A": "B",
},
}, labels))
})
t.Run("Match with multiple dedicated labels select", func(t *testing.T) {
require.True(t, SelectLabels(&meta.LabelSelector{
MatchLabels: map[string]string{
"A": "B",
"E": "F",
},
}, labels))
})
t.Run("Match with mismatch dedicated labels select", func(t *testing.T) {
require.False(t, SelectLabels(&meta.LabelSelector{
MatchLabels: map[string]string{
"A": "B",
"E": "G",
},
}, labels))
})
})
t.Run("Match Expression", func(t *testing.T) {
t.Run("Exists", func(t *testing.T) {
t.Run("Present", func(t *testing.T) {
require.True(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "A",
Operator: meta.LabelSelectorOpExists,
},
},
}, labels))
})
t.Run("Missing", func(t *testing.T) {
require.False(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "B",
Operator: meta.LabelSelectorOpExists,
},
},
}, labels))
})
})
t.Run("Exists", func(t *testing.T) {
t.Run("Present", func(t *testing.T) {
require.False(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "A",
Operator: meta.LabelSelectorOpDoesNotExist,
},
},
}, labels))
})
t.Run("Missing", func(t *testing.T) {
require.True(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "B",
Operator: meta.LabelSelectorOpDoesNotExist,
},
},
}, labels))
})
})
t.Run("In", func(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
require.False(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "A",
Operator: meta.LabelSelectorOpIn,
},
},
}, labels))
})
t.Run("Present", func(t *testing.T) {
require.True(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "A",
Operator: meta.LabelSelectorOpIn,
Values: []string{
"B",
},
},
},
}, labels))
})
t.Run("Present Multiple", func(t *testing.T) {
require.True(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "A",
Operator: meta.LabelSelectorOpIn,
Values: []string{
"E",
"Z",
"B",
},
},
},
}, labels))
})
t.Run("Missing", func(t *testing.T) {
require.False(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "B",
Operator: meta.LabelSelectorOpIn,
Values: []string{
"B",
},
},
},
}, labels))
})
})
t.Run("NotIn", func(t *testing.T) {
t.Run("Not Existing", func(t *testing.T) {
require.False(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "Z",
Operator: meta.LabelSelectorOpNotIn,
},
},
}, labels))
})
t.Run("Empty", func(t *testing.T) {
require.False(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "A",
Operator: meta.LabelSelectorOpNotIn,
},
},
}, labels))
})
t.Run("Present", func(t *testing.T) {
require.False(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "A",
Operator: meta.LabelSelectorOpNotIn,
Values: []string{
"B",
},
},
},
}, labels))
})
t.Run("Present Multiple", func(t *testing.T) {
require.False(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "A",
Operator: meta.LabelSelectorOpNotIn,
Values: []string{
"E",
"Z",
"B",
},
},
},
}, labels))
})
t.Run("Missing", func(t *testing.T) {
require.True(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "B",
Operator: meta.LabelSelectorOpNotIn,
Values: []string{
"B",
},
},
},
}, labels))
})
t.Run("Missing Value", func(t *testing.T) {
require.True(t, SelectLabels(&meta.LabelSelector{
MatchExpressions: []meta.LabelSelectorRequirement{
{
Key: "A",
Operator: meta.LabelSelectorOpNotIn,
Values: []string{
"R",
"Z",
"D",
},
},
},
}, labels))
})
})
})
}

View file

@ -41,6 +41,8 @@ import (
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/apis/ml"
mlApi "github.com/arangodb/kube-arangodb/pkg/apis/ml/v1alpha1"
"github.com/arangodb/kube-arangodb/pkg/apis/scheduler"
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1"
arangoClientSet "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned"
operator "github.com/arangodb/kube-arangodb/pkg/operatorV2"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
@ -205,6 +207,12 @@ func CreateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
vl := *v
_, err := arango.MlV1alpha1().ArangoMLCronJobs(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
require.NoError(t, err)
case **schedulerApi.ArangoProfile:
require.NotNil(t, v)
vl := *v
_, err := arango.SchedulerV1alpha1().ArangoProfiles(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
require.NoError(t, err)
default:
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
}
@ -325,6 +333,12 @@ func UpdateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
vl := *v
_, err := k8s.RbacV1().RoleBindings(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
require.NoError(t, err)
case **schedulerApi.ArangoProfile:
require.NotNil(t, v)
vl := *v
_, err := arango.SchedulerV1alpha1().ArangoProfiles(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
require.NoError(t, err)
default:
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
}
@ -700,6 +714,21 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
} else {
*v = vn
}
case **schedulerApi.ArangoProfile:
require.NotNil(t, v)
vl := *v
vn, err := arango.SchedulerV1alpha1().ArangoProfiles(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
if err != nil {
if kerrors.IsNotFound(err) {
*v = nil
} else {
require.NoError(t, err)
}
} else {
*v = vn
}
default:
require.Fail(t, fmt.Sprintf("Unable to get object: %s", reflect.TypeOf(v).String()))
}
@ -832,11 +861,23 @@ func SetMetaBasedOnType(t *testing.T, object meta.Object) {
ml.ArangoMLCronJobResourcePlural,
object.GetNamespace(),
object.GetName()))
case *schedulerApi.ArangoProfile:
v.Kind = scheduler.ArangoProfileResourceKind
v.APIVersion = schedulerApi.SchemeGroupVersion.String()
v.SetSelfLink(fmt.Sprintf("/api/%s/%s/%s/%s",
schedulerApi.SchemeGroupVersion.String(),
scheduler.ArangoProfileResourcePlural,
object.GetNamespace(),
object.GetName()))
default:
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
}
}
func NewMetaObjectInDefaultNamespace[T meta.Object](t *testing.T, name string, mods ...MetaObjectMod[T]) T {
return NewMetaObject[T](t, FakeNamespace, name, mods...)
}
func NewMetaObject[T meta.Object](t *testing.T, namespace, name string, mods ...MetaObjectMod[T]) T {
var obj T
@ -951,6 +992,10 @@ func NewItem(t *testing.T, o operation.Operation, object meta.Object) operation.
item.Group = ml.ArangoMLGroupName
item.Version = mlApi.ArangoMLVersion
item.Kind = ml.ArangoMLCronJobResourceKind
case *schedulerApi.ArangoProfile:
item.Group = scheduler.ArangoSchedulerGroupName
item.Version = schedulerApi.ArangoSchedulerVersion
item.Kind = scheduler.ArangoProfileResourceKind
default:
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
}

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
// Copyright 2023-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.
@ -34,6 +34,7 @@ import (
backupApi "github.com/arangodb/kube-arangodb/pkg/apis/backup/v1"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
mlApi "github.com/arangodb/kube-arangodb/pkg/apis/ml/v1alpha1"
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
)
@ -76,4 +77,5 @@ func Test_NewMetaObject(t *testing.T) {
NewMetaObjectRun[*backupApi.ArangoBackup](t)
NewMetaObjectRun[*mlApi.ArangoMLExtension](t)
NewMetaObjectRun[*mlApi.ArangoMLStorage](t)
NewMetaObjectRun[*schedulerApi.ArangoProfile](t)
}

View file

@ -0,0 +1,36 @@
//
// 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 tests
import (
"testing"
"github.com/stretchr/testify/require"
core "k8s.io/api/core/v1"
kresources "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/resources"
)
func GetContainerByNameT(t *testing.T, containers []core.Container, name string) core.Container {
id := kresources.GetContainerIDByName(containers, name)
require.NotEqualValues(t, -1, id)
return containers[id]
}