diff --git a/docs/config.md b/docs/config.md index cd32705..4d194f0 100644 --- a/docs/config.md +++ b/docs/config.md @@ -17,8 +17,9 @@ To change the default container runtime: ```yaml # ... -container: - runtime: kubernetes +runtime: + container: + default_runtime: kubernetes # ... ``` diff --git a/pkg/action/runtime.container.go b/pkg/action/runtime.container.go index d078ee0..896b48a 100644 --- a/pkg/action/runtime.container.go +++ b/pkg/action/runtime.container.go @@ -29,6 +29,8 @@ const ( containerFlagRebuildImage = "rebuild-image" containerFlagEntrypoint = "entrypoint" containerFlagExec = "exec" + containerRegistryURL = "registry-url" + containerRegistryType = "registry-type" ) type runtimeContainer struct { @@ -50,15 +52,20 @@ type runtimeContainer struct { nameprv ContainerNameProvider // Runtime flags - isSetRemote bool - copyBack bool - removeImg bool - noCache bool - rebuildImage bool - entrypoint string - entrypointSet bool - exec bool - volumeFlags string + // @todo need to think about a better way to handle this. + runtimeFlags driver.RuntimeFlags + + //isSetRemote bool + //copyBack bool + //removeImg bool + //noCache bool + //rebuildImage bool + //entrypoint string + //entrypointSet bool + //exec bool + //volumeFlags string + //registryURL string + //registryType string } // ContainerNameProvider provides an ability to generate a random container name @@ -156,6 +163,19 @@ func (c *runtimeContainer) GetFlags() *FlagsGroup { Type: jsonschema.Boolean, Default: false, }, + &DefParameter{ + Name: containerRegistryURL, + Title: "k8s Images registry URL", + Type: jsonschema.String, + Default: "localhost:5000", + }, + &DefParameter{ + Name: containerRegistryType, + Title: "k8s Images registry type", + Type: jsonschema.String, + Enum: []any{driver.RegistryNone, driver.RegistryLocal, driver.RegistryRemote}, + Default: driver.RegistryLocal, + }, } flags.AddDefinitions(definitions) @@ -184,32 +204,40 @@ func (c *runtimeContainer) SetFlags(input *Input) error { flags := input.GroupFlags(c.flags.GetName()) if v, ok := flags[containerFlagRemote]; ok { - c.isSetRemote = v.(bool) + c.runtimeFlags.IsSetRemote = v.(bool) } if v, ok := flags[containerFlagCopyBack]; ok { - c.copyBack = v.(bool) + c.runtimeFlags.CopyBack = v.(bool) } if r, ok := flags[containerFlagRemoveImage]; ok { - c.removeImg = r.(bool) + c.runtimeFlags.RemoveImg = r.(bool) } if nc, ok := flags[containerFlagNoCache]; ok { - c.noCache = nc.(bool) + c.runtimeFlags.NoCache = nc.(bool) } if rb, ok := flags[containerFlagRebuildImage]; ok { - c.rebuildImage = rb.(bool) + c.runtimeFlags.RebuildImage = rb.(bool) } if e, ok := flags[containerFlagEntrypoint]; ok && e != "" { - c.entrypointSet = true - c.entrypoint = e.(string) + c.runtimeFlags.EntrypointSet = true + c.runtimeFlags.Entrypoint = e.(string) } if ex, ok := flags[containerFlagExec]; ok { - c.exec = ex.(bool) + c.runtimeFlags.Exec = ex.(bool) + } + + if rt, ok := flags[containerRegistryType]; ok { + c.runtimeFlags.RegistryType = rt.(string) + } + + if rurl, ok := flags[containerRegistryURL]; ok { + c.runtimeFlags.RegistryURL = rurl.(string) } return nil @@ -241,15 +269,17 @@ func (c *runtimeContainer) Init(ctx context.Context, _ *Action) (err error) { if !c.isRemote() && c.isSELinuxEnabled(ctx) { // Check SELinux settings to allow reading the FS inside a container. // Use the lowercase z flag to allow concurrent actions access to the FS. - c.volumeFlags += ":z" + c.runtimeFlags.VolumeFlags += ":z" launchr.Term().Warning().Printfln( "SELinux is detected. The volumes will be mounted with the %q flags, which will relabel your files.\n"+ "This process may take time or potentially break existing permissions.", - c.volumeFlags, + c.runtimeFlags.VolumeFlags, ) - c.Log().Warn("using selinux flags", "flags", c.volumeFlags) + c.Log().Warn("using selinux flags", "flags", c.runtimeFlags.VolumeFlags) } + c.crt.SetRuntimeFlags(c.runtimeFlags) + return nil } @@ -298,7 +328,7 @@ func (c *runtimeContainer) Execute(ctx context.Context, a *Action) (err error) { // Remove the used image if it was specified. defer func() { - if !c.removeImg { + if !c.runtimeFlags.RemoveImg { return } log.Debug("removing container image after run") @@ -405,7 +435,7 @@ func (c *runtimeContainer) imageRemove(ctx context.Context, a *Action) error { func (c *runtimeContainer) isRebuildRequired(bi *driver.BuildDefinition) (bool, error) { // @todo test image cache resolution somehow. - if c.imgccres == nil || bi == nil || !c.rebuildImage { + if c.imgccres == nil || bi == nil || !c.runtimeFlags.RebuildImage { return false, nil } @@ -454,7 +484,7 @@ func (c *runtimeContainer) imageEnsure(ctx context.Context, a *Action) error { status, err := crt.ImageEnsure(ctx, driver.ImageOptions{ Name: image, Build: buildInfo, - NoCache: c.noCache, + NoCache: c.runtimeFlags.NoCache, ForceRebuild: forceRebuild, }) if err != nil { @@ -521,13 +551,13 @@ func (c *runtimeContainer) createContainerDef(a *Action, cname string) driver.Co // Override an entrypoint if it was set in flags. var entrypoint []string - if c.entrypointSet { - entrypoint = []string{c.entrypoint} + if c.runtimeFlags.EntrypointSet { + entrypoint = []string{c.runtimeFlags.Entrypoint} } // Override Command with exec command. cmd := runDef.Container.Command - if c.exec { + if c.runtimeFlags.Exec { cmd = a.Input().ArgsPositional() } @@ -556,8 +586,8 @@ func (c *runtimeContainer) createContainerDef(a *Action, cname string) driver.Co ) } else { createOpts.Binds = []string{ - launchr.MustAbs(a.WorkDir()) + ":" + containerHostMount + c.volumeFlags, - launchr.MustAbs(a.Dir()) + ":" + containerActionMount + c.volumeFlags, + launchr.MustAbs(a.WorkDir()) + ":" + containerHostMount + c.runtimeFlags.VolumeFlags, + launchr.MustAbs(a.Dir()) + ":" + containerActionMount + c.runtimeFlags.VolumeFlags, } } return createOpts @@ -591,7 +621,7 @@ func (c *runtimeContainer) copyAllToContainer(ctx context.Context, cid string, a } func (c *runtimeContainer) copyAllFromContainer(ctx context.Context, cid string, a *Action) (err error) { - if !c.isRemote() || !c.copyBack { + if !c.isRemote() || !c.runtimeFlags.CopyBack { return nil } // @todo it's a bad implementation considering consequential runs, need to find a better way to sync with remote. @@ -670,5 +700,5 @@ func (c *runtimeContainer) isSELinuxEnabled(ctx context.Context) bool { } func (c *runtimeContainer) isRemote() bool { - return c.isRemoteRuntime || c.isSetRemote + return c.isRemoteRuntime || c.runtimeFlags.IsSetRemote } diff --git a/pkg/action/runtime.container_test.go b/pkg/action/runtime.container_test.go index 04af250..2317523 100644 --- a/pkg/action/runtime.container_test.go +++ b/pkg/action/runtime.container_test.go @@ -342,9 +342,11 @@ func Test_ContainerExec_createContainerDef(t *testing.T) { input.SetValidated(true) _ = a.SetInput(input) r.isRemoteRuntime = true - r.entrypointSet = true - r.entrypoint = "/my/entrypoint" - r.exec = true + r.runtimeFlags = driver.RuntimeFlags{ + EntrypointSet: true, + Entrypoint: "/my/entrypoint", + Exec: true, + } return a }, driver.ContainerDefinition{ diff --git a/pkg/driver/docker.go b/pkg/driver/docker.go index b9d6c7a..1bae546 100644 --- a/pkg/driver/docker.go +++ b/pkg/driver/docker.go @@ -43,6 +43,10 @@ func NewDockerRuntime() (ContainerRunner, error) { return &dockerRuntime{cli: c}, nil } +func (d *dockerRuntime) SetRuntimeFlags(_ RuntimeFlags) { + +} + func (d *dockerRuntime) Info(ctx context.Context) (SystemInfo, error) { if d.info.ID != "" { return d.info, nil diff --git a/pkg/driver/k8s.templates.go b/pkg/driver/k8s.templates.go new file mode 100644 index 0000000..4715bc2 --- /dev/null +++ b/pkg/driver/k8s.templates.go @@ -0,0 +1,163 @@ +package driver + +import ( + "fmt" + "strings" + "text/template" +) + +func executeTemplate(templateStr string, data any) (string, error) { + tmpl, err := template.New("script").Parse(templateStr) + if err != nil { + return "", err + } + + var buf strings.Builder + err = tmpl.Execute(&buf, data) + if err != nil { + return "", err + } + + return buf.String(), nil +} + +// ensure image exists in local registry +const buildahImageEnsureTemplate = ` +set -e +cd /action +if [ ! -f "./%s" ]; then + echo "%s does not exist" + exit 1 +fi +image_status=$(curl -s -I -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ +-H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \ +-H "Accept: application/vnd.oci.image.manifest.v1+json" \ +-H "Accept: application/vnd.oci.image.index.v1+json" \ +-o /dev/null -w "%%{http_code}" %s) +if [ "$image_status" = "200" ]; then + echo "image exists" +fi +` + +const buildahInitTemplate = ` +set -e +echo "Buildah sidecar started" + +# Create containers config directory +mkdir -p /etc/containers + +# Configure registries +cat > /etc/containers/registries.conf << 'EOF' +unqualified-search-registries = ["docker.io"] + +[[registry]] +location = "{{.RegistryURL}}" +{{if .Insecure}}insecure = true{{else}}insecure = false{{end}} +EOF + +# Test registry connectivity +curl -f {{.RegistryURL}}/v2/ || { + echo "ERROR: Cannot connect to registry" + exit 1 +} +echo 'Registry connection works' + +# Test buildah +buildah version + +# Keep running to maintain container availability +while true; do + sleep 60 + echo "Buildah sidecar still running..." +done +` + +// Buildah image build template +const buildahBuildTemplate = ` +set -e +cd /action +echo "Starting image build process..." + +{{if .BuildArgs}} +# Build arguments: +{{range $key, $value := .BuildArgs}}echo " --build-arg {{$key}}={{$value}}" +{{end}} +{{end}} + +# Build the image +echo "Building image: {{.RegistryURL}}/{{.ImageName}}" +buildah build --layers \ + -t {{.RegistryURL}}/{{.ImageName}} \ + -f {{.Buildfile}} \ +{{range $key, $value := .BuildArgs}} --build-arg {{$key}}="{{$value}}" \ +{{end}} . 2>&1 || { + echo "ERROR: Build failed with exit code $?" + exit 1 +} + +echo "Build completed successfully" + +# Push to registry +echo "Pushing image to registry..." +{{if .Insecure}} +buildah push --tls-verify=false {{.RegistryURL}}/{{.ImageName}} 2>&1 || { +{{else}} +buildah push {{.RegistryURL}}/{{.ImageName}} 2>&1 || { +{{end}} + echo "ERROR: Push failed with exit code $?" + exit 1 +} + +echo "Build and push completed successfully!" +echo "Image available at:{{.RegistryURL}}/{{.ImageName}}" + +# Verify the push +echo "Verifying image was pushed..." +curl -f {{.RegistryURL}}/v2/_catalog || echo "Warning: Could not verify catalog" +` + +func (k *k8sRuntime) prepareBuildahInitScript() (string, error) { + type buildData struct { + ImageName string + RegistryURL string + Insecure bool + } + + data := &buildData{ + RegistryURL: k.crtflags.RegistryURL, + Insecure: k.crtflags.RegistryType == RegistryLocal, + } + + script, err := executeTemplate(buildahInitTemplate, data) + if err != nil { + return "", fmt.Errorf("failed to generate init build script: %w", err) + } + + return script, nil +} + +func (k *k8sRuntime) prepareBuildahWorkScript(imageName string) (string, error) { + // Add build args to template data + type BuildData struct { + ImageName string + RegistryURL string + BuildArgs map[string]*string + Buildfile string + Insecure bool + } + + buildData := &BuildData{ + ImageName: imageName, + RegistryURL: k.crtflags.RegistryURL, + BuildArgs: k.imageOptions.Build.Args, + Buildfile: ensureBuildFile(k.imageOptions.Build.Buildfile), + Insecure: k.crtflags.RegistryType == RegistryLocal, + } + + script, err := executeTemplate(buildahBuildTemplate, buildData) + if err != nil { + return "", fmt.Errorf("failed to generate image build script: %w", err) + } + + return script, nil +} diff --git a/pkg/driver/k8s.utils.go b/pkg/driver/k8s.utils.go index d9da1b9..e19fcc8 100644 --- a/pkg/driver/k8s.utils.go +++ b/pkg/driver/k8s.utils.go @@ -62,6 +62,11 @@ func k8sCreateContainerID(namespace, podName, containerName string) string { return namespace + "/" + podName + "/" + containerName } +func k8sPodBuildContainerID(cid string) string { + namespace, podName, _ := k8sParseContainerID(cid) + return k8sCreateContainerID(namespace, podName, k8sBuildPodContainer) +} + func k8sPodMainContainerID(cid string) string { namespace, podName, _ := k8sParseContainerID(cid) return k8sCreateContainerID(namespace, podName, k8sMainPodContainer) @@ -257,3 +262,11 @@ func fillFileStatFromSys(modeHex uint32) os.FileMode { } return mode } + +func ensureBuildFile(file string) string { + if file != "" { + return file + } + + return "Dockerfile" +} diff --git a/pkg/driver/kubernetes.go b/pkg/driver/kubernetes.go index e0d764b..3d4014c 100644 --- a/pkg/driver/kubernetes.go +++ b/pkg/driver/kubernetes.go @@ -12,6 +12,7 @@ import ( "time" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/runtime" @@ -25,7 +26,19 @@ import ( "github.com/launchrctl/launchr/internal/launchr" ) +// RegistryLocal defines a local registry type +const RegistryLocal = "local" + +// RegistryRemote defines a remote registry type +const RegistryRemote = "remote" + +// RegistryNone defines no registry type +const RegistryNone = "none" + +var errActionWithoutImage = errors.New("action does not contain an image file") + const k8sMainPodContainer = "supervisor" +const k8sBuildPodContainer = "image-builder" const k8sUseWebsocket = true const k8sStatPathScript = ` FILE="%s" @@ -82,6 +95,9 @@ func k8sLogError(_ context.Context, err error, msg string, keysAndValues ...inte type k8sRuntime struct { config *restclient.Config clientset *kubernetes.Clientset + + imageOptions ImageOptions + crtflags RuntimeFlags } // NewKubernetesRuntime creates a kubernetes container runtime. @@ -103,6 +119,10 @@ func NewKubernetesRuntime() (ContainerRunner, error) { }, nil } +func (k *k8sRuntime) SetRuntimeFlags(f RuntimeFlags) { + k.crtflags = f +} + func (k *k8sRuntime) Info(_ context.Context) (SystemInfo, error) { return SystemInfo{ // Kubernetes is always a remote environment. @@ -207,6 +227,16 @@ func (k *k8sRuntime) ContainerCreate(ctx context.Context, opts ContainerDefiniti hostAliases := k8sHostAliases(opts) volumes, mounts := k8sVolumesAndMounts(opts) + sidecars, volumes, mounts, err := k.prepareSidecarContainers(volumes, mounts) + if err != nil { + return "", err + } + + useHostNetwork := false + if k.crtflags.RegistryType == RegistryLocal { + useHostNetwork = true + } + // Create the pod definition. pod := &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -214,10 +244,12 @@ func (k *k8sRuntime) ContainerCreate(ctx context.Context, opts ContainerDefiniti Namespace: namespace, }, Spec: corev1.PodSpec{ - HostAliases: hostAliases, - Hostname: opts.Hostname, - RestartPolicy: corev1.RestartPolicyNever, - Volumes: volumes, + HostAliases: hostAliases, + Hostname: opts.Hostname, + HostNetwork: useHostNetwork, + RestartPolicy: corev1.RestartPolicyNever, + Volumes: volumes, + InitContainers: sidecars, Containers: []corev1.Container{ { Name: k8sMainPodContainer, @@ -232,7 +264,7 @@ func (k *k8sRuntime) ContainerCreate(ctx context.Context, opts ContainerDefiniti // Create the pod launchr.Log().Debug("creating pod", "namespace", namespace, "pod", podName) - _, err := k.clientset.CoreV1(). + _, err = k.clientset.CoreV1(). Pods(namespace). Create(ctx, pod, metav1.CreateOptions{}) if err != nil { @@ -256,9 +288,35 @@ func (k *k8sRuntime) ContainerCreate(ctx context.Context, opts ContainerDefiniti return cid, err } +func (k *k8sRuntime) ImageEnsure(_ context.Context, imgOpts ImageOptions) (*ImageStatusResponse, error) { + // @todo it doesn't really work well with current implementation. + + // Store image options inside runtime. + k.imageOptions = imgOpts + + // Return nothing to silence ImageEnsure(), as real work will be done inside k.ContainerStart(). + return &ImageStatusResponse{Status: ImagePostpone}, nil +} + +func (k *k8sRuntime) ImageRemove(_ context.Context, _ string, _ ImageRemoveOptions) (*ImageRemoveResponse, error) { + // @todo it doesn't really work well with current implementation. + // additional issue here is kubernetes internal cache, additionally to registry storage. + // should we clean both of them in case of image remove? How 'no-cache' flag should behave? + return &ImageRemoveResponse{Status: ImageRemoved}, nil +} + func (k *k8sRuntime) ContainerStart(ctx context.Context, cid string, opts ContainerDefinition) (<-chan int, *ContainerInOut, error) { - // Create an ephemeral container to run. - err := k.addEphemeralContainer(ctx, cid, opts) + var err error + + // if any registry specified, build and pull an image from that registry + if k.crtflags.RegistryType != RegistryNone { + err = k.buildImage(ctx, cid, opts) + if err != nil { + return nil, nil, err + } + } + + err = k.addEphemeralContainer(ctx, cid, opts) if err != nil { return nil, nil, err } @@ -457,10 +515,15 @@ func (k *k8sRuntime) addEphemeralContainer(ctx context.Context, cid string, opts cmd := slices.Concat(opts.Entrypoint, opts.Command) + imageName := opts.Image + if k.crtflags.RegistryType != RegistryNone { + imageName = fmt.Sprintf("%s/%s", k.crtflags.RegistryURL, opts.Image) + } + ephemeralContainer := corev1.EphemeralContainer{ EphemeralContainerCommon: corev1.EphemeralContainerCommon{ Name: containerName, - Image: opts.Image, + Image: imageName, // Wrap the command into a script that will wait until a special signal USR1. // We do that to not miss any output before the attach. See ContainerStart. Command: []string{"/bin/sh", "-c", k8sWaitAttachScript, "--"}, @@ -525,3 +588,156 @@ func (k *k8sRuntime) addEphemeralContainer(ctx context.Context, cid string, opts return false, nil }) } + +func (k *k8sRuntime) prepareSidecarContainers(volumes []corev1.Volume, mounts []corev1.VolumeMount) ([]corev1.Container, []corev1.Volume, []corev1.VolumeMount, error) { + if k.crtflags.RegistryType != RegistryNone && k.crtflags.RegistryURL == "" { + return nil, nil, nil, fmt.Errorf("registry URL cannot be empty") + } + + var containers []corev1.Container + + if k.crtflags.RegistryType != RegistryNone { + sidecarPolicy := corev1.ContainerRestartPolicyAlways + + buildahInitScript, err := k.prepareBuildahInitScript() + if err != nil { + return nil, nil, nil, err + } + + buildahVolumes := []corev1.Volume{ + { + Name: "buildah-storage", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + SizeLimit: &[]resource.Quantity{resource.MustParse("2Gi")}[0], + }, + }, + }, + } + buildahMounts := []corev1.VolumeMount{ + { + Name: "buildah-storage", + MountPath: "/var/lib/containers", + }, + } + + volumes = append(volumes, buildahVolumes...) + mounts = append(mounts, buildahMounts...) + + buildahContainer := corev1.Container{ + Name: k8sBuildPodContainer, + Image: "quay.io/buildah/stable:latest", + SecurityContext: &corev1.SecurityContext{ + Privileged: &[]bool{true}[0], + RunAsUser: &[]int64{0}[0], + AllowPrivilegeEscalation: &[]bool{true}[0], + ReadOnlyRootFilesystem: &[]bool{false}[0], + Capabilities: &corev1.Capabilities{ + Add: []corev1.Capability{ + "SYS_ADMIN", "MKNOD", "SETFCAP", "SYS_CHROOT", + "SETUID", "SETGID", + }, + }, + }, + RestartPolicy: &sidecarPolicy, + Command: []string{"/bin/bash"}, + Args: []string{ + "-c", + buildahInitScript, + }, + VolumeMounts: mounts, + Env: []corev1.EnvVar{ + { + Name: "STORAGE_DRIVER", + Value: "vfs", + }, + { + Name: "BUILDAH_ISOLATION", + Value: "chroot", + }, + }, + } + containers = append(containers, buildahContainer) + } + + // @todo should we add internal type which includes registry as sidecar and builds everything inside pod? + + return containers, volumes, mounts, nil +} + +func (k *k8sRuntime) buildImage(ctx context.Context, cid string, opts ContainerDefinition) error { + notBuildable := false + bid := k8sPodBuildContainerID(cid) + exists, err := k.ensureImage(ctx, bid, opts.Image) + if err != nil { + if errors.Is(err, errActionWithoutImage) { + notBuildable = true + } else { + return err + } + } + + if !notBuildable && (!exists || k.imageOptions.ForceRebuild || k.imageOptions.NoCache) { + script, err := k.prepareBuildahWorkScript(opts.Image) + if err != nil { + return err + } + + cmdArr := []string{ + "/bin/bash", "-c", + script, + } + + var stdout bytes.Buffer + err = k.containerExec(ctx, bid, cmdArr, k8sStreams{ + out: &stdout, + opts: ContainerStreamsOptions{ + Stdout: true, + }, + }) + + launchr.Log().Debug("build output: ", "output", stdout.String()) + + if err != nil { + return fmt.Errorf("error container exec: %w, message: %s", err, stdout.String()) + } + } + + return nil +} + +func (k *k8sRuntime) ensureImage(ctx context.Context, bid, image string) (bool, error) { + nameParts := strings.Split(image, ":") + repoName := nameParts[0] + tag := "latest" + if len(nameParts) > 1 { + tag = nameParts[1] + } + + buildFile := ensureBuildFile(k.imageOptions.Build.Buildfile) + imageURL := fmt.Sprintf("%s/v2/%s/manifests/%s", k.crtflags.RegistryURL, repoName, tag) + imageCheckScript := fmt.Sprintf(buildahImageEnsureTemplate, buildFile, buildFile, imageURL) + cmdArr := []string{ + "/bin/bash", "-c", + imageCheckScript, + } + + var stdout bytes.Buffer + err := k.containerExec(ctx, bid, cmdArr, k8sStreams{ + out: &stdout, + opts: ContainerStreamsOptions{ + Stdout: true, + }, + }) + if err != nil { + return false, fmt.Errorf("error container exec: %w, message: %s", err, stdout.String()) + } + + buildFileCheck := fmt.Sprintf("%s does not exist", buildFile) + if strings.Contains(stdout.String(), buildFileCheck) { + return false, errActionWithoutImage + } + + imageExistsCheck := "image exists" + return strings.Contains(stdout.String(), imageExistsCheck), nil +} diff --git a/pkg/driver/mocks/mock.go b/pkg/driver/mocks/mock.go index 8ff6148..d2a74a5 100644 --- a/pkg/driver/mocks/mock.go +++ b/pkg/driver/mocks/mock.go @@ -246,3 +246,15 @@ func (mr *MockContainerRuntimeMockRecorder) IsSELinuxSupported(ctx any) *gomock. mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSELinuxSupported", reflect.TypeOf((*MockContainerRuntime)(nil).IsSELinuxSupported), ctx) } + +// SetRuntimeFlags mocks base method. +func (m *MockContainerRuntime) SetRuntimeFlags(flags driver.RuntimeFlags) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetRuntimeFlags", flags) +} + +// SetRuntimeFlags indicates an expected call of SetRuntimeFlags. +func (mr *MockContainerRuntimeMockRecorder) SetRuntimeFlags(flags any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRuntimeFlags", reflect.TypeOf((*MockContainerRuntime)(nil).SetRuntimeFlags), flags) +} diff --git a/pkg/driver/type.go b/pkg/driver/type.go index bbe4412..578b9fa 100644 --- a/pkg/driver/type.go +++ b/pkg/driver/type.go @@ -26,6 +26,7 @@ type ContainerRunner interface { ContainerKill(ctx context.Context, cid, signal string) error ContainerRemove(ctx context.Context, cid string) error Close() error + SetRuntimeFlags(flags RuntimeFlags) } // ContainerImageBuilder is an interface for container runtime to build images. @@ -105,6 +106,7 @@ const ( ImagePull // ImagePull - image is being pulled from the registry. ImageBuild // ImageBuild - image is being built. ImageRemoved // ImageRemoved - image was removed + ImagePostpone // ImagePostpone - image was removed ) // SystemInfo holds information about the container runner environment. @@ -166,6 +168,21 @@ type ImageRemoveResponse struct { Status ImageStatus } +// RuntimeFlags stores container runtime opts. +type RuntimeFlags struct { + IsSetRemote bool + CopyBack bool + RemoveImg bool + NoCache bool + RebuildImage bool + Entrypoint string + EntrypointSet bool + Exec bool + VolumeFlags string + RegistryURL string + RegistryType string +} + // ContainerPathStat is a type alias for container path stat result. type ContainerPathStat struct { Name string