mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-22 16:36:30 +00:00
parent
59d824ebf8
commit
10f2e209d6
7 changed files with 111 additions and 26 deletions
|
@ -18,8 +18,10 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"os"
|
||||
"runtime"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
@ -155,6 +157,17 @@ func (e *kube) Load(ctx context.Context) (*types.BackendInfo, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (e *kube) getConfig() *config {
|
||||
if e.config == nil {
|
||||
return nil
|
||||
}
|
||||
c := *e.config
|
||||
c.PodLabels = maps.Clone(e.config.PodLabels)
|
||||
c.PodAnnotations = maps.Clone(e.config.PodLabels)
|
||||
c.ImagePullSecretNames = slices.Clone(e.config.ImagePullSecretNames)
|
||||
return &c
|
||||
}
|
||||
|
||||
// Setup 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")
|
||||
|
|
53
pipeline/backend/kubernetes/kubernetes_test.go
Normal file
53
pipeline/backend/kubernetes/kubernetes_test.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2024 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 kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGettingConfig(t *testing.T) {
|
||||
engine := kube{
|
||||
config: &config{
|
||||
Namespace: "default",
|
||||
StorageClass: "hdd",
|
||||
VolumeSize: "1G",
|
||||
StorageRwx: false,
|
||||
PodLabels: map[string]string{"l1": "v1"},
|
||||
PodAnnotations: map[string]string{"a1": "v1"},
|
||||
ImagePullSecretNames: []string{"regcred"},
|
||||
SecurityContext: SecurityContextConfig{RunAsNonRoot: false},
|
||||
},
|
||||
}
|
||||
config := engine.getConfig()
|
||||
config.Namespace = "wp"
|
||||
config.StorageClass = "ssd"
|
||||
config.StorageRwx = true
|
||||
config.PodLabels = nil
|
||||
config.PodAnnotations["a2"] = "v2"
|
||||
config.ImagePullSecretNames = append(config.ImagePullSecretNames, "docker.io")
|
||||
config.SecurityContext.RunAsNonRoot = true
|
||||
|
||||
assert.Equal(t, "default", engine.config.Namespace)
|
||||
assert.Equal(t, "hdd", engine.config.StorageClass)
|
||||
assert.Equal(t, "1G", engine.config.VolumeSize)
|
||||
assert.Equal(t, false, engine.config.StorageRwx)
|
||||
assert.Equal(t, 1, len(engine.config.PodLabels))
|
||||
assert.Equal(t, 1, len(engine.config.PodAnnotations))
|
||||
assert.Equal(t, 1, len(engine.config.ImagePullSecretNames))
|
||||
assert.Equal(t, false, engine.config.SecurityContext.RunAsNonRoot)
|
||||
}
|
|
@ -74,15 +74,16 @@ func podMeta(step *types.Step, config *config, podName string) metav1.ObjectMeta
|
|||
Namespace: config.Namespace,
|
||||
}
|
||||
|
||||
labels := make(map[string]string, len(config.PodLabels)+1)
|
||||
// copy to not alter the engine config
|
||||
maps.Copy(labels, config.PodLabels)
|
||||
labels[StepLabel] = step.Name
|
||||
meta.Labels = labels
|
||||
meta.Labels = config.PodLabels
|
||||
if meta.Labels == nil {
|
||||
meta.Labels = make(map[string]string, 1)
|
||||
}
|
||||
meta.Labels[StepLabel] = step.Name
|
||||
|
||||
// copy to not alter the engine config
|
||||
meta.Annotations = make(map[string]string, len(config.PodAnnotations))
|
||||
maps.Copy(meta.Annotations, config.PodAnnotations)
|
||||
meta.Annotations = config.PodAnnotations
|
||||
if meta.Annotations == nil {
|
||||
meta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
securityContext := step.BackendOptions.Kubernetes.SecurityContext
|
||||
if securityContext != nil {
|
||||
|
@ -442,13 +443,14 @@ func startPod(ctx context.Context, engine *kube, step *types.Step) (*v1.Pod, err
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pod, err := mkPod(step, engine.config, podName, engine.goos)
|
||||
engineConfig := engine.getConfig()
|
||||
pod, err := mkPod(step, engineConfig, podName, engine.goos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Trace().Msgf("creating pod: %s", pod.Name)
|
||||
return engine.client.CoreV1().Pods(engine.config.Namespace).Create(ctx, pod, metav1.CreateOptions{})
|
||||
return engine.client.CoreV1().Pods(engineConfig.Namespace).Create(ctx, pod, metav1.CreateOptions{})
|
||||
}
|
||||
|
||||
func stopPod(ctx context.Context, engine *kube, step *types.Step, deleteOpts metav1.DeleteOptions) error {
|
||||
|
|
|
@ -32,7 +32,7 @@ const (
|
|||
ServiceLabel = "service"
|
||||
)
|
||||
|
||||
func mkService(step *types.Step, namespace string) (*v1.Service, error) {
|
||||
func mkService(step *types.Step, config *config) (*v1.Service, error) {
|
||||
name, err := serviceName(step)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -51,7 +51,7 @@ func mkService(step *types.Step, namespace string) (*v1.Service, error) {
|
|||
return &v1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: config.Namespace,
|
||||
},
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeClusterIP,
|
||||
|
@ -77,13 +77,14 @@ func servicePort(port types.Port) v1.ServicePort {
|
|||
}
|
||||
|
||||
func startService(ctx context.Context, engine *kube, step *types.Step) (*v1.Service, error) {
|
||||
svc, err := mkService(step, engine.config.Namespace)
|
||||
engineConfig := engine.getConfig()
|
||||
svc, err := mkService(step, engineConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Trace().Str("name", svc.Name).Interface("selector", svc.Spec.Selector).Interface("ports", svc.Spec.Ports).Msg("creating service")
|
||||
return engine.client.CoreV1().Services(engine.config.Namespace).Create(ctx, svc, metav1.CreateOptions{})
|
||||
return engine.client.CoreV1().Services(engineConfig.Namespace).Create(ctx, svc, metav1.CreateOptions{})
|
||||
}
|
||||
|
||||
func stopService(ctx context.Context, engine *kube, step *types.Step, deleteOpts metav1.DeleteOptions) error {
|
||||
|
|
|
@ -82,7 +82,7 @@ func TestService(t *testing.T) {
|
|||
s, err := mkService(&types.Step{
|
||||
Name: "bar",
|
||||
Ports: ports,
|
||||
}, "foo")
|
||||
}, &config{Namespace: "foo"})
|
||||
assert.NoError(t, err)
|
||||
j, err := json.Marshal(s)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -25,15 +25,15 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func mkPersistentVolumeClaim(namespace, name, storageClass, size string, storageRwx bool) (*v1.PersistentVolumeClaim, error) {
|
||||
_storageClass := &storageClass
|
||||
if storageClass == "" {
|
||||
func mkPersistentVolumeClaim(config *config, name string) (*v1.PersistentVolumeClaim, error) {
|
||||
_storageClass := &config.StorageClass
|
||||
if config.StorageClass == "" {
|
||||
_storageClass = nil
|
||||
}
|
||||
|
||||
var accessMode v1.PersistentVolumeAccessMode
|
||||
|
||||
if storageRwx {
|
||||
if config.StorageRwx {
|
||||
accessMode = v1.ReadWriteMany
|
||||
} else {
|
||||
accessMode = v1.ReadWriteOnce
|
||||
|
@ -47,14 +47,14 @@ func mkPersistentVolumeClaim(namespace, name, storageClass, size string, storage
|
|||
pvc := &v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: volumeName,
|
||||
Namespace: namespace,
|
||||
Namespace: config.Namespace,
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{accessMode},
|
||||
StorageClassName: _storageClass,
|
||||
Resources: v1.VolumeResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceStorage: resource.MustParse(size),
|
||||
v1.ResourceStorage: resource.MustParse(config.VolumeSize),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -76,13 +76,14 @@ func volumeMountPath(name string) string {
|
|||
}
|
||||
|
||||
func startVolume(ctx context.Context, engine *kube, name string) (*v1.PersistentVolumeClaim, error) {
|
||||
pvc, err := mkPersistentVolumeClaim(engine.config.Namespace, name, engine.config.StorageClass, engine.config.VolumeSize, engine.config.StorageRwx)
|
||||
engineConfig := engine.getConfig()
|
||||
pvc, err := mkPersistentVolumeClaim(engineConfig, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Trace().Msgf("creating volume: %s", pvc.Name)
|
||||
return engine.client.CoreV1().PersistentVolumeClaims(engine.config.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
|
||||
return engine.client.CoreV1().PersistentVolumeClaims(engineConfig.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
|
||||
}
|
||||
|
||||
func stopVolume(ctx context.Context, engine *kube, name string, deleteOpts metav1.DeleteOptions) error {
|
||||
|
|
|
@ -84,20 +84,35 @@ func TestPersistentVolumeClaim(t *testing.T) {
|
|||
"status": {}
|
||||
}`
|
||||
|
||||
pvc, err := mkPersistentVolumeClaim("someNamespace", "somename", "local-storage", "1Gi", true)
|
||||
pvc, err := mkPersistentVolumeClaim(&config{
|
||||
Namespace: "someNamespace",
|
||||
StorageClass: "local-storage",
|
||||
VolumeSize: "1Gi",
|
||||
StorageRwx: true,
|
||||
}, "somename")
|
||||
assert.NoError(t, err)
|
||||
|
||||
j, err := json.Marshal(pvc)
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, expectedRwx, string(j))
|
||||
|
||||
pvc, err = mkPersistentVolumeClaim("someNamespace", "somename", "local-storage", "1Gi", false)
|
||||
pvc, err = mkPersistentVolumeClaim(&config{
|
||||
Namespace: "someNamespace",
|
||||
StorageClass: "local-storage",
|
||||
VolumeSize: "1Gi",
|
||||
StorageRwx: false,
|
||||
}, "somename")
|
||||
assert.NoError(t, err)
|
||||
|
||||
j, err = json.Marshal(pvc)
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, expectedRwo, string(j))
|
||||
|
||||
_, err = mkPersistentVolumeClaim("someNamespace", "some0..INVALID3name", "local-storage", "1Gi", false)
|
||||
_, err = mkPersistentVolumeClaim(&config{
|
||||
Namespace: "someNamespace",
|
||||
StorageClass: "local-storage",
|
||||
VolumeSize: "1Gi",
|
||||
StorageRwx: false,
|
||||
}, "some0..INVALID3name")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue