From 71858252e1e6d23e6e3b150710b20c9faf274ce7 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 20 Jan 2024 12:33:40 +0100 Subject: [PATCH 1/5] Parse backend options on backend --- pipeline/backend/docker/convert_test.go | 2 +- .../backend/kubernetes/backend_options.go | 74 ++++++++++++++++++ pipeline/backend/kubernetes/kubernetes.go | 12 +-- pipeline/backend/kubernetes/pod.go | 48 ++++++------ pipeline/backend/kubernetes/pod_test.go | 49 ++++++------ pipeline/backend/types/auth.go | 1 - pipeline/backend/types/backend.go | 5 -- pipeline/backend/types/backend_kubernetes.go | 76 ------------------- pipeline/backend/types/step.go | 2 +- pipeline/frontend/yaml/compiler/compiler.go | 1 - pipeline/frontend/yaml/compiler/convert.go | 57 +------------- .../frontend/yaml/types/backend_options.go | 71 ----------------- pipeline/frontend/yaml/types/container.go | 2 +- server/model/registry.go | 3 +- server/pipeline/stepbuilder/stepBuilder.go | 1 - 15 files changed, 137 insertions(+), 267 deletions(-) create mode 100644 pipeline/backend/kubernetes/backend_options.go delete mode 100644 pipeline/backend/types/backend_kubernetes.go delete mode 100644 pipeline/frontend/yaml/types/backend_options.go diff --git a/pipeline/backend/docker/convert_test.go b/pipeline/backend/docker/convert_test.go index e3540e7146..435d669b4b 100644 --- a/pipeline/backend/docker/convert_test.go +++ b/pipeline/backend/docker/convert_test.go @@ -151,7 +151,7 @@ func TestToConfigFull(t *testing.T) { OnFailure: true, OnSuccess: true, Failure: "fail", - AuthConfig: backend.Auth{Username: "user", Password: "123456", Email: "user@example.com"}, + AuthConfig: backend.Auth{Username: "user", Password: "123456"}, NetworkMode: "bridge", Ports: []backend.Port{{Number: 21}, {Number: 22}}, }) diff --git a/pipeline/backend/kubernetes/backend_options.go b/pipeline/backend/kubernetes/backend_options.go new file mode 100644 index 0000000000..62097eb371 --- /dev/null +++ b/pipeline/backend/kubernetes/backend_options.go @@ -0,0 +1,74 @@ +package kubernetes + +import ( + "github.com/mitchellh/mapstructure" + + backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types" +) + +// BackendOptions defines all the advanced options for the kubernetes backend +type BackendOptions struct { + Resources Resources `mapstructure:"resouces"` + ServiceAccountName string `mapstructure:"serviceAccountName"` + NodeSelector map[string]string `mapstructure:"nodeSelector"` + Tolerations []Toleration `mapstructure:"tolerations"` + SecurityContext *SecurityContext `mapstructure:"securityContext"` +} + +// Resources defines two maps for kubernetes resource definitions +type Resources struct { + Requests map[string]string `mapstructure:"requests"` + Limits map[string]string `mapstructure:"limits"` +} + +// Toleration defines Kubernetes toleration +type Toleration struct { + Key string `mapstructure:"key"` + Operator TolerationOperator `mapstructure:"operator"` + Value string `mapstructure:"value"` + Effect TaintEffect `mapstructure:"effect"` + TolerationSeconds *int64 `mapstructure:"tolerationSeconds"` +} + +type TaintEffect string + +const ( + TaintEffectNoSchedule TaintEffect = "NoSchedule" + TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule" + TaintEffectNoExecute TaintEffect = "NoExecute" +) + +type TolerationOperator string + +const ( + TolerationOpExists TolerationOperator = "Exists" + TolerationOpEqual TolerationOperator = "Equal" +) + +type SecurityContext struct { + Privileged *bool `mapstructure:"privileged"` + RunAsNonRoot *bool `mapstructure:"runAsNonRoot"` + RunAsUser *int64 `mapstructure:"runAsUser"` + RunAsGroup *int64 `mapstructure:"runAsGroup"` + FSGroup *int64 `mapstructure:"fsGroup"` + SeccompProfile *SecProfile `mapstructure:"seccompProfile"` + ApparmorProfile *SecProfile `mapstructure:"apparmorProfile"` +} + +type SecProfile struct { + Type SecProfileType `mapstructure:"type"` + LocalhostProfile string `mapstructure:"localhostProfile"` +} + +type SecProfileType string + +const ( + SecProfileTypeRuntimeDefault SecProfileType = "RuntimeDefault" + SecProfileTypeLocalhost SecProfileType = "Localhost" +) + +func parseBackendOptions(step *backend.Step) (BackendOptions, error) { + var result BackendOptions + err := mapstructure.Decode(step.BackendOptions[EngineName], &result) + return result, err +} diff --git a/pipeline/backend/kubernetes/kubernetes.go b/pipeline/backend/kubernetes/kubernetes.go index 8b8b57676a..440ea9a846 100644 --- a/pipeline/backend/kubernetes/kubernetes.go +++ b/pipeline/backend/kubernetes/kubernetes.go @@ -168,7 +168,7 @@ func (e *kube) getConfig() *config { return &c } -// Setup the pipeline environment. +// SetupWorkflow sets up the pipeline environment. func (e *kube) SetupWorkflow(ctx context.Context, conf *types.Config, taskUUID string) error { log.Trace().Str("taskUUID", taskUUID).Msgf("Setting up Kubernetes primitives") @@ -179,7 +179,7 @@ func (e *kube) SetupWorkflow(ctx context.Context, conf *types.Config, taskUUID s } } - extraHosts := []types.HostAlias{} + var extraHosts []types.HostAlias for _, stage := range conf.Stages { for _, step := range stage.Steps { if step.Type == types.StepTypeService { @@ -202,7 +202,7 @@ func (e *kube) SetupWorkflow(ctx context.Context, conf *types.Config, taskUUID s return nil } -// Start the pipeline step. +// StartStep starts the pipeline step. func (e *kube) StartStep(ctx context.Context, step *types.Step, taskUUID string) error { if step.Type == types.StepTypeService { // a service should be started by SetupWorkflow so we can ignore it @@ -214,7 +214,7 @@ func (e *kube) StartStep(ctx context.Context, step *types.Step, taskUUID string) return err } -// Wait for the pipeline step to complete and returns +// WaitStep waits for the pipeline step to complete and returns // the completion results. func (e *kube) WaitStep(ctx context.Context, step *types.Step, taskUUID string) (*types.State, error) { podName, err := stepToPodName(step) @@ -280,7 +280,7 @@ func (e *kube) WaitStep(ctx context.Context, step *types.Step, taskUUID string) return bs, nil } -// Tail the pipeline step logs. +// TailStep tails the pipeline step logs. func (e *kube) TailStep(ctx context.Context, step *types.Step, taskUUID string) (io.ReadCloser, error) { podName, err := stepToPodName(step) if err != nil { @@ -363,7 +363,7 @@ func (e *kube) DestroyStep(ctx context.Context, step *types.Step, taskUUID strin return err } -// Destroy the pipeline environment. +// DestroyWorkflow destroys the pipeline environment. func (e *kube) DestroyWorkflow(ctx context.Context, conf *types.Config, taskUUID string) error { log.Trace().Str("taskUUID", taskUUID).Msg("deleting Kubernetes primitives") diff --git a/pipeline/backend/kubernetes/pod.go b/pipeline/backend/kubernetes/pod.go index 49f7ca6e08..160f432970 100644 --- a/pipeline/backend/kubernetes/pod.go +++ b/pipeline/backend/kubernetes/pod.go @@ -36,14 +36,18 @@ const ( ) func mkPod(step *types.Step, config *config, podName, goos string) (*v1.Pod, error) { - meta := podMeta(step, config, podName) + options, err := parseBackendOptions(step) + if err != nil { + log.Error().Err(err).Msg("could not parse backend options") + } + meta := podMeta(step, config, options, podName) - spec, err := podSpec(step, config) + spec, err := podSpec(step, config, options) if err != nil { return nil, err } - container, err := podContainer(step, podName, goos) + container, err := podContainer(step, podName, goos, options) if err != nil { return nil, err } @@ -68,7 +72,7 @@ func podName(step *types.Step) (string, error) { return dnsName(podPrefix + step.UUID) } -func podMeta(step *types.Step, config *config, podName string) metav1.ObjectMeta { +func podMeta(step *types.Step, config *config, options BackendOptions, podName string) metav1.ObjectMeta { meta := metav1.ObjectMeta{ Name: podName, Namespace: config.Namespace, @@ -85,7 +89,7 @@ func podMeta(step *types.Step, config *config, podName string) metav1.ObjectMeta meta.Annotations = make(map[string]string) } - securityContext := step.BackendOptions.Kubernetes.SecurityContext + securityContext := options.SecurityContext if securityContext != nil { key, value := apparmorAnnotation(podName, securityContext.ApparmorProfile) if key != nil && value != nil { @@ -96,16 +100,16 @@ func podMeta(step *types.Step, config *config, podName string) metav1.ObjectMeta return meta } -func podSpec(step *types.Step, config *config) (v1.PodSpec, error) { +func podSpec(step *types.Step, config *config, options BackendOptions) (v1.PodSpec, error) { var err error spec := v1.PodSpec{ RestartPolicy: v1.RestartPolicyNever, - ServiceAccountName: step.BackendOptions.Kubernetes.ServiceAccountName, + ServiceAccountName: options.ServiceAccountName, ImagePullSecrets: imagePullSecretsReferences(config.ImagePullSecretNames), HostAliases: hostAliases(step.ExtraHosts), - NodeSelector: nodeSelector(step.BackendOptions.Kubernetes.NodeSelector, step.Environment["CI_SYSTEM_PLATFORM"]), - Tolerations: tolerations(step.BackendOptions.Kubernetes.Tolerations), - SecurityContext: podSecurityContext(step.BackendOptions.Kubernetes.SecurityContext, config.SecurityContext), + NodeSelector: nodeSelector(options.NodeSelector, step.Environment["CI_SYSTEM_PLATFORM"]), + Tolerations: tolerations(options.Tolerations), + SecurityContext: podSecurityContext(options.SecurityContext, config.SecurityContext), } spec.Volumes, err = volumes(step.Volumes) if err != nil { @@ -115,7 +119,7 @@ func podSpec(step *types.Step, config *config) (v1.PodSpec, error) { return spec, nil } -func podContainer(step *types.Step, podName, goos string) (v1.Container, error) { +func podContainer(step *types.Step, podName, goos string, options BackendOptions) (v1.Container, error) { var err error container := v1.Container{ Name: podName, @@ -139,9 +143,9 @@ func podContainer(step *types.Step, podName, goos string) (v1.Container, error) container.Env = mapToEnvVars(step.Environment) container.Ports = containerPorts(step.Ports) - container.SecurityContext = containerSecurityContext(step.BackendOptions.Kubernetes.SecurityContext, step.Privileged) + container.SecurityContext = containerSecurityContext(options.SecurityContext, step.Privileged) - container.Resources, err = resourceRequirements(step.BackendOptions.Kubernetes.Resources) + container.Resources, err = resourceRequirements(options.Resources) if err != nil { return container, err } @@ -251,7 +255,7 @@ func imagePullSecretsReference(imagePullSecretName string) v1.LocalObjectReferen } } -func resourceRequirements(resources types.Resources) (v1.ResourceRequirements, error) { +func resourceRequirements(resources Resources) (v1.ResourceRequirements, error) { var err error requirements := v1.ResourceRequirements{} @@ -298,7 +302,7 @@ func nodeSelector(backendNodeSelector map[string]string, platform string) map[st return nodeSelector } -func tolerations(backendTolerations []types.Toleration) []v1.Toleration { +func tolerations(backendTolerations []Toleration) []v1.Toleration { var tolerations []v1.Toleration if len(backendTolerations) > 0 { @@ -312,7 +316,7 @@ func tolerations(backendTolerations []types.Toleration) []v1.Toleration { return tolerations } -func toleration(backendToleration types.Toleration) v1.Toleration { +func toleration(backendToleration Toleration) v1.Toleration { return v1.Toleration{ Key: backendToleration.Key, Operator: v1.TolerationOperator(backendToleration.Operator), @@ -322,7 +326,7 @@ func toleration(backendToleration types.Toleration) v1.Toleration { } } -func podSecurityContext(sc *types.SecurityContext, secCtxConf SecurityContextConfig) *v1.PodSecurityContext { +func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig) *v1.PodSecurityContext { var ( nonRoot *bool user *int64 @@ -364,7 +368,7 @@ func podSecurityContext(sc *types.SecurityContext, secCtxConf SecurityContextCon return securityContext } -func seccompProfile(scp *types.SecProfile) *v1.SeccompProfile { +func seccompProfile(scp *SecProfile) *v1.SeccompProfile { if scp == nil || len(scp.Type) == 0 { return nil } @@ -380,7 +384,7 @@ func seccompProfile(scp *types.SecProfile) *v1.SeccompProfile { return seccompProfile } -func containerSecurityContext(sc *types.SecurityContext, stepPrivileged bool) *v1.SecurityContext { +func containerSecurityContext(sc *SecurityContext, stepPrivileged bool) *v1.SecurityContext { var privileged *bool if sc != nil && sc.Privileged != nil && *sc.Privileged { @@ -400,7 +404,7 @@ func containerSecurityContext(sc *types.SecurityContext, stepPrivileged bool) *v return securityContext } -func apparmorAnnotation(containerName string, scp *types.SecProfile) (*string, *string) { +func apparmorAnnotation(containerName string, scp *SecProfile) (*string, *string) { if scp == nil { return nil, nil } @@ -411,12 +415,12 @@ func apparmorAnnotation(containerName string, scp *types.SecProfile) (*string, * profilePath string ) - if scp.Type == types.SecProfileTypeRuntimeDefault { + if scp.Type == SecProfileTypeRuntimeDefault { profileType = "runtime" profilePath = "default" } - if scp.Type == types.SecProfileTypeLocalhost { + if scp.Type == SecProfileTypeLocalhost { profileType = "localhost" profilePath = scp.LocalhostProfile } diff --git a/pipeline/backend/kubernetes/pod_test.go b/pipeline/backend/kubernetes/pod_test.go index 68cd899428..bb146d8617 100644 --- a/pipeline/backend/kubernetes/pod_test.go +++ b/pipeline/backend/kubernetes/pod_test.go @@ -288,21 +288,6 @@ func TestFullPod(t *testing.T) { {Number: 2345, Protocol: "tcp"}, {Number: 3456, Protocol: "udp"}, } - secCtx := types.SecurityContext{ - Privileged: newBool(true), - RunAsNonRoot: newBool(true), - RunAsUser: newInt64(101), - RunAsGroup: newInt64(101), - FSGroup: newInt64(101), - SeccompProfile: &types.SecProfile{ - Type: "Localhost", - LocalhostProfile: "profiles/audit.json", - }, - ApparmorProfile: &types.SecProfile{ - Type: "Localhost", - LocalhostProfile: "k8s-apparmor-example-deny-write", - }, - } pod, err := mkPod(&types.Step{ Name: "go-test", Image: "meltwater/drone-cache", @@ -315,16 +300,32 @@ func TestFullPod(t *testing.T) { Environment: map[string]string{"CGO": "0"}, ExtraHosts: hostAliases, Ports: ports, - BackendOptions: types.BackendOptions{ - Kubernetes: types.KubernetesBackendOptions{ - NodeSelector: map[string]string{"storage": "ssd"}, - ServiceAccountName: "wp-svc-acc", - Tolerations: []types.Toleration{{Key: "net-port", Value: "100Mbit", Effect: types.TaintEffectNoSchedule}}, - Resources: types.Resources{ - Requests: map[string]string{"memory": "128Mi", "cpu": "1000m"}, - Limits: map[string]string{"memory": "256Mi", "cpu": "2"}, + BackendOptions: map[string]any{ + "kubernetes": map[string]any{ + "nodeSelector": map[string]string{"storage": "ssd"}, + "serviceAccountName": "wp-svc-acc", + "tolerations": []map[string]any{ + {"key": "net-port", "value": "100Mbit", "effect": TaintEffectNoSchedule}, + }, + "resources": map[string]any{ + "requests": map[string]string{"memory": "128Mi", "cpu": "1000m"}, + "limits": map[string]string{"memory": "256Mi", "cpu": "2"}, + }, + "securityContext": map[string]any{ + "privileged": newBool(true), + "runAsNonRoot": newBool(true), + "runAsUser": newInt64(101), + "runAsGroup": newInt64(101), + "fsGroup": newInt64(101), + "seccompProfile": map[string]any{ + "type": "Localhost", + "localhostProfile": "profiles/audit.json", + }, + "apparmorProfile": map[string]any{ + "type": "Localhost", + "localhostProfile": "k8s-apparmor-example-deny-write", + }, }, - SecurityContext: &secCtx, }, }, }, &config{ diff --git a/pipeline/backend/types/auth.go b/pipeline/backend/types/auth.go index 3df98c0203..6c336a3572 100644 --- a/pipeline/backend/types/auth.go +++ b/pipeline/backend/types/auth.go @@ -18,5 +18,4 @@ package types type Auth struct { Username string `json:"username,omitempty"` Password string `json:"password,omitempty"` - Email string `json:"email,omitempty"` } diff --git a/pipeline/backend/types/backend.go b/pipeline/backend/types/backend.go index d6cfd09909..efe09c1f39 100644 --- a/pipeline/backend/types/backend.go +++ b/pipeline/backend/types/backend.go @@ -55,8 +55,3 @@ type Backend interface { type BackendInfo struct { Platform string } - -// BackendOptions defines advanced options for specific backends -type BackendOptions struct { - Kubernetes KubernetesBackendOptions `json:"kubernetes,omitempty"` -} diff --git a/pipeline/backend/types/backend_kubernetes.go b/pipeline/backend/types/backend_kubernetes.go deleted file mode 100644 index 0c1a85ec1b..0000000000 --- a/pipeline/backend/types/backend_kubernetes.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2023 Woodpecker Authors -// -// 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. - -package types - -// KubernetesBackendOptions defines all the advanced options for the kubernetes backend -type KubernetesBackendOptions struct { - Resources Resources `json:"resouces,omitempty"` - ServiceAccountName string `json:"serviceAccountName,omitempty"` - NodeSelector map[string]string `json:"nodeSelector,omitempty"` - Tolerations []Toleration `json:"tolerations,omitempty"` - SecurityContext *SecurityContext `json:"securityContext,omitempty"` -} - -// Resources defines two maps for kubernetes resource definitions -type Resources struct { - Requests map[string]string `json:"requests,omitempty"` - Limits map[string]string `json:"limits,omitempty"` -} - -// Defines Kubernetes toleration -type Toleration struct { - Key string `json:"key,omitempty"` - Operator TolerationOperator `json:"operator,omitempty"` - Value string `json:"value,omitempty"` - Effect TaintEffect `json:"effect,omitempty"` - TolerationSeconds *int64 `json:"tolerationSeconds,omitempty"` -} - -type TaintEffect string - -const ( - TaintEffectNoSchedule TaintEffect = "NoSchedule" - TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule" - TaintEffectNoExecute TaintEffect = "NoExecute" -) - -type TolerationOperator string - -const ( - TolerationOpExists TolerationOperator = "Exists" - TolerationOpEqual TolerationOperator = "Equal" -) - -type SecurityContext struct { - Privileged *bool `json:"privileged,omitempty"` - RunAsNonRoot *bool `json:"runAsNonRoot,omitempty"` - RunAsUser *int64 `json:"runAsUser,omitempty"` - RunAsGroup *int64 `json:"runAsGroup,omitempty"` - FSGroup *int64 `json:"fsGroup,omitempty"` - SeccompProfile *SecProfile `json:"seccompProfile,omitempty"` - ApparmorProfile *SecProfile `json:"apparmorProfile,omitempty"` -} - -type SecProfile struct { - Type SecProfileType `json:"type,omitempty"` - LocalhostProfile string `json:"localhostProfile,omitempty"` -} - -type SecProfileType string - -const ( - SecProfileTypeRuntimeDefault SecProfileType = "RuntimeDefault" - SecProfileTypeLocalhost SecProfileType = "Localhost" -) diff --git a/pipeline/backend/types/step.go b/pipeline/backend/types/step.go index 3fbfeeab7d..9eb61fc06c 100644 --- a/pipeline/backend/types/step.go +++ b/pipeline/backend/types/step.go @@ -46,7 +46,7 @@ type Step struct { AuthConfig Auth `json:"auth_config,omitempty"` NetworkMode string `json:"network_mode,omitempty"` Ports []Port `json:"ports,omitempty"` - BackendOptions BackendOptions `json:"backend_options,omitempty"` + BackendOptions map[string]any `json:"backend_options,omitempty"` } // StepType identifies the type of step diff --git a/pipeline/frontend/yaml/compiler/compiler.go b/pipeline/frontend/yaml/compiler/compiler.go index 3e82fcaaa1..6a0bc0fe1f 100644 --- a/pipeline/frontend/yaml/compiler/compiler.go +++ b/pipeline/frontend/yaml/compiler/compiler.go @@ -34,7 +34,6 @@ type Registry struct { Hostname string Username string Password string - Email string Token string } diff --git a/pipeline/frontend/yaml/compiler/convert.go b/pipeline/frontend/yaml/compiler/convert.go index c5b3739f4b..84b54e3074 100644 --- a/pipeline/frontend/yaml/compiler/convert.go +++ b/pipeline/frontend/yaml/compiler/convert.go @@ -111,7 +111,6 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe if utils.MatchHostname(container.Image, registry.Hostname) { authConfig.Username = registry.Username authConfig.Password = registry.Password - authConfig.Email = registry.Email break } } @@ -125,11 +124,6 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe } } - // Advanced backend settings - backendOptions := backend_types.BackendOptions{ - Kubernetes: convertKubernetesBackendOptions(&container.BackendOptions.Kubernetes), - } - memSwapLimit := int64(container.MemSwapLimit) if c.reslimit.MemSwapLimit != 0 { memSwapLimit = c.reslimit.MemSwapLimit @@ -205,7 +199,7 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe Failure: failure, NetworkMode: networkMode, Ports: ports, - BackendOptions: backendOptions, + BackendOptions: container.BackendOptions, }, nil } @@ -231,52 +225,3 @@ func convertPort(portDef string) (backend_types.Port, error) { return port, nil } - -func convertKubernetesBackendOptions(kubeOpt *yaml_types.KubernetesBackendOptions) backend_types.KubernetesBackendOptions { - resources := backend_types.Resources{ - Limits: kubeOpt.Resources.Limits, - Requests: kubeOpt.Resources.Requests, - } - - var tolerations []backend_types.Toleration - for _, t := range kubeOpt.Tolerations { - tolerations = append(tolerations, backend_types.Toleration{ - Key: t.Key, - Operator: backend_types.TolerationOperator(t.Operator), - Value: t.Value, - Effect: backend_types.TaintEffect(t.Effect), - TolerationSeconds: t.TolerationSeconds, - }) - } - - var securityContext *backend_types.SecurityContext - if kubeOpt.SecurityContext != nil { - securityContext = &backend_types.SecurityContext{ - Privileged: kubeOpt.SecurityContext.Privileged, - RunAsNonRoot: kubeOpt.SecurityContext.RunAsNonRoot, - RunAsUser: kubeOpt.SecurityContext.RunAsUser, - RunAsGroup: kubeOpt.SecurityContext.RunAsGroup, - FSGroup: kubeOpt.SecurityContext.FSGroup, - } - if kubeOpt.SecurityContext.SeccompProfile != nil { - securityContext.SeccompProfile = &backend_types.SecProfile{ - Type: backend_types.SecProfileType(kubeOpt.SecurityContext.SeccompProfile.Type), - LocalhostProfile: kubeOpt.SecurityContext.SeccompProfile.LocalhostProfile, - } - } - if kubeOpt.SecurityContext.ApparmorProfile != nil { - securityContext.ApparmorProfile = &backend_types.SecProfile{ - Type: backend_types.SecProfileType(kubeOpt.SecurityContext.ApparmorProfile.Type), - LocalhostProfile: kubeOpt.SecurityContext.ApparmorProfile.LocalhostProfile, - } - } - } - - return backend_types.KubernetesBackendOptions{ - Resources: resources, - ServiceAccountName: kubeOpt.ServiceAccountName, - NodeSelector: kubeOpt.NodeSelector, - Tolerations: tolerations, - SecurityContext: securityContext, - } -} diff --git a/pipeline/frontend/yaml/types/backend_options.go b/pipeline/frontend/yaml/types/backend_options.go deleted file mode 100644 index 5c1a1b7a9c..0000000000 --- a/pipeline/frontend/yaml/types/backend_options.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2023 Woodpecker Authors -// -// 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. - -package types - -// BackendOptions are advanced options for specific backends -type BackendOptions struct { - Kubernetes KubernetesBackendOptions `yaml:"kubernetes,omitempty"` -} - -type KubernetesBackendOptions struct { - Resources Resources `yaml:"resources,omitempty"` - ServiceAccountName string `yaml:"serviceAccountName,omitempty"` - NodeSelector map[string]string `yaml:"nodeSelector,omitempty"` - Tolerations []Toleration `yaml:"tolerations,omitempty"` - SecurityContext *SecurityContext `yaml:"securityContext,omitempty"` -} - -type Resources struct { - Requests map[string]string `yaml:"requests,omitempty"` - Limits map[string]string `yaml:"limits,omitempty"` -} - -type Toleration struct { - Key string `yaml:"key,omitempty"` - Operator TolerationOperator `yaml:"operator,omitempty"` - Value string `yaml:"value,omitempty"` - Effect TaintEffect `yaml:"effect,omitempty"` - TolerationSeconds *int64 `yaml:"tolerationSeconds,omitempty"` -} - -type TaintEffect string - -const ( - TaintEffectNoSchedule TaintEffect = "NoSchedule" - TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule" - TaintEffectNoExecute TaintEffect = "NoExecute" -) - -type TolerationOperator string - -const ( - TolerationOpExists TolerationOperator = "Exists" - TolerationOpEqual TolerationOperator = "Equal" -) - -type SecurityContext struct { - Privileged *bool `yaml:"privileged,omitempty"` - RunAsNonRoot *bool `yaml:"runAsNonRoot,omitempty"` - RunAsUser *int64 `yaml:"runAsUser,omitempty"` - RunAsGroup *int64 `yaml:"runAsGroup,omitempty"` - FSGroup *int64 `yaml:"fsGroup,omitempty"` - SeccompProfile *SecProfile `yaml:"seccompProfile,omitempty"` - ApparmorProfile *SecProfile `yaml:"apparmorProfile,omitempty"` -} - -type SecProfile struct { - Type string `yaml:"type,omitempty"` - LocalhostProfile string `yaml:"localhostProfile,omitempty"` -} diff --git a/pipeline/frontend/yaml/types/container.go b/pipeline/frontend/yaml/types/container.go index 810cd88c8f..eabeee422d 100644 --- a/pipeline/frontend/yaml/types/container.go +++ b/pipeline/frontend/yaml/types/container.go @@ -33,7 +33,7 @@ type ( // Container defines a container. Container struct { - BackendOptions BackendOptions `yaml:"backend_options,omitempty"` + BackendOptions map[string]any `yaml:"backend_options,omitempty"` Commands base.StringOrSlice `yaml:"commands,omitempty"` Entrypoint base.StringOrSlice `yaml:"entrypoint,omitempty"` Detached bool `yaml:"detach,omitempty"` diff --git a/server/model/registry.go b/server/model/registry.go index 875cd2d9c0..37c8d4f5c3 100644 --- a/server/model/registry.go +++ b/server/model/registry.go @@ -58,7 +58,8 @@ type Registry struct { Username string `json:"username" xorm:"varchar(2000) 'registry_username'"` Password string `json:"password" xorm:"TEXT 'registry_password'"` Token string `json:"token" xorm:"TEXT 'registry_token'"` - Email string `json:"email" xorm:"varchar(500) 'registry_email'"` + // TODO remove + Email string `json:"email" xorm:"varchar(500) 'registry_email'"` } // @name Registry // Validate validates the registry information. diff --git a/server/pipeline/stepbuilder/stepBuilder.go b/server/pipeline/stepbuilder/stepBuilder.go index 88c40363dd..674f381403 100644 --- a/server/pipeline/stepbuilder/stepBuilder.go +++ b/server/pipeline/stepbuilder/stepBuilder.go @@ -256,7 +256,6 @@ func (b *StepBuilder) toInternalRepresentation(parsed *yaml_types.Workflow, envi Hostname: reg.Address, Username: reg.Username, Password: reg.Password, - Email: reg.Email, }) } From d1eeb538ce9fbe16de82dd061ad3eba69ceb4f4f Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 20 Jan 2024 12:41:34 +0100 Subject: [PATCH 2/5] mod tidy, fix test, update schema --- go.mod | 1 + go.sum | 10 +- .../backend/kubernetes/backend_options.go | 2 +- .../frontend/yaml/linter/schema/schema.json | 96 +------------------ 4 files changed, 5 insertions(+), 104 deletions(-) diff --git a/go.mod b/go.mod index 4bfdc32553..1004bbf12d 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/kinbiko/jsonassert v1.1.1 github.com/lib/pq v1.10.9 github.com/mattn/go-sqlite3 v1.14.19 + github.com/mitchellh/mapstructure v1.4.2 github.com/moby/moby v24.0.7+incompatible github.com/moby/term v0.5.0 github.com/muesli/termenv v0.15.2 diff --git a/go.sum b/go.sum index c2ca7726dc..0231b2f739 100644 --- a/go.sum +++ b/go.sum @@ -308,6 +308,8 @@ github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= +github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/moby v24.0.7+incompatible h1:RrVT5IXBn85mRtFKP+gFwVLCcnNPZIgN3NVRJG9Le+4= github.com/moby/moby v24.0.7+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= @@ -417,8 +419,6 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/xanzy/go-gitlab v0.95.2 h1:4p0IirHqEp5f0baK/aQqr4TR57IsD+8e4fuyAA1yi88= -github.com/xanzy/go-gitlab v0.95.2/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xanzy/go-gitlab v0.96.0 h1:LGkZ+wSNMRtHIBaYE4Hq3dZVjprwHv3Y1+rhKU3WETs= github.com/xanzy/go-gitlab v0.96.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -622,16 +622,10 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= -k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw= k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ= -k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= -k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= -k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= -k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= k8s.io/client-go v0.29.1 h1:19B/+2NGEwnFLzt0uB5kNJnfTsbV8w6TgQRz9l7ti7A= k8s.io/client-go v0.29.1/go.mod h1:TDG/psL9hdet0TI9mGyHJSgRkW3H9JZk2dNEUS7bRks= k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= diff --git a/pipeline/backend/kubernetes/backend_options.go b/pipeline/backend/kubernetes/backend_options.go index 62097eb371..ad41396511 100644 --- a/pipeline/backend/kubernetes/backend_options.go +++ b/pipeline/backend/kubernetes/backend_options.go @@ -8,7 +8,7 @@ import ( // BackendOptions defines all the advanced options for the kubernetes backend type BackendOptions struct { - Resources Resources `mapstructure:"resouces"` + Resources Resources `mapstructure:"resources"` ServiceAccountName string `mapstructure:"serviceAccountName"` NodeSelector map[string]string `mapstructure:"nodeSelector"` Tolerations []Toleration `mapstructure:"tolerations"` diff --git a/pipeline/frontend/yaml/linter/schema/schema.json b/pipeline/frontend/yaml/linter/schema/schema.json index bdb4cccf79..e343bfdaf6 100644 --- a/pipeline/frontend/yaml/linter/schema/schema.json +++ b/pipeline/frontend/yaml/linter/schema/schema.json @@ -680,101 +680,7 @@ }, "step_backend_options": { "description": "Advanced options for the different agent backends", - "type": "object", - "properties": { - "kubernetes": { - "$ref": "#/definitions/step_backend_kubernetes" - } - } - }, - "step_backend_kubernetes": { - "description": "Advanced options for the kubernetes agent backends", - "type": "object", - "properties": { - "resources": { - "$ref": "#/definitions/step_backend_kubernetes_resources" - }, - "securityContext": { - "$ref": "#/definitions/step_backend_kubernetes_security_context" - } - } - }, - "step_backend_kubernetes_resources": { - "description": "Resources for the kubernetes backend. Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes", - "type": "object", - "properties": { - "requests": { - "$ref": "#/definitions/step_kubernetes_resources_object" - }, - "limits": { - "$ref": "#/definitions/step_kubernetes_resources_object" - } - } - }, - "step_backend_kubernetes_security_context": { - "description": "Pods / containers security context. Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes", - "type": "object", - "properties": { - "privileged": { - "type": "boolean" - }, - "runAsNonRoot": { - "type": "boolean" - }, - "runAsUser": { - "type": "number" - }, - "runAsGroup": { - "type": "number" - }, - "fsGroup": { - "type": "number" - }, - "seccompProfile": { - "$ref": "#/definitions/step_backend_kubernetes_secprofile" - }, - "apparmorProfile": { - "$ref": "#/definitions/step_backend_kubernetes_secprofile" - } - } - }, - "step_backend_kubernetes_secprofile": { - "description": "Pods / containers security profile. Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes", - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "localhostProfile": { - "type": "string" - } - } - }, - "step_kubernetes_resources_object": { - "description": "A list of kubernetes resource mappings", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "step_backend_kubernetes_service_account": { - "description": "serviceAccountName to be use by job. Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes", - "type": "object", - "properties": { - "requests": { - "$ref": "#/definitions/step_kubernetes_service_account_object" - }, - "limits": { - "$ref": "#/definitions/step_kubernetes_service_account_object" - } - } - }, - "step_kubernetes_service_account_object": { - "description": "A list of kubernetes resource mappings", - "type": "object", - "additionalProperties": { - "type": "string" - } + "type": "object" }, "services": { "description": "Read more: https://woodpecker-ci.org/docs/usage/services", From e042b7fb329cb699890f0ffcd4b1cf45d5dc352d Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 20 Jan 2024 18:38:04 +0100 Subject: [PATCH 3/5] Restore schema --- .../frontend/yaml/linter/schema/schema.json | 96 ++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/pipeline/frontend/yaml/linter/schema/schema.json b/pipeline/frontend/yaml/linter/schema/schema.json index e343bfdaf6..bdb4cccf79 100644 --- a/pipeline/frontend/yaml/linter/schema/schema.json +++ b/pipeline/frontend/yaml/linter/schema/schema.json @@ -680,7 +680,101 @@ }, "step_backend_options": { "description": "Advanced options for the different agent backends", - "type": "object" + "type": "object", + "properties": { + "kubernetes": { + "$ref": "#/definitions/step_backend_kubernetes" + } + } + }, + "step_backend_kubernetes": { + "description": "Advanced options for the kubernetes agent backends", + "type": "object", + "properties": { + "resources": { + "$ref": "#/definitions/step_backend_kubernetes_resources" + }, + "securityContext": { + "$ref": "#/definitions/step_backend_kubernetes_security_context" + } + } + }, + "step_backend_kubernetes_resources": { + "description": "Resources for the kubernetes backend. Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes", + "type": "object", + "properties": { + "requests": { + "$ref": "#/definitions/step_kubernetes_resources_object" + }, + "limits": { + "$ref": "#/definitions/step_kubernetes_resources_object" + } + } + }, + "step_backend_kubernetes_security_context": { + "description": "Pods / containers security context. Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes", + "type": "object", + "properties": { + "privileged": { + "type": "boolean" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "number" + }, + "runAsGroup": { + "type": "number" + }, + "fsGroup": { + "type": "number" + }, + "seccompProfile": { + "$ref": "#/definitions/step_backend_kubernetes_secprofile" + }, + "apparmorProfile": { + "$ref": "#/definitions/step_backend_kubernetes_secprofile" + } + } + }, + "step_backend_kubernetes_secprofile": { + "description": "Pods / containers security profile. Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes", + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "localhostProfile": { + "type": "string" + } + } + }, + "step_kubernetes_resources_object": { + "description": "A list of kubernetes resource mappings", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "step_backend_kubernetes_service_account": { + "description": "serviceAccountName to be use by job. Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes", + "type": "object", + "properties": { + "requests": { + "$ref": "#/definitions/step_kubernetes_service_account_object" + }, + "limits": { + "$ref": "#/definitions/step_kubernetes_service_account_object" + } + } + }, + "step_kubernetes_service_account_object": { + "description": "A list of kubernetes resource mappings", + "type": "object", + "additionalProperties": { + "type": "string" + } }, "services": { "description": "Read more: https://woodpecker-ci.org/docs/usage/services", From 9eaebdddb67d9b52789836c1b1b6dc5958843820 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 20 Jan 2024 18:46:00 +0100 Subject: [PATCH 4/5] Parse in higher func --- .../backend/kubernetes/backend_options.go | 3 + .../kubernetes/backend_options_test.go | 73 +++++++++++++++++++ pipeline/backend/kubernetes/kubernetes.go | 8 +- pipeline/backend/kubernetes/pod.go | 10 +-- pipeline/backend/kubernetes/pod_test.go | 56 +++++++------- 5 files changed, 112 insertions(+), 38 deletions(-) create mode 100644 pipeline/backend/kubernetes/backend_options_test.go diff --git a/pipeline/backend/kubernetes/backend_options.go b/pipeline/backend/kubernetes/backend_options.go index ad41396511..689f835fee 100644 --- a/pipeline/backend/kubernetes/backend_options.go +++ b/pipeline/backend/kubernetes/backend_options.go @@ -69,6 +69,9 @@ const ( func parseBackendOptions(step *backend.Step) (BackendOptions, error) { var result BackendOptions + if step.BackendOptions == nil { + return result, nil + } err := mapstructure.Decode(step.BackendOptions[EngineName], &result) return result, err } diff --git a/pipeline/backend/kubernetes/backend_options_test.go b/pipeline/backend/kubernetes/backend_options_test.go new file mode 100644 index 0000000000..f9c21a5fe0 --- /dev/null +++ b/pipeline/backend/kubernetes/backend_options_test.go @@ -0,0 +1,73 @@ +package kubernetes + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types" +) + +func Test_parseBackendOptions(t *testing.T) { + got, err := parseBackendOptions(&backend.Step{BackendOptions: nil}) + assert.NoError(t, err) + assert.Equal(t, BackendOptions{}, got) + got, err = parseBackendOptions(&backend.Step{BackendOptions: map[string]any{}}) + assert.NoError(t, err) + assert.Equal(t, BackendOptions{}, got) + got, err = parseBackendOptions(&backend.Step{ + BackendOptions: map[string]any{ + "kubernetes": map[string]any{ + "nodeSelector": map[string]string{"storage": "ssd"}, + "serviceAccountName": "wp-svc-acc", + "tolerations": []map[string]any{ + {"key": "net-port", "value": "100Mbit", "effect": TaintEffectNoSchedule}, + }, + "resources": map[string]any{ + "requests": map[string]string{"memory": "128Mi", "cpu": "1000m"}, + "limits": map[string]string{"memory": "256Mi", "cpu": "2"}, + }, + "securityContext": map[string]any{ + "privileged": newBool(true), + "runAsNonRoot": newBool(true), + "runAsUser": newInt64(101), + "runAsGroup": newInt64(101), + "fsGroup": newInt64(101), + "seccompProfile": map[string]any{ + "type": "Localhost", + "localhostProfile": "profiles/audit.json", + }, + "apparmorProfile": map[string]any{ + "type": "Localhost", + "localhostProfile": "k8s-apparmor-example-deny-write", + }, + }, + }, + }, + }) + assert.NoError(t, err) + assert.Equal(t, BackendOptions{ + NodeSelector: map[string]string{"storage": "ssd"}, + ServiceAccountName: "wp-svc-acc", + Tolerations: []Toleration{{Key: "net-port", Value: "100Mbit", Effect: TaintEffectNoSchedule}}, + Resources: Resources{ + Requests: map[string]string{"memory": "128Mi", "cpu": "1000m"}, + Limits: map[string]string{"memory": "256Mi", "cpu": "2"}, + }, + SecurityContext: &SecurityContext{ + Privileged: newBool(true), + RunAsNonRoot: newBool(true), + RunAsUser: newInt64(101), + RunAsGroup: newInt64(101), + FSGroup: newInt64(101), + SeccompProfile: &SecProfile{ + Type: "Localhost", + LocalhostProfile: "profiles/audit.json", + }, + ApparmorProfile: &SecProfile{ + Type: "Localhost", + LocalhostProfile: "k8s-apparmor-example-deny-write", + }, + }, + }, got) +} diff --git a/pipeline/backend/kubernetes/kubernetes.go b/pipeline/backend/kubernetes/kubernetes.go index 440ea9a846..3bc2eb63e1 100644 --- a/pipeline/backend/kubernetes/kubernetes.go +++ b/pipeline/backend/kubernetes/kubernetes.go @@ -209,8 +209,14 @@ func (e *kube) StartStep(ctx context.Context, step *types.Step, taskUUID string) log.Trace().Msgf("StartStep got service '%s', ignoring it.", step.Name) return nil } + + options, err := parseBackendOptions(step) + if err != nil { + log.Error().Err(err).Msg("could not parse backend options") + } + log.Trace().Str("taskUUID", taskUUID).Msgf("starting step: %s", step.Name) - _, err := startPod(ctx, e, step) + _, err = startPod(ctx, e, step, options) return err } diff --git a/pipeline/backend/kubernetes/pod.go b/pipeline/backend/kubernetes/pod.go index 160f432970..391daf4eff 100644 --- a/pipeline/backend/kubernetes/pod.go +++ b/pipeline/backend/kubernetes/pod.go @@ -35,11 +35,7 @@ const ( podPrefix = "wp-" ) -func mkPod(step *types.Step, config *config, podName, goos string) (*v1.Pod, error) { - options, err := parseBackendOptions(step) - if err != nil { - log.Error().Err(err).Msg("could not parse backend options") - } +func mkPod(step *types.Step, config *config, podName, goos string, options BackendOptions) (*v1.Pod, error) { meta := podMeta(step, config, options, podName) spec, err := podSpec(step, config, options) @@ -445,13 +441,13 @@ func mapToEnvVars(m map[string]string) []v1.EnvVar { return ev } -func startPod(ctx context.Context, engine *kube, step *types.Step) (*v1.Pod, error) { +func startPod(ctx context.Context, engine *kube, step *types.Step, options BackendOptions) (*v1.Pod, error) { podName, err := podName(step) if err != nil { return nil, err } engineConfig := engine.getConfig() - pod, err := mkPod(step, engineConfig, podName, engine.goos) + pod, err := mkPod(step, engineConfig, podName, engine.goos, options) if err != nil { return nil, err } diff --git a/pipeline/backend/kubernetes/pod_test.go b/pipeline/backend/kubernetes/pod_test.go index bb146d8617..fc1eff6881 100644 --- a/pipeline/backend/kubernetes/pod_test.go +++ b/pipeline/backend/kubernetes/pod_test.go @@ -130,7 +130,7 @@ func TestTinyPod(t *testing.T) { Environment: map[string]string{"CI": "woodpecker"}, }, &config{ Namespace: "woodpecker", - }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64") + }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{}) assert.NoError(t, err) json, err := json.Marshal(pod) @@ -288,6 +288,21 @@ func TestFullPod(t *testing.T) { {Number: 2345, Protocol: "tcp"}, {Number: 3456, Protocol: "udp"}, } + secCtx := SecurityContext{ + Privileged: newBool(true), + RunAsNonRoot: newBool(true), + RunAsUser: newInt64(101), + RunAsGroup: newInt64(101), + FSGroup: newInt64(101), + SeccompProfile: &SecProfile{ + Type: "Localhost", + LocalhostProfile: "profiles/audit.json", + }, + ApparmorProfile: &SecProfile{ + Type: "Localhost", + LocalhostProfile: "k8s-apparmor-example-deny-write", + }, + } pod, err := mkPod(&types.Step{ Name: "go-test", Image: "meltwater/drone-cache", @@ -300,41 +315,22 @@ func TestFullPod(t *testing.T) { Environment: map[string]string{"CGO": "0"}, ExtraHosts: hostAliases, Ports: ports, - BackendOptions: map[string]any{ - "kubernetes": map[string]any{ - "nodeSelector": map[string]string{"storage": "ssd"}, - "serviceAccountName": "wp-svc-acc", - "tolerations": []map[string]any{ - {"key": "net-port", "value": "100Mbit", "effect": TaintEffectNoSchedule}, - }, - "resources": map[string]any{ - "requests": map[string]string{"memory": "128Mi", "cpu": "1000m"}, - "limits": map[string]string{"memory": "256Mi", "cpu": "2"}, - }, - "securityContext": map[string]any{ - "privileged": newBool(true), - "runAsNonRoot": newBool(true), - "runAsUser": newInt64(101), - "runAsGroup": newInt64(101), - "fsGroup": newInt64(101), - "seccompProfile": map[string]any{ - "type": "Localhost", - "localhostProfile": "profiles/audit.json", - }, - "apparmorProfile": map[string]any{ - "type": "Localhost", - "localhostProfile": "k8s-apparmor-example-deny-write", - }, - }, - }, - }, }, &config{ Namespace: "woodpecker", ImagePullSecretNames: []string{"regcred", "another-pull-secret"}, PodLabels: map[string]string{"app": "test"}, PodAnnotations: map[string]string{"apps.kubernetes.io/pod-index": "0"}, SecurityContext: SecurityContextConfig{RunAsNonRoot: false}, - }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64") + }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{ + NodeSelector: map[string]string{"storage": "ssd"}, + ServiceAccountName: "wp-svc-acc", + Tolerations: []Toleration{{Key: "net-port", Value: "100Mbit", Effect: TaintEffectNoSchedule}}, + Resources: Resources{ + Requests: map[string]string{"memory": "128Mi", "cpu": "1000m"}, + Limits: map[string]string{"memory": "256Mi", "cpu": "2"}, + }, + SecurityContext: &secCtx, + }) assert.NoError(t, err) json, err := json.Marshal(pod) From 6114516887d642eee251f29b9edae8d5fb29f57b Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Mon, 22 Jan 2024 08:00:50 +0100 Subject: [PATCH 5/5] Add schema test --- .../linter/schema/.woodpecker/test-custom-backend.yaml | 10 ++++++++++ pipeline/frontend/yaml/linter/schema/schema_test.go | 5 +++++ 2 files changed, 15 insertions(+) create mode 100644 pipeline/frontend/yaml/linter/schema/.woodpecker/test-custom-backend.yaml diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-custom-backend.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-custom-backend.yaml new file mode 100644 index 0000000000..de6b09b9f5 --- /dev/null +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-custom-backend.yaml @@ -0,0 +1,10 @@ +steps: + build: + image: golang + commands: + - go build + - go test + backend_options: + custom_backend: + option1: xyz + option2: [1, 2, 3] diff --git a/pipeline/frontend/yaml/linter/schema/schema_test.go b/pipeline/frontend/yaml/linter/schema/schema_test.go index 29bc5a4c40..d423a9e3de 100644 --- a/pipeline/frontend/yaml/linter/schema/schema_test.go +++ b/pipeline/frontend/yaml/linter/schema/schema_test.go @@ -111,6 +111,11 @@ func TestSchema(t *testing.T) { testFile: ".woodpecker/test-dag.yaml", fail: false, }, + { + name: "Custom backend", + testFile: ".woodpecker/test-custom-backend.yaml", + fail: false, + }, } for _, tt := range testTable {