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

[Feature] [ML] Pod & Container Config (#1533)

Co-authored-by: Nikita Vaniasin <nikita.vanyasin@gmail.com>
This commit is contained in:
Adam Janikowski 2023-12-08 16:13:12 +01:00 committed by GitHub
parent cff60f2eab
commit 041bae8810
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 1398 additions and 48 deletions

View file

@ -32,6 +32,7 @@
- (Improvement) (ML) CronJob status update
- (Improvement) (ML) Job Sidecar Shutdown
- (Feature) (ML) Handler for Extension StatefulSet and Service
- (Feature) (ML) Pod & Container Config
## [1.2.35](https://github.com/arangodb/kube-arangodb/tree/1.2.35) (2023-11-06)
- (Maintenance) Update go-driver to v1.6.0, update IsNotFound() checks

View file

@ -38,7 +38,7 @@ PullSecrets define Secrets used to pull Image from registry
### .spec.deployment.prediction.resources
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L33)</sup>
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34)</sup>
Resources holds resource requests & limits for container
@ -83,7 +83,7 @@ PullSecrets define Secrets used to pull Image from registry
### .spec.deployment.project.resources
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L33)</sup>
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34)</sup>
Resources holds resource requests & limits for container
@ -155,7 +155,7 @@ PullSecrets define Secrets used to pull Image from registry
### .spec.deployment.training.resources
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L33)</sup>
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34)</sup>
Resources holds resource requests & limits for container
@ -172,6 +172,48 @@ Image define image details
***
### .spec.init.affinity
Type: `core.Affinity` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/scheduling.go#L37)</sup>
Affinity defines scheduling constraints for workload
Links:
* [Kubernetes docs](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity)
***
### .spec.init.hostIPC
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/container_namespace.go#L33)</sup>
HostIPC defines to use the host's ipc namespace.
Default Value: `false`
***
### .spec.init.hostNetwork
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/container_namespace.go#L27)</sup>
HostNetwork requests Host network for this pod. Use the host's network namespace.
If this option is set, the ports that will be used must be specified.
Default Value: `false`
***
### .spec.init.hostPID
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/container_namespace.go#L30)</sup>
HostPID define to use the host's pid namespace.
Default Value: `false`
***
### .spec.init.image
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/image.go#L31)</sup>
@ -180,6 +222,28 @@ Image define image details
***
### .spec.init.nodeSelector
Type: `object` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/scheduling.go#L32)</sup>
NodeSelector is a selector that must be true for the workload to fit on a node.
Links:
* [Kubernetes docs](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector)
***
### .spec.init.podSecurityContext
Type: `core.PodSecurityContext` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/security_pod.go#L29)</sup>
PodSecurityContext holds pod-level security attributes and common container settings.
Links:
* [Kubernetes docs](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
***
### .spec.init.pullPolicy
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/image.go#L35)</sup>
@ -198,6 +262,63 @@ PullSecrets define Secrets used to pull Image from registry
***
### .spec.init.resources
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34)</sup>
Resources holds resource requests & limits for container
Links:
* [Documentation of core.ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#resourcerequirements-v1-core)
***
### .spec.init.schedulerName
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/scheduling.go#L47)</sup>
SchedulerName specifies, the pod will be dispatched by specified scheduler.
If not specified, the pod will be dispatched by default scheduler.
Default Value: `""`
***
### .spec.init.securityContext
Type: `core.SecurityContext` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/security_container.go#L29)</sup>
PodSecurityContext holds pod-level security attributes and common container settings.
Links:
* [Kubernetes docs](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
***
### .spec.init.shareProcessNamespace
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/container_namespace.go#L39)</sup>
ShareProcessNamespace defines to share a single process namespace between all of the containers in a pod.
When this is set containers will be able to view and signal processes from other containers
in the same pod, and the first process in each container will not be assigned PID 1.
HostPID and ShareProcessNamespace cannot both be set.
Default Value: `false`
***
### .spec.init.tolerations
Type: `[]core.Toleration` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/scheduling.go#L42)</sup>
Tolerations defines tolerations
Links:
* [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/)
***
### .spec.metadataService.local.arangoMLFeatureStore
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/ml/v1alpha1/extension_spec_metadata_service.go#L65)</sup>

View file

@ -136,7 +136,7 @@ PullSecrets define Secrets used to pull Image from registry
### .spec.mode.sidecar.resources
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L33)</sup>
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34)</sup>
Resources holds resource requests & limits for container
@ -145,6 +145,17 @@ Links:
***
### .spec.mode.sidecar.securityContext
Type: `core.SecurityContext` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/security_container.go#L29)</sup>
PodSecurityContext holds pod-level security attributes and common container settings.
Links:
* [Kubernetes docs](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
***
### .spec.mode.sidecar.shutdownListenPort
Type: `integer` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/ml/v1alpha1/storage_spec_mode_sidecar.go#L36)</sup>

View file

@ -92,7 +92,7 @@ func (a *ArangoMLExtensionSpec) Validate() error {
shared.PrefixResourceErrors("storage", shared.ValidateRequired(a.GetStorage(), func(obj sharedApi.Object) error { return obj.Validate() })),
a.GetImage().Validate(),
shared.PrefixResourceErrors("init", a.GetInit().Validate()),
shared.ValidateAnyNotNil(".image or .init.image needs to be specified", a.GetImage(), a.GetInit().GetImage()),
shared.ValidateAnyNotNil(".image or .init.image needs to be specified", a.GetImage(), a.GetInit().GetContainerTemplate().GetImage()),
shared.PrefixResourceErrors("deployment", a.GetDeployment().Validate()),
))
}

