diff --git a/api/v1/ytsaurus_types.go b/api/v1/ytsaurus_types.go index 8b5c528b..415db87d 100644 --- a/api/v1/ytsaurus_types.go +++ b/api/v1/ytsaurus_types.go @@ -276,6 +276,7 @@ type MastersSpec struct { MaxSnapshotCountToKeep *int `json:"maxSnapshotCountToKeep,omitempty"` MaxChangelogCountToKeep *int `json:"maxChangelogCountToKeep,omitempty"` + // List of sidecar containers as yaml of core/v1 Container. Sidecars []string `json:"sidecars,omitempty"` } @@ -415,7 +416,9 @@ type ExecNodesSpec struct { //+kubebuilder:default:=default //+kubebuilder:validation:MinLength:=1 Name string `json:"name,omitempty"` - // List of sidecar containers as yaml of corev1.Container. + // List of init containers as yaml of core/v1 Container. + InitContainers []string `json:"initContainers,omitempty"` + // List of sidecar containers as yaml of core/v1 Container. Sidecars []string `json:"sidecars,omitempty"` //+kubebuilder:default:=true //+optional diff --git a/api/v1/ytsaurus_webhook.go b/api/v1/ytsaurus_webhook.go index c01cfe1b..c59667df 100644 --- a/api/v1/ytsaurus_webhook.go +++ b/api/v1/ytsaurus_webhook.go @@ -241,7 +241,7 @@ func validateSidecars(sidecars []string, path *field.Path) field.ErrorList { names := make(map[string]bool) for i, sidecarSpec := range sidecars { sidecar := corev1.Container{} - if err := yaml.Unmarshal([]byte(sidecarSpec), &sidecar); err != nil { + if err := yaml.UnmarshalStrict([]byte(sidecarSpec), &sidecar); err != nil { allErrors = append(allErrors, field.Invalid(path.Index(i), sidecarSpec, err.Error())) } if _, exists := names[sidecar.Name]; exists { @@ -275,6 +275,9 @@ func (r *Ytsaurus) validateExecNodes(*Ytsaurus) field.ErrorList { allErrors = append(allErrors, field.NotFound(path.Child("locations"), LocationTypeSlots)) } + if en.InitContainers != nil { + allErrors = append(allErrors, validateSidecars(en.InitContainers, path.Child("initContainers"))...) + } if en.Sidecars != nil { allErrors = append(allErrors, validateSidecars(en.Sidecars, path.Child("sidecars"))...) } diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 01488f19..46db768c 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -490,6 +490,11 @@ func (in *ExecNodesSpec) DeepCopyInto(out *ExecNodesSpec) { *out = *in in.InstanceSpec.DeepCopyInto(&out.InstanceSpec) in.ClusterNodesSpec.DeepCopyInto(&out.ClusterNodesSpec) + if in.InitContainers != nil { + in, out := &in.InitContainers, &out.InitContainers + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.Sidecars != nil { in, out := &in.Sidecars, &out.Sidecars *out = make([]string, len(*in)) diff --git a/config/crd/bases/cluster.ytsaurus.tech_remoteexecnodes.yaml b/config/crd/bases/cluster.ytsaurus.tech_remoteexecnodes.yaml index fe1161d9..c1f7a30e 100644 --- a/config/crd/bases/cluster.ytsaurus.tech_remoteexecnodes.yaml +++ b/config/crd/bases/cluster.ytsaurus.tech_remoteexecnodes.yaml @@ -690,6 +690,11 @@ spec: type: object x-kubernetes-map-type: atomic type: array + initContainers: + description: List of init containers as yaml of core/v1 Container. + items: + type: string + type: array instanceCount: format: int32 type: integer @@ -1078,7 +1083,7 @@ spec: runtimeClassName: type: string sidecars: - description: List of sidecar containers as yaml of corev1.Container. + description: List of sidecar containers as yaml of core/v1 Container. items: type: string type: array diff --git a/config/crd/bases/cluster.ytsaurus.tech_ytsaurus.yaml b/config/crd/bases/cluster.ytsaurus.tech_ytsaurus.yaml index 071e3446..652a3b14 100644 --- a/config/crd/bases/cluster.ytsaurus.tech_ytsaurus.yaml +++ b/config/crd/bases/cluster.ytsaurus.tech_ytsaurus.yaml @@ -7803,6 +7803,11 @@ spec: image: description: Overrides coreImage for component. type: string + initContainers: + description: List of init containers as yaml of core/v1 Container. + items: + type: string + type: array instanceCount: format: int32 type: integer @@ -8183,7 +8188,7 @@ spec: runtimeClassName: type: string sidecars: - description: List of sidecar containers as yaml of corev1.Container. + description: List of sidecar containers as yaml of core/v1 Container. items: type: string type: array @@ -15339,6 +15344,7 @@ spec: runtimeClassName: type: string sidecars: + description: List of sidecar containers as yaml of core/v1 Container. items: type: string type: array @@ -27074,6 +27080,7 @@ spec: runtimeClassName: type: string sidecars: + description: List of sidecar containers as yaml of core/v1 Container. items: type: string type: array diff --git a/docs/api.md b/docs/api.md index f103f203..17e097ac 100644 --- a/docs/api.md +++ b/docs/api.md @@ -458,7 +458,8 @@ _Appears in:_ | `tags` _string array_ | List of the node tags. | | | | `rack` _string_ | Name of the node rack. | | | | `name` _string_ | | default | MinLength: 1
| -| `sidecars` _string array_ | List of sidecar containers as yaml of corev1.Container. | | | +| `initContainers` _string array_ | List of init containers as yaml of core/v1 Container. | | | +| `sidecars` _string array_ | List of sidecar containers as yaml of core/v1 Container. | | | | `privileged` _boolean_ | | true | | | `jobProxyLoggers` _[TextLoggerSpec](#textloggerspec) array_ | | | | | `jobResources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#resourcerequirements-v1-core)_ | Resources dedicated for running jobs. | | | @@ -865,7 +866,7 @@ _Appears in:_ | `hostAddressLabel` _string_ | | | | | `maxSnapshotCountToKeep` _integer_ | | | | | `maxChangelogCountToKeep` _integer_ | | | | -| `sidecars` _string array_ | | | | +| `sidecars` _string array_ | List of sidecar containers as yaml of core/v1 Container. | | | #### OauthServiceSpec @@ -1115,7 +1116,8 @@ _Appears in:_ | `tags` _string array_ | List of the node tags. | | | | `rack` _string_ | Name of the node rack. | | | | `name` _string_ | | default | MinLength: 1
| -| `sidecars` _string array_ | List of sidecar containers as yaml of corev1.Container. | | | +| `initContainers` _string array_ | List of init containers as yaml of core/v1 Container. | | | +| `sidecars` _string array_ | List of sidecar containers as yaml of core/v1 Container. | | | | `privileged` _boolean_ | | true | | | `jobProxyLoggers` _[TextLoggerSpec](#textloggerspec) array_ | | | | | `jobResources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#resourcerequirements-v1-core)_ | Resources dedicated for running jobs. | | | diff --git a/pkg/components/exec_node_base.go b/pkg/components/exec_node_base.go index a414da7f..312a7638 100644 --- a/pkg/components/exec_node_base.go +++ b/pkg/components/exec_node_base.go @@ -44,6 +44,39 @@ func (n *baseExecNode) doBuildBase() error { statefulSet := n.server.buildStatefulSet() podSpec := &statefulSet.Spec.Template.Spec + if len(podSpec.Containers) != 1 { + log.Panicf("Number of exec node containers is expected to be 1, actual %v", len(podSpec.Containers)) + } + + if err := AddInitContainersToPodSpec(n.spec.InitContainers, podSpec); err != nil { + return err + } + + if err := AddSidecarsToPodSpec(n.spec.Sidecars, podSpec); err != nil { + return err + } + + setContainerPrivileged := func(ct *corev1.Container) { + if ct.SecurityContext == nil { + ct.SecurityContext = &corev1.SecurityContext{} + } + if ct.SecurityContext.Privileged == nil { + ct.SecurityContext.Privileged = ptr.Bool(n.spec.Privileged) + } + } + + for i := range podSpec.InitContainers { + setContainerPrivileged(&podSpec.InitContainers[i]) + } + + for i := range podSpec.Containers { + setContainerPrivileged(&podSpec.Containers[i]) + + if envSpec := n.spec.JobEnvironment; envSpec != nil && envSpec.CRI != nil { + n.addEnvironmentForCRITools(&podSpec.Containers[i]) + } + } + // Pour job resources into node container if jobs are not isolated. if n.spec.JobResources != nil && !n.IsJobEnvironmentIsolated() { addResourceList := func(list, newList corev1.ResourceList) { @@ -61,26 +94,6 @@ func (n *baseExecNode) doBuildBase() error { addResourceList(podSpec.Containers[0].Resources.Limits, n.spec.JobResources.Limits) } - setContainerPrivileged := func(ct *corev1.Container) { - if ct.SecurityContext == nil { - ct.SecurityContext = &corev1.SecurityContext{} - } - ct.SecurityContext.Privileged = ptr.Bool(n.spec.Privileged) - } - - if len(podSpec.Containers) != 1 { - log.Panicf("Number of exec node containers is expected to be 1, actual %v", len(podSpec.Containers)) - } - setContainerPrivileged(&podSpec.Containers[0]) - - if envSpec := n.spec.JobEnvironment; envSpec != nil && envSpec.CRI != nil { - n.addEnvironmentForCRITools(&podSpec.Containers[0]) - } - - for i := range podSpec.InitContainers { - setContainerPrivileged(&podSpec.InitContainers[i]) - } - if n.IsJobEnvironmentIsolated() { // Add sidecar container for running jobs. if envSpec := n.spec.JobEnvironment; envSpec != nil && envSpec.CRI != nil { @@ -97,10 +110,6 @@ func (n *baseExecNode) doBuildBase() error { }) } - if err := AddSidecarsToPodSpec(n.spec.Sidecars, podSpec); err != nil { - return err - } - if n.sidecarConfig != nil { podSpec.Volumes = append(podSpec.Volumes, createConfigVolume(consts.ContainerdConfigVolumeName, n.sidecarConfig.labeller.GetSidecarConfigMapName(consts.JobsContainerName), nil)) diff --git a/pkg/components/helpers.go b/pkg/components/helpers.go index b5d598e8..f9bc518b 100644 --- a/pkg/components/helpers.go +++ b/pkg/components/helpers.go @@ -209,10 +209,22 @@ func AddAffinity(statefulSet *appsv1.StatefulSet, func AddSidecarsToPodSpec(sidecar []string, podSpec *corev1.PodSpec) error { for _, sidecarSpec := range sidecar { sidecar := corev1.Container{} - if err := yaml.Unmarshal([]byte(sidecarSpec), &sidecar); err != nil { + if err := yaml.UnmarshalStrict([]byte(sidecarSpec), &sidecar); err != nil { return err } podSpec.Containers = append(podSpec.Containers, sidecar) } return nil } + +func AddInitContainersToPodSpec(initContainers []string, podSpec *corev1.PodSpec) error { + containers := make([]corev1.Container, len(initContainers), len(initContainers)+len(podSpec.InitContainers)) + for i, spec := range initContainers { + if err := yaml.UnmarshalStrict([]byte(spec), &containers[i]); err != nil { + return err + } + } + // Insert new containers into head + podSpec.InitContainers = append(containers, podSpec.InitContainers...) + return nil +} diff --git a/ytop-chart/templates/remoteexecnodes-crd.yaml b/ytop-chart/templates/remoteexecnodes-crd.yaml index 24247fde..1e1b3402 100644 --- a/ytop-chart/templates/remoteexecnodes-crd.yaml +++ b/ytop-chart/templates/remoteexecnodes-crd.yaml @@ -674,6 +674,11 @@ spec: type: object x-kubernetes-map-type: atomic type: array + initContainers: + description: List of init containers as yaml of core/v1 Container. + items: + type: string + type: array instanceCount: format: int32 type: integer @@ -1062,7 +1067,7 @@ spec: runtimeClassName: type: string sidecars: - description: List of sidecar containers as yaml of corev1.Container. + description: List of sidecar containers as yaml of core/v1 Container. items: type: string type: array diff --git a/ytop-chart/templates/ytsaurus-crd.yaml b/ytop-chart/templates/ytsaurus-crd.yaml index dfadea07..13a26231 100644 --- a/ytop-chart/templates/ytsaurus-crd.yaml +++ b/ytop-chart/templates/ytsaurus-crd.yaml @@ -7759,6 +7759,11 @@ spec: image: description: Overrides coreImage for component. type: string + initContainers: + description: List of init containers as yaml of core/v1 Container. + items: + type: string + type: array instanceCount: format: int32 type: integer @@ -8139,7 +8144,7 @@ spec: runtimeClassName: type: string sidecars: - description: List of sidecar containers as yaml of corev1.Container. + description: List of sidecar containers as yaml of core/v1 Container. items: type: string type: array @@ -15252,6 +15257,7 @@ spec: runtimeClassName: type: string sidecars: + description: List of sidecar containers as yaml of core/v1 Container. items: type: string type: array @@ -26896,6 +26902,7 @@ spec: runtimeClassName: type: string sidecars: + description: List of sidecar containers as yaml of core/v1 Container. items: type: string type: array