mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-07-26 01:17:39 +00:00
Fixes https://gitea.com/gitea/runner/issues/667 Fixes https://gitea.com/gitea/runner/pulls/1103 `container.options` is parsed with docker/cli's `addFlags`, which omits the flags docker/cli registers on the `create` and `run` commands themselves. Those were rejected as unknown — most visibly `--platform`. | Flag | Behavior | Why | | --- | --- | --- | | `--platform` | overrides the runner-wide container architecture | the only way to pick an image architecture per job, e.g. across a matrix | | `--pull always\|missing\|never` | `always` forces a pull, `never` skips it | `force_pull` is runner-wide config today, with no per-job control | Both are resolved in `NewContainer` because the image pull runs before the container is created and the two have to agree. `--name`, `--quiet` and `--disable-content-trust` are now accepted and ignored, and `--use-api-socket` is rejected pointing at `container.docker_host`, so a valid `docker create` line no longer fails outright. <sub>Written by Claude (Opus 4.8).</sub> --------- Co-authored-by: bircni <bircni@icloud.com> Reviewed-on: https://gitea.com/gitea/runner/pulls/1104 Reviewed-by: bircni <bircni@icloud.com> Co-authored-by: silverwind <me@silverwind.io>
87 lines
2.9 KiB
Go
87 lines
2.9 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
|
|
|
|
package container
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"slices"
|
|
|
|
"github.com/kballard/go-shellquote"
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
const (
|
|
pullPolicyAlways = "always"
|
|
pullPolicyMissing = "missing"
|
|
pullPolicyNever = "never"
|
|
)
|
|
|
|
var pullPolicies = []string{pullPolicyAlways, pullPolicyMissing, pullPolicyNever}
|
|
|
|
// createFlags are the flags docker/cli registers on the `create` and `run` commands
|
|
// instead of in addFlags, so they are not part of containerOptions.
|
|
type createFlags struct {
|
|
platform string
|
|
pull string
|
|
name string
|
|
useAPISocket bool
|
|
}
|
|
|
|
func registerCreateFlags(flags *pflag.FlagSet) *createFlags {
|
|
cf := new(createFlags)
|
|
flags.StringVar(&cf.platform, "platform", "", "Set platform if server is multi-platform capable")
|
|
flags.StringVar(&cf.pull, "pull", pullPolicyMissing, `Pull image before creating ("always", "missing", "never")`)
|
|
flags.StringVar(&cf.name, "name", "", "Assign a name to the container")
|
|
flags.BoolVar(&cf.useAPISocket, "use-api-socket", false, "Bind mount Docker API socket and required auth")
|
|
// Accepted without effect: pull progress is only logged at debug level, and docker
|
|
// no longer implements content trust.
|
|
flags.BoolP("quiet", "q", false, "Suppress the pull output")
|
|
flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)")
|
|
return cf
|
|
}
|
|
|
|
// parseContainerOptions parses a container options string. The flags are returned even
|
|
// on error, holding whatever was read before the failure.
|
|
func parseContainerOptions(options string) (*pflag.FlagSet, *containerOptions, *createFlags, error) {
|
|
flags := pflag.NewFlagSet("container_flags", pflag.ContinueOnError)
|
|
flags.SetOutput(io.Discard)
|
|
copts := addFlags(flags)
|
|
cf := registerCreateFlags(flags)
|
|
|
|
args, err := shellquote.Split(options)
|
|
if err != nil {
|
|
return flags, copts, cf, fmt.Errorf("Cannot split container options: '%s': '%w'", options, err)
|
|
}
|
|
|
|
if err := flags.Parse(args); err != nil {
|
|
return flags, copts, cf, fmt.Errorf("Cannot parse container options: '%s': '%w'", options, err)
|
|
}
|
|
|
|
return flags, copts, cf, nil
|
|
}
|
|
|
|
// createFlagsFromOptions reads the create-level flags that have to be known before the
|
|
// container is created. Malformed options keep the defaults here and are reported by
|
|
// mergeContainerConfigs at create time.
|
|
func createFlagsFromOptions(options string) *createFlags {
|
|
_, _, cf, _ := parseContainerOptions(options)
|
|
return cf
|
|
}
|
|
|
|
func (cf *createFlags) validate() error {
|
|
if !slices.Contains(pullPolicies, cf.pull) {
|
|
return fmt.Errorf("invalid --pull option %q: must be one of %q", cf.pull, pullPolicies)
|
|
}
|
|
|
|
if cf.useAPISocket {
|
|
return errors.New("--use-api-socket is not supported, use the runner's container.docker_host setting to expose a docker socket")
|
|
}
|
|
|
|
return nil
|
|
}
|