View file

@ -26,23 +26,36 @@ import (
)
type ArangoMLExtensionSpecInit struct {
// Image define default image used for the init job
*sharedApi.Image `json:",inline"`
// PodTemplate keeps the information about Pod configuration
*sharedApi.PodTemplate `json:",inline"`
// ContainerTemplate Keeps the information about Container configuration
*sharedApi.ContainerTemplate `json:",inline"`
}
func (a *ArangoMLExtensionSpecInit) GetImage() *sharedApi.Image {
if a == nil || a.Image == nil {
func (a *ArangoMLExtensionSpecInit) GetPodTemplate() *sharedApi.PodTemplate {
if a == nil {
return nil
}
return a.Image
return a.PodTemplate
}
func (a *ArangoMLExtensionSpecInit) GetContainerTemplate() *sharedApi.ContainerTemplate {
if a == nil {
return nil
}
return a.ContainerTemplate
}
func (a *ArangoMLExtensionSpecInit) Validate() error {
if a == nil {
return nil
}
return shared.WithErrors(
a.GetImage().Validate(),
a.GetPodTemplate().Validate(),
a.GetContainerTemplate().Validate(),
)
}

View file

@ -35,27 +35,16 @@ type ArangoMLStorageSpecModeSidecar struct {
// +doc/default: 9202
ShutdownListenPort *uint16 `json:"shutdownListenPort,omitempty"`
// Image define default image used for the extension
*sharedApi.Image `json:",inline"`
// Resources holds resource requests & limits for sidecar container
*sharedApi.Resources `json:",inline"`
// ContainerTemplate Keeps the information about Container configuration
*sharedApi.ContainerTemplate `json:",inline"`
}
func (s *ArangoMLStorageSpecModeSidecar) GetImage() *sharedApi.Image {
if s == nil || s.Image == nil {
func (s *ArangoMLStorageSpecModeSidecar) GetContainerTemplate() *sharedApi.ContainerTemplate {
if s == nil || s.ContainerTemplate == nil {
return nil
}
return s.Image
}
func (s *ArangoMLStorageSpecModeSidecar) GetResources() *sharedApi.Resources {
if s == nil || s.Resources == nil {
return nil
}
return s.Resources
return s.ContainerTemplate
}
func (s *ArangoMLStorageSpecModeSidecar) Validate() error {
@ -73,7 +62,7 @@ func (s *ArangoMLStorageSpecModeSidecar) Validate() error {
err = append(err, shared.PrefixResourceErrors("shutdownListenPort", errors.Newf("must be positive")))
}
err = append(err, s.GetResources().Validate())
err = append(err, s.GetContainerTemplate().Validate())
return shared.WithErrors(err...)
}

View file

@ -66,6 +66,7 @@ func Test_ArangoMLStorageSpec(t *testing.T) {
core.ResourceMemory: resource.MustParse("128Mi"),
},
}
s.Mode.Sidecar.ContainerTemplate = &sharedApi.ContainerTemplate{}
s.Mode.Sidecar.Resources = &sharedApi.Resources{Resources: &assignedRequirements}
expectedRequirements := core.ResourceRequirements{
@ -76,7 +77,7 @@ func Test_ArangoMLStorageSpec(t *testing.T) {
},
}
actualRequirements := s.Mode.Sidecar.GetResources().With(core.ResourceRequirements{
actualRequirements := s.Mode.Sidecar.GetResources().With(&sharedApi.Resources{Resources: &core.ResourceRequirements{
Limits: core.ResourceList{
core.ResourceCPU: resource.MustParse("100m"),
core.ResourceMemory: resource.MustParse("128Mi"),
@ -85,7 +86,7 @@ func Test_ArangoMLStorageSpec(t *testing.T) {
core.ResourceCPU: resource.MustParse("200m"),
core.ResourceMemory: resource.MustParse("256Mi"),
},
})
require.Equal(t, expectedRequirements, actualRequirements)
}})
require.Equal(t, expectedRequirements, *actualRequirements.GetResources())
})
}

View file

@ -446,9 +446,14 @@ func (in *ArangoMLExtensionSpecDeploymentService) DeepCopy() *ArangoMLExtensionS
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArangoMLExtensionSpecInit) DeepCopyInto(out *ArangoMLExtensionSpecInit) {
*out = *in
if in.Image != nil {
in, out := &in.Image, &out.Image
*out = new(sharedv1.Image)
if in.PodTemplate != nil {
in, out := &in.PodTemplate, &out.PodTemplate
*out = new(sharedv1.PodTemplate)
(*in).DeepCopyInto(*out)
}
if in.ContainerTemplate != nil {
in, out := &in.ContainerTemplate, &out.ContainerTemplate
*out = new(sharedv1.ContainerTemplate)
(*in).DeepCopyInto(*out)
}
return
@ -779,14 +784,9 @@ func (in *ArangoMLStorageSpecModeSidecar) DeepCopyInto(out *ArangoMLStorageSpecM
*out = new(uint16)
**out = **in
}
if in.Image != nil {
in, out := &in.Image, &out.Image
*out = new(sharedv1.Image)
(*in).DeepCopyInto(*out)
}
if in.Resources != nil {
in, out := &in.Resources, &out.Resources
*out = new(sharedv1.Resources)
if in.ContainerTemplate != nil {
in, out := &in.ContainerTemplate, &out.ContainerTemplate
*out = new(sharedv1.ContainerTemplate)
(*in).DeepCopyInto(*out)
}
return

View file

@ -0,0 +1,76 @@
//
// 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 v1
type ContainerNamespace struct {
// HostNetwork requests Host network for this pod. Use the host's network namespace.
// If this option is set, the ports that will be used must be specified.
// +doc/default: false
HostNetwork bool `json:"hostNetwork,omitempty" protobuf:"varint,11,opt,name=hostNetwork"`
// HostPID define to use the host's pid namespace.
// +doc/default: false
HostPID bool `json:"hostPID,omitempty" protobuf:"varint,12,opt,name=hostPID"`
// HostIPC defines to use the host's ipc namespace.
// +doc/default: false
HostIPC bool `json:"hostIPC,omitempty" protobuf:"varint,13,opt,name=hostIPC"`
// ShareProcessNamespace defines to share a single process namespace between all of the containers in a pod.
// When this is set containers will be able to view and signal processes from other containers
// in the same pod, and the first process in each container will not be assigned PID 1.
// HostPID and ShareProcessNamespace cannot both be set.
// +doc/default: false
ShareProcessNamespace *bool `json:"shareProcessNamespace,omitempty" protobuf:"varint,27,opt,name=shareProcessNamespace"`
}
func (c *ContainerNamespace) GetHostNetwork() bool {
if c == nil {
return false
}
return c.HostNetwork
}
func (c *ContainerNamespace) GetHostPID() bool {
if c == nil {
return false
}
return c.HostPID
}
func (c *ContainerNamespace) GetHostIPC() bool {
if c == nil {
return false
}
return c.HostIPC
}
func (c *ContainerNamespace) GetShareProcessNamespace() *bool {
if c == nil {
return nil
}
return c.ShareProcessNamespace
}
func (c *ContainerNamespace) Validate() error {
return nil
}

View file

@ -0,0 +1,91 @@
//
// 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 v1
import (
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
)
type ContainerTemplate struct {
// Image define default image used for the job
*Image `json:",inline"`
// Resources define resources assigned to the pod
*Resources `json:",inline"`
// SecurityContainer keeps the security settings for Container
*SecurityContainer `json:",inline"`
}
func (a *ContainerTemplate) With(other *ContainerTemplate) *ContainerTemplate {
if a == nil && other == nil {
return nil
}
if a == nil {
return other.DeepCopy()
}
if other == nil {
return a.DeepCopy()
}
return &ContainerTemplate{
Image: a.GetImage().With(other.GetImage()),
Resources: a.GetResources().With(other.GetResources()),
SecurityContainer: a.GetSecurityContainer().With(other.GetSecurityContainer()),
}
}
func (a *ContainerTemplate) GetImage() *Image {
if a == nil || a.Image == nil {
return nil
}
return a.Image
}
func (a *ContainerTemplate) GetSecurityContainer() *SecurityContainer {
if a == nil || a.SecurityContainer == nil {
return nil
}
return a.SecurityContainer
}
func (a *ContainerTemplate) GetResources() *Resources {
if a == nil || a.Resources == nil {
return nil
}
return a.Resources
}
func (a *ContainerTemplate) Validate() error {
if a == nil {
return nil
}
return shared.WithErrors(
a.GetImage().Validate(),
a.GetResources().Validate(),
a.GetSecurityContainer().Validate(),
)
}

View file

@ -0,0 +1,69 @@
//
// 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 v1
import "github.com/arangodb/kube-arangodb/pkg/apis/shared"
type PodTemplate struct {
// Scheduling keeps the scheduling information
*Scheduling `json:",inline"`
// ContainerNamespace keeps the Container layer Kernel namespace configuration
*ContainerNamespace `json:",inline"`
// SecurityPod keeps the security settings for Pod
*SecurityPod `json:",inline"`
}
func (a *PodTemplate) GetSecurityPod() *SecurityPod {
if a == nil {
return nil
}
return a.SecurityPod
}
func (a *PodTemplate) GetScheduling() *Scheduling {
if a == nil {
return nil
}
return a.Scheduling
}
func (a *PodTemplate) GetContainerNamespace() *ContainerNamespace {
if a == nil {
return nil
}
return a.ContainerNamespace
}
func (a *PodTemplate) Validate() error {
if a == nil {
return nil
}
return shared.WithErrors(
a.GetScheduling().Validate(),
a.GetContainerNamespace().Validate(),
a.GetSecurityPod().Validate(),
)
}

View file

@ -38,6 +38,18 @@ type Image struct {
PullSecrets []string `json:"pullSecrets,omitempty"`
}
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) GetImage() string {
if i == nil || i.Image == nil {
return ""

View file

@ -23,6 +23,7 @@ package v1
import (
core "k8s.io/api/core/v1"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/resources"
)
@ -33,12 +34,20 @@ type Resources struct {
Resources *core.ResourceRequirements `json:"resources,omitempty"`
}
func (r *Resources) With(newResources core.ResourceRequirements) core.ResourceRequirements {
if res := r.GetResources(); res == nil {
return newResources
} else {
return resources.ApplyContainerResource(*res, newResources)
func (r *Resources) With(newResources *Resources) *Resources {
if r == nil && newResources == nil {
return nil
}
if r == nil {
return newResources.DeepCopy()
}
if newResources == nil {
return r.DeepCopy()
}
return &Resources{Resources: util.NewType(resources.ApplyContainerResource(util.TypeOrDefault(r.GetResources()), util.TypeOrDefault(newResources.GetResources())))}
}
func (r *Resources) GetResources() *core.ResourceRequirements {

View file

@ -0,0 +1,84 @@
//
// 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 v1
import (
core "k8s.io/api/core/v1"
)
type SchedulingTolerations []core.Toleration
type Scheduling struct {
// NodeSelector is a selector that must be true for the workload to fit on a node.
// +doc/link: Kubernetes docs|https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
// Affinity defines scheduling constraints for workload
// +doc/type: core.Affinity
// +doc/link: Kubernetes docs|https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
Affinity *core.Affinity `json:"affinity,omitempty"`
// Tolerations defines tolerations
// +doc/type: []core.Toleration
// +doc/link: Kubernetes docs|https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/
Tolerations SchedulingTolerations `json:"tolerations,omitempty"`
// SchedulerName specifies, the pod will be dispatched by specified scheduler.
// If not specified, the pod will be dispatched by default scheduler.
// +doc/default: ""
SchedulerName *string `json:"schedulerName,omitempty"`
}
func (s *Scheduling) GetNodeSelector() map[string]string {
if s != nil {
return s.NodeSelector
}
return nil
}
func (s *Scheduling) GetSchedulerName() string {
if s != nil && s.SchedulerName != nil {
return *s.SchedulerName
}
return ""
}
func (s *Scheduling) GetAffinity() *core.Affinity {
if s != nil {
return s.Affinity
}
return nil
}
func (s *Scheduling) GetTolerations() SchedulingTolerations {
if s != nil {
return s.Tolerations
}
return nil
}
func (s *Scheduling) Validate() error {
return nil
}

View file

@ -0,0 +1,56 @@
//
// 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 v1
import core "k8s.io/api/core/v1"
type SecurityContainer struct {
// PodSecurityContext holds pod-level security attributes and common container settings.
// +doc/type: core.SecurityContext
// +doc/link: Kubernetes docs|https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
SecurityContext *core.SecurityContext `json:"securityContext,omitempty"`
}
func (s *SecurityContainer) With(other *SecurityContainer) *SecurityContainer {
if s == nil && other == nil {
return nil
}
if other == nil {
return s.DeepCopy()
}
// TODO: Add fine graned merge
return other.DeepCopy()
}
func (s *SecurityContainer) GetSecurityContext() *core.SecurityContext {
if s == nil {
return nil
}
return s.SecurityContext
}
func (s *SecurityContainer) Validate() error {
return nil
}

View file

@ -0,0 +1,42 @@
//
// 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 v1
import core "k8s.io/api/core/v1"
type SecurityPod struct {
// PodSecurityContext holds pod-level security attributes and common container settings.
// +doc/type: core.PodSecurityContext
// +doc/link: Kubernetes docs|https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
PodSecurityContext *core.PodSecurityContext `json:"podSecurityContext,omitempty"`
}
func (s *SecurityPod) GetPodSecurityContext() *core.PodSecurityContext {
if s == nil {
return nil
}
return s.PodSecurityContext
}
func (s *SecurityPod) Validate() error {
return nil
}

View file

@ -30,6 +30,58 @@ import (
types "k8s.io/apimachinery/pkg/types"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ContainerNamespace) DeepCopyInto(out *ContainerNamespace) {
*out = *in
if in.ShareProcessNamespace != nil {
in, out := &in.ShareProcessNamespace, &out.ShareProcessNamespace
*out = new(bool)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerNamespace.
func (in *ContainerNamespace) DeepCopy() *ContainerNamespace {
if in == nil {
return nil
}
out := new(ContainerNamespace)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ContainerTemplate) DeepCopyInto(out *ContainerTemplate) {
*out = *in
if in.Image != nil {
in, out := &in.Image, &out.Image
*out = new(Image)
(*in).DeepCopyInto(*out)
}
if in.Resources != nil {
in, out := &in.Resources, &out.Resources
*out = new(Resources)
(*in).DeepCopyInto(*out)
}
if in.SecurityContainer != nil {
in, out := &in.SecurityContainer, &out.SecurityContainer
*out = new(SecurityContainer)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerTemplate.
func (in *ContainerTemplate) DeepCopy() *ContainerTemplate {
if in == nil {
return nil
}
out := new(ContainerTemplate)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in HashList) DeepCopyInto(out *HashList) {
{
@ -107,6 +159,37 @@ func (in *Object) DeepCopy() *Object {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PodTemplate) DeepCopyInto(out *PodTemplate) {
*out = *in
if in.Scheduling != nil {
in, out := &in.Scheduling, &out.Scheduling
*out = new(Scheduling)
(*in).DeepCopyInto(*out)
}
if in.ContainerNamespace != nil {
in, out := &in.ContainerNamespace, &out.ContainerNamespace
*out = new(ContainerNamespace)
(*in).DeepCopyInto(*out)
}
if in.SecurityPod != nil {
in, out := &in.SecurityPod, &out.SecurityPod
*out = new(SecurityPod)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTemplate.
func (in *PodTemplate) DeepCopy() *PodTemplate {
if in == nil {
return nil
}
out := new(PodTemplate)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Resources) DeepCopyInto(out *Resources) {
*out = *in
@ -128,6 +211,110 @@ func (in *Resources) DeepCopy() *Resources {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Scheduling) DeepCopyInto(out *Scheduling) {
*out = *in
if in.NodeSelector != nil {
in, out := &in.NodeSelector, &out.NodeSelector
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Affinity != nil {
in, out := &in.Affinity, &out.Affinity
*out = new(corev1.Affinity)
(*in).DeepCopyInto(*out)
}
if in.Tolerations != nil {
in, out := &in.Tolerations, &out.Tolerations
*out = make(SchedulingTolerations, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.SchedulerName != nil {
in, out := &in.SchedulerName, &out.SchedulerName
*out = new(string)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Scheduling.
func (in *Scheduling) DeepCopy() *Scheduling {
if in == nil {
return nil
}
out := new(Scheduling)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in SchedulingTolerations) DeepCopyInto(out *SchedulingTolerations) {
{
in := &in
*out = make(SchedulingTolerations, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchedulingTolerations.
func (in SchedulingTolerations) DeepCopy() SchedulingTolerations {
if in == nil {
return nil
}
out := new(SchedulingTolerations)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecurityContainer) DeepCopyInto(out *SecurityContainer) {
*out = *in
if in.SecurityContext != nil {
in, out := &in.SecurityContext, &out.SecurityContext
*out = new(corev1.SecurityContext)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityContainer.
func (in *SecurityContainer) DeepCopy() *SecurityContainer {
if in == nil {
return nil
}
out := new(SecurityContainer)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecurityPod) DeepCopyInto(out *SecurityPod) {
*out = *in
if in.PodSecurityContext != nil {
in, out := &in.PodSecurityContext, &out.PodSecurityContext
*out = new(corev1.PodSecurityContext)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPod.
func (in *SecurityPod) DeepCopy() *SecurityPod {
if in == nil {
return nil
}
out := new(SecurityPod)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceAccount) DeepCopyInto(out *ServiceAccount) {
*out = *in

View file

@ -122,9 +122,385 @@ v1alpha1:
init:
description: ArangoMLExtensionSpecInit define Init job specification
properties:
affinity:
description: Affinity defines scheduling constraints for workload
properties:
nodeAffinity:
properties:
preferredDuringSchedulingIgnoredDuringExecution:
items:
properties:
preference:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
type: object
type: array
matchFields:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
type: object
type: array
type: object
weight:
format: int32
type: integer
type: object
type: array
requiredDuringSchedulingIgnoredDuringExecution:
properties:
nodeSelectorTerms:
items:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
type: object
type: array
matchFields:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
type: object
type: array
type: object
type: array
type: object
type: object
podAffinity:
properties:
preferredDuringSchedulingIgnoredDuringExecution:
items:
properties:
podAffinityTerm:
properties:
labelSelector:
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
namespaceSelector:
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
namespaces:
items:
type: string
type: array
topologyKey:
type: string
type: object
weight:
format: int32
type: integer
type: object
type: array
requiredDuringSchedulingIgnoredDuringExecution:
items:
properties:
labelSelector:
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
namespaceSelector:
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
namespaces:
items:
type: string
type: array
topologyKey:
type: string
type: object
type: array
type: object
podAntiAffinity:
properties:
preferredDuringSchedulingIgnoredDuringExecution:
items:
properties:
podAffinityTerm:
properties:
labelSelector:
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
namespaceSelector:
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
namespaces:
items:
type: string
type: array
topologyKey:
type: string
type: object
weight:
format: int32
type: integer
type: object
type: array
requiredDuringSchedulingIgnoredDuringExecution:
items:
properties:
labelSelector:
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
namespaceSelector:
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
namespaces:
items:
type: string
type: array
topologyKey:
type: string
type: object
type: array
type: object
type: object
hostIPC:
description: HostIPC defines to use the host's ipc namespace.
type: boolean
hostNetwork:
description: |-
HostNetwork requests Host network for this pod. Use the host's network namespace.
If this option is set, the ports that will be used must be specified.
type: boolean
hostPID:
description: HostPID define to use the host's pid namespace.
type: boolean
image:
description: Image define image details
type: string
nodeSelector:
additionalProperties:
type: string
description: NodeSelector is a selector that must be true for the workload to fit on a node.
type: object
podSecurityContext:
description: PodSecurityContext holds pod-level security attributes and common container settings.
properties:
fsGroup:
format: int64
type: integer
fsGroupChangePolicy:
type: string
runAsGroup:
format: int64
type: integer
runAsNonRoot:
type: boolean
runAsUser:
format: int64
type: integer
seLinuxOptions:
properties:
level:
type: string
role:
type: string
type:
type: string
user:
type: string
type: object
seccompProfile:
properties:
localhostProfile:
type: string
type:
type: string
type: object
supplementalGroups:
items:
format: int64
type: integer
type: array
sysctls:
items:
properties:
name:
type: string
value:
type: string
type: object
type: array
windowsOptions:
properties:
gmsaCredentialSpec:
type: string
gmsaCredentialSpecName:
type: string
hostProcess:
type: boolean
runAsUserName:
type: string
type: object
type: object
pullPolicy:
description: PullPolicy define Image pull policy
type: string
@ -133,6 +509,107 @@ v1alpha1:
items:
type: string
type: array
resources:
description: Resources holds resource requests & limits for container
properties:
limits:
additionalProperties:
type: string
type: object
requests:
additionalProperties:
type: string
type: object
type: object
schedulerName:
description: |-
SchedulerName specifies, the pod will be dispatched by specified scheduler.
If not specified, the pod will be dispatched by default scheduler.
type: string
securityContext:
description: PodSecurityContext holds pod-level security attributes and common container settings.
properties:
allowPrivilegeEscalation:
type: boolean
capabilities:
properties:
add:
items:
type: string
type: array
drop:
items:
type: string
type: array
type: object
privileged:
type: boolean
procMount:
type: string
readOnlyRootFilesystem:
type: boolean
runAsGroup:
format: int64
type: integer
runAsNonRoot:
type: boolean
runAsUser:
format: int64
type: integer
seLinuxOptions:
properties:
level:
type: string
role:
type: string
type:
type: string
user:
type: string
type: object
seccompProfile:
properties:
localhostProfile:
type: string
type:
type: string
type: object
windowsOptions:
properties:
gmsaCredentialSpec:
type: string
gmsaCredentialSpecName:
type: string
hostProcess:
type: boolean
runAsUserName:
type: string
type: object
type: object
shareProcessNamespace:
description: |-
ShareProcessNamespace defines to share a single process namespace between all of the containers in a pod.
When this is set containers will be able to view and signal processes from other containers
in the same pod, and the first process in each container will not be assigned PID 1.
HostPID and ShareProcessNamespace cannot both be set.
type: boolean
tolerations:
description: Tolerations defines tolerations
items:
properties:
effect:
type: string
key:
type: string
operator:
type: string
tolerationSeconds:
format: int64
type: integer
value:
type: string
type: object
type: array
type: object
metadataService:
description: MetadataService keeps the MetadataService configuration

View file

@ -95,6 +95,66 @@ v1alpha1:
type: string
type: object
type: object
securityContext:
description: PodSecurityContext holds pod-level security attributes and common container settings.
properties:
allowPrivilegeEscalation:
type: boolean
capabilities:
properties:
add:
items:
type: string
type: array
drop:
items:
type: string
type: array
type: object
privileged:
type: boolean
procMount:
type: string
readOnlyRootFilesystem:
type: boolean
runAsGroup:
format: int64
type: integer
runAsNonRoot:
type: boolean
runAsUser:
format: int64
type: integer
seLinuxOptions:
properties:
level:
type: string
role:
type: string
type:
type: string
user:
type: string
type: object
seccompProfile:
properties:
localhostProfile:
type: string
type:
type: string
type: object
windowsOptions:
properties:
gmsaCredentialSpec:
type: string
gmsaCredentialSpecName:
type: string
hostProcess:
type: boolean
runAsUserName:
type: string
type: object
type: object
shutdownListenPort:
description: ShutdownListenPort defines on which port the sidecar container will be listening for shutdown connections
format: int32

View file

@ -43,6 +43,18 @@ func SortKeys(m interface{}) []string {
return r
}
func CopyFullMap[K comparable, V any](src map[K]V) map[K]V {
if src == nil {
return nil
}
r := map[K]V{}
CopyMap(r, src)
return r
}
func CopyMap[K comparable, V any](dst, src map[K]V) {
// TODO: replace with maps.Copy when switching to go1.21
for k, v := range src {

View file

@ -21,5 +21,5 @@
package k8sutil
type DeepCopy[T interface{}] interface {
DeepCopy() T
DeepCopy() DeepCopy[T]
}

View file

@ -36,6 +36,7 @@ import (
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
sharedApi "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
"github.com/arangodb/kube-arangodb/pkg/handlers/utils"
@ -763,3 +764,41 @@ func GetFinalizers(spec api.ServerGroupSpec, group api.ServerGroup) []string {
return finalizers
}
func InjectPodTemplate(spec *sharedApi.PodTemplate, pod *core.PodTemplateSpec) error {
if scheduling := spec.GetScheduling(); scheduling != nil {
pod.Spec.Tolerations = scheduling.GetTolerations().DeepCopy()
pod.Spec.Affinity = scheduling.GetAffinity().DeepCopy()
pod.Spec.NodeSelector = util.CopyFullMap(scheduling.GetNodeSelector())
pod.Spec.SchedulerName = spec.GetSchedulerName()
}
if namespace := spec.GetContainerNamespace(); namespace != nil {
pod.Spec.HostNetwork = namespace.GetHostNetwork()
pod.Spec.HostPID = namespace.GetHostPID()
pod.Spec.HostIPC = namespace.GetHostIPC()
pod.Spec.ShareProcessNamespace = util.NewType(util.TypeOrDefault(namespace.GetShareProcessNamespace(), false))
}
if security := spec.GetSecurityPod(); security != nil {
pod.Spec.SecurityContext = security.PodSecurityContext.DeepCopy()
}
return nil
}
func InjectContainerTemplate(spec *sharedApi.ContainerTemplate, pod *core.PodTemplateSpec, container *core.Container) error {
if err := InjectImageDetails(spec.GetImage(), pod, container); err != nil {
return err
}
if res := spec.GetResources(); res != nil {
container.Resources = util.TypeOrDefault(res.GetResources())
}
if security := spec.GetSecurityContainer(); security != nil {
container.SecurityContext = security.SecurityContext.DeepCopy()
}
return nil
}