diff --git a/internal/services/config/config.go b/internal/services/config/config.go index 358a652..9afe5b1 100644 --- a/internal/services/config/config.go +++ b/internal/services/config/config.go @@ -109,6 +109,8 @@ type Executor struct { Driver Driver `yaml:"driver"` + InitImage InitImage `yaml:"initImage"` + Labels map[string]string `yaml:"labels"` // ActiveTasksLimit is the max number of concurrent active tasks ActiveTasksLimit int `yaml:"active_tasks_limit"` @@ -116,6 +118,10 @@ type Executor struct { AllowPrivilegedContainers bool `yaml:"allowPrivilegedContainers"` } +type InitImage struct { + Image string `yaml:"image"` +} + type Configstore struct { Debug bool `yaml:"debug"` @@ -228,6 +234,9 @@ var defaultConfig = Config{ RunWorkspaceExpireInterval: 7 * 24 * time.Hour, }, Executor: Executor{ + InitImage: InitImage{ + Image: "busybox", + }, ActiveTasksLimit: 2, }, } @@ -263,6 +272,14 @@ func validateWeb(w *Web) error { return nil } +func validateInitImage(i *InitImage) error { + if i.Image == "" { + return errors.Errorf("image is empty") + } + + return nil +} + func Validate(c *Config, componentsNames []string) error { // Global if len(c.ID) > maxIDLength { @@ -331,6 +348,10 @@ func Validate(c *Config, componentsNames []string) error { default: return errors.Errorf("executor driver type %q unknown", c.Executor.Driver.Type) } + + if err := validateInitImage(&c.Executor.InitImage); err != nil { + return errors.Errorf("executor initImage configuration error: %w", err) + } } // Scheduler diff --git a/internal/services/executor/driver/docker.go b/internal/services/executor/driver/docker.go index 0092ea2..28f317b 100644 --- a/internal/services/executor/driver/docker.go +++ b/internal/services/executor/driver/docker.go @@ -48,11 +48,12 @@ type DockerDriver struct { log *zap.SugaredLogger client *client.Client toolboxPath string + initImage string executorID string arch types.Arch } -func NewDockerDriver(logger *zap.Logger, executorID, toolboxPath string) (*DockerDriver, error) { +func NewDockerDriver(logger *zap.Logger, executorID, toolboxPath, initImage string) (*DockerDriver, error) { cli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.26")) if err != nil { return nil, err @@ -62,6 +63,7 @@ func NewDockerDriver(logger *zap.Logger, executorID, toolboxPath string) (*Docke log: logger.Sugar(), client: cli, toolboxPath: toolboxPath, + initImage: initImage, executorID: executorID, arch: types.ArchFromString(runtime.GOARCH), }, nil @@ -72,7 +74,7 @@ func (d *DockerDriver) Setup(ctx context.Context) error { } func (d *DockerDriver) createToolboxVolume(ctx context.Context, podID string) (*dockertypes.Volume, error) { - reader, err := d.client.ImagePull(ctx, "busybox", dockertypes.ImagePullOptions{}) + reader, err := d.client.ImagePull(ctx, d.initImage, dockertypes.ImagePullOptions{}) if err != nil { return nil, err } @@ -95,7 +97,7 @@ func (d *DockerDriver) createToolboxVolume(ctx context.Context, podID string) (* resp, err := d.client.ContainerCreate(ctx, &container.Config{ Entrypoint: []string{"cat"}, - Image: "busybox", + Image: d.initImage, Tty: true, }, &container.HostConfig{ Binds: []string{fmt.Sprintf("%s:%s", toolboxVol.Name, "/tmp/agola")}, diff --git a/internal/services/executor/driver/docker_test.go b/internal/services/executor/driver/docker_test.go index fecf4e4..119e28b 100644 --- a/internal/services/executor/driver/docker_test.go +++ b/internal/services/executor/driver/docker_test.go @@ -42,7 +42,9 @@ func TestDockerPod(t *testing.T) { logger := zaptest.NewLogger(t, zaptest.Level(zap.InfoLevel)) - d, err := NewDockerDriver(logger, "executorid01", toolboxPath) + initImage := "busybox" + + d, err := NewDockerDriver(logger, "executorid01", toolboxPath, initImage) if err != nil { t.Fatalf("unexpected err: %v", err) } diff --git a/internal/services/executor/driver/k8s.go b/internal/services/executor/driver/k8s.go index d778038..ae0a6a3 100644 --- a/internal/services/executor/driver/k8s.go +++ b/internal/services/executor/driver/k8s.go @@ -74,6 +74,7 @@ type K8sDriver struct { restconfig *restclient.Config client *kubernetes.Clientset toolboxPath string + initImage string namespace string executorID string executorsGroupID string @@ -95,7 +96,7 @@ type K8sPod struct { initVolumeDir string } -func NewK8sDriver(logger *zap.Logger, executorID, toolboxPath string) (*K8sDriver, error) { +func NewK8sDriver(logger *zap.Logger, executorID, toolboxPath, initImage string) (*K8sDriver, error) { kubeClientConfig := NewKubeClientConfig("", "", "") kubecfg, err := kubeClientConfig.ClientConfig() if err != nil { @@ -112,13 +113,14 @@ func NewK8sDriver(logger *zap.Logger, executorID, toolboxPath string) (*K8sDrive } d := &K8sDriver{ - log: logger.Sugar(), - restconfig: kubecfg, - client: kubecli, - toolboxPath: toolboxPath, - namespace: namespace, - executorID: executorID, - k8sLabelArch: corev1.LabelArchStable, + log: logger.Sugar(), + restconfig: kubecfg, + client: kubecli, + toolboxPath: toolboxPath, + initImage: initImage, + namespace: namespace, + executorID: executorID, + k8sLabelArch: corev1.LabelArchStable, } serverVersion, err := d.client.Discovery().ServerVersion() @@ -361,7 +363,7 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri InitContainers: []corev1.Container{ { Name: "initcontainer", - Image: "busybox", + Image: d.initImage, // wait for a file named /tmp/done and then exit Command: []string{"/bin/sh", "-c", "while true; do if [[ -f /tmp/done ]]; then exit; fi; sleep 1; done"}, Stdin: true, diff --git a/internal/services/executor/driver/k8s_test.go b/internal/services/executor/driver/k8s_test.go index f42f507..75a5c27 100644 --- a/internal/services/executor/driver/k8s_test.go +++ b/internal/services/executor/driver/k8s_test.go @@ -41,7 +41,9 @@ func TestK8sPod(t *testing.T) { logger := zaptest.NewLogger(t, zaptest.Level(zap.InfoLevel)) - d, err := NewK8sDriver(logger, "executorid01", toolboxPath) + initImage := "busybox" + + d, err := NewK8sDriver(logger, "executorid01", toolboxPath, initImage) if err != nil { t.Fatalf("unexpected err: %v", err) } diff --git a/internal/services/executor/executor.go b/internal/services/executor/executor.go index c350f94..ef87423 100644 --- a/internal/services/executor/executor.go +++ b/internal/services/executor/executor.go @@ -1426,12 +1426,12 @@ func NewExecutor(ctx context.Context, l *zap.Logger, c *config.Executor) (*Execu var d driver.Driver switch c.Driver.Type { case config.DriverTypeDocker: - d, err = driver.NewDockerDriver(logger, e.id, e.c.ToolboxPath) + d, err = driver.NewDockerDriver(logger, e.id, e.c.ToolboxPath, e.c.InitImage.Image) if err != nil { return nil, errors.Errorf("failed to create docker driver: %w", err) } case config.DriverTypeK8s: - d, err = driver.NewK8sDriver(logger, e.id, c.ToolboxPath) + d, err = driver.NewK8sDriver(logger, e.id, c.ToolboxPath, e.c.InitImage.Image) if err != nil { return nil, errors.Errorf("failed to create kubernetes driver: %w", err) } diff --git a/tests/setup_test.go b/tests/setup_test.go index 3b6ffb0..698f163 100644 --- a/tests/setup_test.go +++ b/tests/setup_test.go @@ -264,6 +264,9 @@ func setup(ctx context.Context, t *testing.T, dir string) (*testutil.TestEmbedde }, Labels: map[string]string{}, ActiveTasksLimit: 2, + InitImage: config.InitImage{ + Image: "busybox", + }, }, Configstore: config.Configstore{ Debug: false,