diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c23ed80..bd9d49a69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/docs/api/ArangoMLExtension.V1Alpha1.md b/docs/api/ArangoMLExtension.V1Alpha1.md index 2ee955e8e..3333f3c4b 100644 --- a/docs/api/ArangoMLExtension.V1Alpha1.md +++ b/docs/api/ArangoMLExtension.V1Alpha1.md @@ -38,7 +38,7 @@ PullSecrets define Secrets used to pull Image from registry ### .spec.deployment.prediction.resources -Type: `core.ResourceRequirements` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L33) +Type: `core.ResourceRequirements` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34) 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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L33) +Type: `core.ResourceRequirements` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34) 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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L33) +Type: `core.ResourceRequirements` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34) Resources holds resource requests & limits for container @@ -172,6 +172,48 @@ Image define image details *** +### .spec.init.affinity + +Type: `core.Affinity` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/scheduling.go#L37) + +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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/container_namespace.go#L33) + +HostIPC defines to use the host's ipc namespace. + +Default Value: `false` + +*** + +### .spec.init.hostNetwork + +Type: `boolean` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/container_namespace.go#L27) + +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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/container_namespace.go#L30) + +HostPID define to use the host's pid namespace. + +Default Value: `false` + +*** + ### .spec.init.image Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/image.go#L31) @@ -180,6 +222,28 @@ Image define image details *** +### .spec.init.nodeSelector + +Type: `object` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/scheduling.go#L32) + +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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/security_pod.go#L29) + +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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/image.go#L35) @@ -198,6 +262,63 @@ PullSecrets define Secrets used to pull Image from registry *** +### .spec.init.resources + +Type: `core.ResourceRequirements` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34) + +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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/scheduling.go#L47) + +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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/security_container.go#L29) + +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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/container_namespace.go#L39) + +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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/scheduling.go#L42) + +Tolerations defines tolerations + +Links: +* [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) + +*** + ### .spec.metadataService.local.arangoMLFeatureStore Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/ml/v1alpha1/extension_spec_metadata_service.go#L65) diff --git a/docs/api/ArangoMLStorage.V1Alpha1.md b/docs/api/ArangoMLStorage.V1Alpha1.md index 371485ec8..1768faf15 100644 --- a/docs/api/ArangoMLStorage.V1Alpha1.md +++ b/docs/api/ArangoMLStorage.V1Alpha1.md @@ -136,7 +136,7 @@ PullSecrets define Secrets used to pull Image from registry ### .spec.mode.sidecar.resources -Type: `core.ResourceRequirements` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L33) +Type: `core.ResourceRequirements` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/resources.go#L34) Resources holds resource requests & limits for container @@ -145,6 +145,17 @@ Links: *** +### .spec.mode.sidecar.securityContext + +Type: `core.SecurityContext` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/security_container.go#L29) + +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` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/ml/v1alpha1/storage_spec_mode_sidecar.go#L36) diff --git a/pkg/apis/ml/v1alpha1/extension_spec.go b/pkg/apis/ml/v1alpha1/extension_spec.go index 17f311377..b1f7e6818 100644 --- a/pkg/apis/ml/v1alpha1/extension_spec.go +++ b/pkg/apis/ml/v1alpha1/extension_spec.go @@ -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()), )) } diff --git a/pkg/apis/ml/v1alpha1/extension_spec_init.go b/pkg/apis/ml/v1alpha1/extension_spec_init_job.go similarity index 64% rename from pkg/apis/ml/v1alpha1/extension_spec_init.go rename to pkg/apis/ml/v1alpha1/extension_spec_init_job.go index cdc4a774b..42eab49b3 100644 --- a/pkg/apis/ml/v1alpha1/extension_spec_init.go +++ b/pkg/apis/ml/v1alpha1/extension_spec_init_job.go @@ -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(), ) } diff --git a/pkg/apis/ml/v1alpha1/storage_spec_mode_sidecar.go b/pkg/apis/ml/v1alpha1/storage_spec_mode_sidecar.go index e858d0070..b401e4158 100644 --- a/pkg/apis/ml/v1alpha1/storage_spec_mode_sidecar.go +++ b/pkg/apis/ml/v1alpha1/storage_spec_mode_sidecar.go @@ -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...) } diff --git a/pkg/apis/ml/v1alpha1/storage_spec_test.go b/pkg/apis/ml/v1alpha1/storage_spec_test.go index 88032862e..78bbcb7d1 100644 --- a/pkg/apis/ml/v1alpha1/storage_spec_test.go +++ b/pkg/apis/ml/v1alpha1/storage_spec_test.go @@ -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()) }) } diff --git a/pkg/apis/ml/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/ml/v1alpha1/zz_generated.deepcopy.go index 6a97c20ef..1b7b81efd 100644 --- a/pkg/apis/ml/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/ml/v1alpha1/zz_generated.deepcopy.go @@ -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 diff --git a/pkg/apis/shared/v1/container_namespace.go b/pkg/apis/shared/v1/container_namespace.go new file mode 100644 index 000000000..248683ef0 --- /dev/null +++ b/pkg/apis/shared/v1/container_namespace.go @@ -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 +} diff --git a/pkg/apis/shared/v1/core_container_spec.go b/pkg/apis/shared/v1/core_container_spec.go new file mode 100644 index 000000000..003da9885 --- /dev/null +++ b/pkg/apis/shared/v1/core_container_spec.go @@ -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(), + ) +} diff --git a/pkg/apis/shared/v1/core_pod_spec.go b/pkg/apis/shared/v1/core_pod_spec.go new file mode 100644 index 000000000..0a5da9f27 --- /dev/null +++ b/pkg/apis/shared/v1/core_pod_spec.go @@ -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(), + ) +} diff --git a/pkg/apis/shared/v1/image.go b/pkg/apis/shared/v1/image.go index e40de8043..d27948edd 100644 --- a/pkg/apis/shared/v1/image.go +++ b/pkg/apis/shared/v1/image.go @@ -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 "" diff --git a/pkg/apis/shared/v1/resources.go b/pkg/apis/shared/v1/resources.go index 6c9afca04..0fb3fe133 100644 --- a/pkg/apis/shared/v1/resources.go +++ b/pkg/apis/shared/v1/resources.go @@ -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 { diff --git a/pkg/apis/shared/v1/scheduling.go b/pkg/apis/shared/v1/scheduling.go new file mode 100644 index 000000000..340f7028e --- /dev/null +++ b/pkg/apis/shared/v1/scheduling.go @@ -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 +} diff --git a/pkg/apis/shared/v1/security_container.go b/pkg/apis/shared/v1/security_container.go new file mode 100644 index 000000000..d8d10f934 --- /dev/null +++ b/pkg/apis/shared/v1/security_container.go @@ -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 +} diff --git a/pkg/apis/shared/v1/security_pod.go b/pkg/apis/shared/v1/security_pod.go new file mode 100644 index 000000000..3d788b4c3 --- /dev/null +++ b/pkg/apis/shared/v1/security_pod.go @@ -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 +} diff --git a/pkg/apis/shared/v1/zz_generated.deepcopy.go b/pkg/apis/shared/v1/zz_generated.deepcopy.go index 02d8e5454..3eb567e46 100644 --- a/pkg/apis/shared/v1/zz_generated.deepcopy.go +++ b/pkg/apis/shared/v1/zz_generated.deepcopy.go @@ -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 diff --git a/pkg/crd/crds/ml-extension.schema.generated.yaml b/pkg/crd/crds/ml-extension.schema.generated.yaml index 865964bba..772cc7d2c 100644 --- a/pkg/crd/crds/ml-extension.schema.generated.yaml +++ b/pkg/crd/crds/ml-extension.schema.generated.yaml @@ -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 diff --git a/pkg/crd/crds/ml-storage.schema.generated.yaml b/pkg/crd/crds/ml-storage.schema.generated.yaml index addb482bc..a102f7fc1 100644 --- a/pkg/crd/crds/ml-storage.schema.generated.yaml +++ b/pkg/crd/crds/ml-storage.schema.generated.yaml @@ -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 diff --git a/pkg/util/dict.go b/pkg/util/dict.go index a516d3209..fa138e97b 100644 --- a/pkg/util/dict.go +++ b/pkg/util/dict.go @@ -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 { diff --git a/pkg/util/k8sutil/deepcopy.go b/pkg/util/k8sutil/deepcopy.go index 837475c8c..455197ca9 100644 --- a/pkg/util/k8sutil/deepcopy.go +++ b/pkg/util/k8sutil/deepcopy.go @@ -21,5 +21,5 @@ package k8sutil type DeepCopy[T interface{}] interface { - DeepCopy() T + DeepCopy() DeepCopy[T] } diff --git a/pkg/util/k8sutil/pods.go b/pkg/util/k8sutil/pods.go index d49471479..90485e0df 100644 --- a/pkg/util/k8sutil/pods.go +++ b/pkg/util/k8sutil/pods.go @@ -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 +}