diff options
author | Josh Patterson <josh.patterson@securityonionsolutions.com> | 2022-08-29 15:48:02 -0400 |
---|---|---|
committer | Josh Patterson <josh.patterson@securityonionsolutions.com> | 2022-08-29 15:48:02 -0400 |
commit | 0e53c8c73509e666bbb5ff4ba0ec2a8fa5c8c1b8 (patch) | |
tree | 139b60bd14d06eaf9c6c0a40d78c1e3c08404037 | |
parent | 08af95f63576af0c443fdef9d3ba6ba12a0c0dbc (diff) | |
parent | 468aa6478c73e4acd8708ce8bb0bb5a056f329c2 (diff) | |
download | podman-0e53c8c73509e666bbb5ff4ba0ec2a8fa5c8c1b8.tar.gz podman-0e53c8c73509e666bbb5ff4ba0ec2a8fa5c8c1b8.tar.bz2 podman-0e53c8c73509e666bbb5ff4ba0ec2a8fa5c8c1b8.zip |
Merge remote-tracking branch 'upstream/main' into api_compat_containers
305 files changed, 7928 insertions, 3933 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index f94ee2f3b..628b74f72 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -33,7 +33,7 @@ env: UBUNTU_NAME: "ubuntu-2204" # Image identifiers - IMAGE_SUFFIX: "c5495735033528320" + IMAGE_SUFFIX: "c5823947156488192" # EC2 images FEDORA_AMI: "fedora-aws-${IMAGE_SUFFIX}" FEDORA_AARCH64_AMI: "fedora-podman-aws-arm64-${IMAGE_SUFFIX}" @@ -431,7 +431,7 @@ alt_build_task: - env: ALT_NAME: 'Build Without CGO' - env: - ALT_NAME: 'Test build RPM' + ALT_NAME: 'Test build podman-next Copr RPM' - env: ALT_NAME: 'Alt Arch. Cross' # This task cannot make use of the shared repo.tbz artifact. @@ -681,11 +681,6 @@ podman_machine_task: # Required_pr_labels does not apply to non-PRs. # Do not run on tags, branches, [CI:BUILD], or [CI:DOCS]. only_if: *not_tag_branch_build_docs - # This task costs about $4 per attempt to execute. - # Only run it if a magic PR label is present. - # DO NOT ADD THIS TASK AS DEPENDENCY FOR `success_task` - # it will cause an infinate-block / never completing build. - required_pr_labels: test_podman_machine depends_on: - build - local_integration_test @@ -708,6 +703,31 @@ podman_machine_task: always: *int_logs_artifacts +podman_machine_aarch64_task: + name: *std_name_fmt + alias: podman_machine_aarch64 + only_if: *not_tag_branch_build_docs + depends_on: + - build_aarch64 + - validate_aarch64 + - local_integration_test + - remote_integration_test + - container_integration_test + - rootless_integration_test + ec2_instance: + <<: *standard_build_ec2_aarch64 + env: + TEST_FLAVOR: "machine" + EC2_INST_TYPE: c6g.metal + PRIV_NAME: "rootless" # intended use-case + DISTRO_NV: "${FEDORA_AARCH64_NAME}" + VM_IMAGE_NAME: "${FEDORA_AARCH64_AMI}" + clone_script: *get_gosrc_aarch64 + setup_script: *setup + main_script: *main + always: *int_logs_artifacts + + # Always run subsequent to integration tests. While parallelism is lost # with runtime, debugging system-test failures can be more challenging # for some golang developers. Otherwise the following tasks run across @@ -966,8 +986,12 @@ meta_task: ${FEDORA_CACHE_IMAGE_NAME} ${UBUNTU_CACHE_IMAGE_NAME} build-push-${IMAGE_SUFFIX} + EC2IMGNAMES: >- + ${FEDORA_AARCH64_AMI} + ${FEDORA_AMI} BUILDID: "${CIRRUS_BUILD_ID}" REPOREF: "${CIRRUS_REPO_NAME}" + AWSINI: ENCRYPTED[21b2db557171b11eb5abdbccae593f48c9caeba86dfcc4d4ff109edee9b4656ab6720a110dadfcd51e88cc59a71cc7af] GCPJSON: ENCRYPTED[3a198350077849c8df14b723c0f4c9fece9ebe6408d35982e7adf2105a33f8e0e166ed3ed614875a0887e1af2b8775f4] GCPNAME: ENCRYPTED[2f9738ef295a706f66a13891b40e8eaa92a89e0e87faf8bed66c41eca72bf76cfd190a6f2d0e8444c631fdf15ed32ef6] GCPPROJECT: libpod-218412 @@ -1003,9 +1027,8 @@ success_task: - remote_integration_test - container_integration_test - rootless_integration_test - # Label triggered task. If made automatic, remove line below - # AND bypass in contrib/cirrus/cirrus_yaml_test.py for this name. - # - podman_machine + - podman_machine + - podman_machine_aarch64 - local_system_test - local_system_test_aarch64 - remote_system_test diff --git a/.packit.sh b/.packit.sh new file mode 100644 index 000000000..7b404598a --- /dev/null +++ b/.packit.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# Packit's default fix-spec-file often doesn't fetch version string correctly. +# This script handles any custom processing of the dist-git spec file and gets used by the +# fix-spec-file action in .packit.yaml + +set -eo pipefail + +# Get Version from HEAD +HEAD_VERSION=$(grep 'var Version = semver.MustParse' version/version.go | cut -d\" -f2 | sed -e 's/-/~/') + +# Generate source tarball +git archive --prefix=podman-$HEAD_VERSION/ -o podman-$HEAD_VERSION.tar.gz HEAD + +# RPM Spec modifications + +# Fix Version +sed -i "s/^Version:.*/Version: $HEAD_VERSION/" podman.spec + +# Fix Release +sed -i "s/^Release: %autorelease/Release: $PACKIT_RPMSPEC_RELEASE%{?dist}/" podman.spec + +# Fix Source0 +sed -i "s/^Source0:.*.tar.gz/Source0: %{name}-$HEAD_VERSION.tar.gz/" podman.spec + +# Fix autosetup +sed -i "s/^%autosetup.*/%autosetup -Sgit -n %{name}-$HEAD_VERSION/" podman.spec diff --git a/.packit.yaml b/.packit.yaml new file mode 100644 index 000000000..ab284b2d5 --- /dev/null +++ b/.packit.yaml @@ -0,0 +1,20 @@ +# See the documentation for more information: +# https://packit.dev/docs/configuration/ + +upstream_package_name: podman +downstream_package_name: podman + +actions: + post-upstream-clone: + - "curl -O https://src.fedoraproject.org/rpms/podman/raw/main/f/podman.spec" + fix-spec-file: + - bash .packit.sh + +jobs: + - job: production_build + trigger: pull_request + targets: &production_dist_targets + - fedora-36 + - fedora-37 + - fedora-rawhide + scratch: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5ee0c1df..d0f4ceb02 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -97,6 +97,13 @@ You need install some dependencies before building a binary. $ export PKG_CONFIG_PATH="/usr/lib/pkgconfig" ``` +#### Debian / Ubuntu + + ```shell + $ sudo apt-get install -y libsystemd-dev libgpgme-dev libseccomp-dev + $ export PKG_CONFIG_PATH="/usr/lib/pkgconfig" + ``` + ### Building binaries and test your changes To test your changes do `make binaries` to generate your binaries. @@ -38,6 +38,7 @@ MANDIR ?= ${PREFIX}/share/man SHAREDIR_CONTAINERS ?= ${PREFIX}/share/containers ETCDIR ?= ${PREFIX}/etc TMPFILESDIR ?= ${PREFIX}/lib/tmpfiles.d +USERTMPFILESDIR ?= ${PREFIX}/share/user-tmpfiles.d MODULESLOADDIR ?= ${PREFIX}/lib/modules-load.d SYSTEMDDIR ?= ${PREFIX}/lib/systemd/system USERSYSTEMDDIR ?= ${PREFIX}/lib/systemd/user @@ -266,7 +267,7 @@ test/version/version: version/version.go .PHONY: codespell codespell: - codespell -S bin,vendor,.git,go.sum,.cirrus.yml,"RELEASE_NOTES.md,*.xz,*.gz,*.ps1,*.tar,swagger.yaml,*.tgz,bin2img,*ico,*.png,*.1,*.5,copyimg,*.orig,apidoc.go" -L pullrequest,uint,iff,od,seeked,splitted,marge,erro,hist,ether -w + codespell -S bin,vendor,.git,go.sum,.cirrus.yml,"RELEASE_NOTES.md,*.xz,*.gz,*.ps1,*.tar,swagger.yaml,*.tgz,bin2img,*ico,*.png,*.1,*.5,copyimg,*.orig,apidoc.go" -L clos,ans,pullrequest,uint,iff,od,seeked,splitted,marge,erro,hist,ether -w .PHONY: validate validate: lint .gitvalidation validate.completions man-page-check swagger-check tests-included tests-expect-exit pr-removes-fixed-skips @@ -795,8 +796,9 @@ install.completions: install.docker: install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(BINDIR) install ${SELINUXOPT} -m 755 docker $(DESTDIR)$(BINDIR)/docker - install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${USERSYSTEMDDIR} ${DESTDIR}${TMPFILESDIR} + install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${USERSYSTEMDDIR} ${DESTDIR}${TMPFILESDIR} ${DESTDIR}${USERTMPFILESDIR} install ${SELINUXOPT} -m 644 contrib/systemd/system/podman-docker.conf -t ${DESTDIR}${TMPFILESDIR} + install ${SELINUXOPT} -m 644 contrib/systemd/system/podman-docker.conf -t ${DESTDIR}${USERTMPFILESDIR} .PHONY: install.docker-docs install.docker-docs: diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b762bbbe3..8a9672507 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -11,7 +11,7 @@ - The `podman play kube` command now supports volumes with the `BlockDevice` and `CharDevice` types ([#13951](https://github.com/containers/podman/issues/13951)). - The `podman play kube` command now features a new flag, `--userns`, to set the user namespace of created pods. Two values are allowed at present: `host` and `auto` ([#7504](https://github.com/containers/podman/issues/7504)). - The `podman play kube` command now supports setting the type of created init containers via the `io.podman.annotations.init.container.type` annotation. -- Pods now have include an exit policy (configurable via the `--exit-policy` option to `podman pod create`), which determines what will happen to the pod's infra container when the entire pod stops. The default, `continue`, acts as Podman currently does, while a new option, `stop`, stops the infra container after the last container in the pod stops, and is used by default for pods from `podman play kube` ([#13464](https://github.com/containers/podman/issues/13464)). +- The `podman pod create` command now supports an exit policy (configurable via the `--exit-policy` option), which determines what will happen to the pod's infra container when the entire pod stops. The default, `continue`, acts as Podman currently does, while a new option, `stop`, stops the infra container after the last container in the pod stops. The latter is used for pods created via `podman play kube` ([#13464](https://github.com/containers/podman/issues/13464)). - The `podman pod create` command now allows the pod's name to be specified as an argument, instead of using the `--name` option - for example, `podman pod create mypod` instead of the prior `podman pod create --name mypod`. Please note that the `--name` option is not deprecated and will continue to work. - The `podman pod create` command's `--share` option now supports adding namespaces to the set by prefacing them with `+` (as opposed to specifying all namespaces that should be shared) ([#13422](https://github.com/containers/podman/issues/13422)). - The `podman pod create` command has a new option, `--shm-size`, to specify the size of the `/dev/shm` mount that will be shared if the pod shares its UTS namespace ([#14609](https://github.com/containers/podman/issues/14609)). diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 00873b95b..1e573cc2d 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -124,6 +124,14 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, "This is a Docker specific option and is a NOOP", ) + envMergeFlagName := "env-merge" + createFlags.StringArrayVar( + &cf.EnvMerge, + envMergeFlagName, []string{}, + "Preprocess environment variables from image before injecting them into the container", + ) + _ = cmd.RegisterFlagCompletionFunc(envMergeFlagName, completion.AutocompleteNone) + envFlagName := "env" createFlags.StringArrayP( envFlagName, "e", Env(), diff --git a/cmd/podman/containers/restart.go b/cmd/podman/containers/restart.go index 9d704d671..4e0e96411 100644 --- a/cmd/podman/containers/restart.go +++ b/cmd/podman/containers/restart.go @@ -3,13 +3,14 @@ package containers import ( "context" "fmt" + "io/ioutil" + "strings" "github.com/containers/common/pkg/completion" "github.com/containers/podman/v4/cmd/podman/common" "github.com/containers/podman/v4/cmd/podman/registry" "github.com/containers/podman/v4/cmd/podman/utils" "github.com/containers/podman/v4/cmd/podman/validate" - "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/spf13/cobra" ) @@ -25,7 +26,7 @@ var ( Long: restartDescription, RunE: restart, Args: func(cmd *cobra.Command, args []string) error { - return validate.CheckAllLatestAndIDFile(cmd, args, false, "") + return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile") }, ValidArgsFunction: common.AutocompleteContainers, Example: `podman restart ctrID @@ -47,20 +48,35 @@ var ( ) var ( - restartOptions = entities.RestartOptions{} - restartTimeout uint + restartOpts = entities.RestartOptions{ + Filters: make(map[string][]string), + } + restartCidFiles = []string{} + restartTimeout uint ) func restartFlags(cmd *cobra.Command) { flags := cmd.Flags() - flags.BoolVarP(&restartOptions.All, "all", "a", false, "Restart all non-running containers") - flags.BoolVar(&restartOptions.Running, "running", false, "Restart only running containers when --all is used") + flags.BoolVarP(&restartOpts.All, "all", "a", false, "Restart all non-running containers") + flags.BoolVar(&restartOpts.Running, "running", false, "Restart only running containers") + + cidfileFlagName := "cidfile" + flags.StringArrayVar(&restartCidFiles, cidfileFlagName, nil, "Read the container ID from the file") + _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) + + filterFlagName := "filter" + flags.StringSliceVarP(&filters, filterFlagName, "f", []string{}, "Filter output based on conditions given") + _ = cmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompletePsFilters) timeFlagName := "time" flags.UintVarP(&restartTimeout, timeFlagName, "t", containerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container") _ = cmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone) + if registry.IsRemote() { + _ = flags.MarkHidden("cidfile") + } + flags.SetNormalizeFunc(utils.AliasFlags) } @@ -69,39 +85,54 @@ func init() { Command: restartCommand, }) restartFlags(restartCommand) - validate.AddLatestFlag(restartCommand, &restartOptions.Latest) + validate.AddLatestFlag(restartCommand, &restartOpts.Latest) registry.Commands = append(registry.Commands, registry.CliCommand{ Command: containerRestartCommand, Parent: containerCmd, }) restartFlags(containerRestartCommand) - validate.AddLatestFlag(containerRestartCommand, &restartOptions.Latest) + validate.AddLatestFlag(containerRestartCommand, &restartOpts.Latest) } func restart(cmd *cobra.Command, args []string) error { var ( errs utils.OutputErrors ) - if len(args) < 1 && !restartOptions.Latest && !restartOptions.All { - return fmt.Errorf("you must provide at least one container name or ID: %w", define.ErrInvalidArg) + + if cmd.Flag("time").Changed { + restartOpts.Timeout = &restartTimeout } - if len(args) > 0 && restartOptions.Latest { - return fmt.Errorf("--latest and containers cannot be used together: %w", define.ErrInvalidArg) + + for _, cidFile := range restartCidFiles { + content, err := ioutil.ReadFile(cidFile) + if err != nil { + return fmt.Errorf("error reading CIDFile: %w", err) + } + id := strings.Split(string(content), "\n")[0] + args = append(args, id) } - if cmd.Flag("time").Changed { - restartOptions.Timeout = &restartTimeout + for _, f := range filters { + split := strings.SplitN(f, "=", 2) + if len(split) < 2 { + return fmt.Errorf("invalid filter %q", f) + } + restartOpts.Filters[split[0]] = append(restartOpts.Filters[split[0]], split[1]) } - responses, err := registry.ContainerEngine().ContainerRestart(context.Background(), args, restartOptions) + + responses, err := registry.ContainerEngine().ContainerRestart(context.Background(), args, restartOpts) if err != nil { return err } for _, r := range responses { - if r.Err == nil { - fmt.Println(r.Id) - } else { + switch { + case r.Err != nil: errs = append(errs, r.Err) + case r.RawInput != "": + fmt.Println(r.RawInput) + default: + fmt.Println(r.Id) } } return errs.PrintErrors() diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go index 1e3976389..9c760e752 100644 --- a/cmd/podman/containers/rm.go +++ b/cmd/podman/containers/rm.go @@ -149,7 +149,8 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit return err } for _, r := range responses { - if r.Err != nil { + switch { + case r.Err != nil: if errors.Is(r.Err, define.ErrWillDeadlock) { logrus.Errorf("Potential deadlock detected - please run 'podman system renumber' to resolve") } @@ -160,8 +161,10 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit setExitCode(r.Err) } errs = append(errs, r.Err) - } else { + case r.RawInput != "": fmt.Println(r.RawInput) + default: + fmt.Println(r.Id) } } return errs.PrintErrors() diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go index 0dd8ce80a..f29bbf34c 100644 --- a/cmd/podman/containers/stats.go +++ b/cmd/podman/containers/stats.go @@ -58,6 +58,7 @@ type statsOptionsCLI struct { var ( statsOptions statsOptionsCLI + notrunc bool ) func statFlags(cmd *cobra.Command) { @@ -69,6 +70,7 @@ func statFlags(cmd *cobra.Command) { flags.StringVar(&statsOptions.Format, formatFlagName, "", "Pretty-print container statistics to JSON or using a Go template") _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&containerStats{})) + flags.BoolVar(¬runc, "no-trunc", false, "Do not truncate output") flags.BoolVar(&statsOptions.NoReset, "no-reset", false, "Disable resetting the screen between intervals") flags.BoolVar(&statsOptions.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result, default setting is false") intervalFlagName := "interval" @@ -186,6 +188,9 @@ type containerStats struct { } func (s *containerStats) ID() string { + if notrunc { + return s.ContainerID + } return s.ContainerID[0:12] } diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go index 8211ceba5..fe9d1e9b6 100644 --- a/cmd/podman/images/pull.go +++ b/cmd/podman/images/pull.go @@ -155,6 +155,11 @@ func imagePull(cmd *cobra.Command, args []string) error { pullOptions.Username = creds.Username pullOptions.Password = creds.Password } + + if !pullOptions.Quiet { + pullOptions.Writer = os.Stderr + } + // Let's do all the remaining Yoga in the API to prevent us from // scattering logic across (too) many parts of the code. var errs utils.OutputErrors diff --git a/cmd/podman/images/push.go b/cmd/podman/images/push.go index 1734900de..fa60860db 100644 --- a/cmd/podman/images/push.go +++ b/cmd/podman/images/push.go @@ -164,6 +164,10 @@ func imagePush(cmd *cobra.Command, args []string) error { pushOptions.Password = creds.Password } + if !pushOptions.Quiet { + pushOptions.Writer = os.Stderr + } + if err := common.PrepareSigningPassphrase(&pushOptions.ImagePushOptions, pushOptions.SignPassphraseFileCLI); err != nil { return err } diff --git a/cmd/podman/images/save.go b/cmd/podman/images/save.go index 43366e1b3..ecff0f841 100644 --- a/cmd/podman/images/save.go +++ b/cmd/podman/images/save.go @@ -103,8 +103,8 @@ func save(cmd *cobra.Command, args []string) (finalErr error) { tags []string succeeded = false ) - if cmd.Flag("compress").Changed && (saveOpts.Format != define.OCIManifestDir && saveOpts.Format != define.V2s2ManifestDir) { - return errors.New("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'") + if cmd.Flag("compress").Changed && saveOpts.Format != define.V2s2ManifestDir { + return errors.New("--compress can only be set when --format is 'docker-dir'") } if len(saveOpts.Output) == 0 { saveOpts.Quiet = true diff --git a/cmd/podman/images/trust_set.go b/cmd/podman/images/trust_set.go index 832e9f724..e7339f0b1 100644 --- a/cmd/podman/images/trust_set.go +++ b/cmd/podman/images/trust_set.go @@ -53,7 +53,7 @@ File(s) must exist before using this command`) } func setTrust(cmd *cobra.Command, args []string) error { - validTrustTypes := []string{"accept", "insecureAcceptAnything", "reject", "signedBy"} + validTrustTypes := []string{"accept", "insecureAcceptAnything", "reject", "signedBy", "sigstoreSigned"} valid, err := isValidImageURI(args[0]) if err != nil || !valid { @@ -61,7 +61,7 @@ func setTrust(cmd *cobra.Command, args []string) error { } if !util.StringInSlice(setOptions.Type, validTrustTypes) { - return fmt.Errorf("invalid choice: %s (choose from 'accept', 'reject', 'signedBy')", setOptions.Type) + return fmt.Errorf("invalid choice: %s (choose from 'accept', 'reject', 'signedBy', 'sigstoreSigned')", setOptions.Type) } return registry.ImageEngine().SetTrust(registry.Context(), args, setOptions) } diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go index edddf026e..d519bc7d9 100644 --- a/cmd/podman/inspect/inspect.go +++ b/cmd/podman/inspect/inspect.go @@ -201,7 +201,7 @@ func (i *inspector) inspect(namesOrIDs []string) error { err = printJSON(data) default: // Landing here implies user has given a custom --format - row := inspectNormalize(i.options.Format) + row := inspectNormalize(i.options.Format, tmpType) row = report.NormalizeFormat(row) row = report.EnforceRange(row) err = printTmpl(tmpType, row, data) @@ -300,7 +300,7 @@ func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]inte return data, allErrs, nil } -func inspectNormalize(row string) string { +func inspectNormalize(row string, inspectType string) string { m := regexp.MustCompile(`{{\s*\.Id\s*}}`) row = m.ReplaceAllString(row, "{{.ID}}") @@ -309,5 +309,18 @@ func inspectNormalize(row string) string { ".Dst", ".Destination", ".ImageID", ".Image", ) + + // If inspect type is `image` we need to replace + // certain additional fields like `.Config.HealthCheck` + // but don't want to replace them for other inspect types. + if inspectType == common.ImageType { + r = strings.NewReplacer( + ".Src", ".Source", + ".Dst", ".Destination", + ".ImageID", ".Image", + ".Config.Healthcheck", ".HealthCheck", + ) + } + return r.Replace(row) } diff --git a/cmd/podman/kube/down.go b/cmd/podman/kube/down.go index a670d911c..792c80499 100644 --- a/cmd/podman/kube/down.go +++ b/cmd/podman/kube/down.go @@ -19,7 +19,8 @@ var ( Args: cobra.ExactArgs(1), ValidArgsFunction: common.AutocompleteDefaultOneArg, Example: `podman kube down nginx.yml - cat nginx.yml | podman kube down -`, + cat nginx.yml | podman kube down - + podman kube down https://example.com/nginx.yml`, } ) diff --git a/cmd/podman/kube/generate.go b/cmd/podman/kube/generate.go index 6df4b55fc..ee2ea51ae 100644 --- a/cmd/podman/kube/generate.go +++ b/cmd/podman/kube/generate.go @@ -22,7 +22,7 @@ var ( Whether the input is for a container or pod, Podman will always generate the specification as a pod.` - generateKubeCmd = &cobra.Command{ + kubeGenerateCmd = &cobra.Command{ Use: "generate [options] {CONTAINER...|POD...|VOLUME...}", Short: "Generate Kubernetes YAML from containers, pods or volumes.", Long: generateDescription, @@ -35,33 +35,28 @@ var ( podman kube generate volumeName podman kube generate ctrID podID volumeName --service`, } - kubeGenerateDescription = generateDescription - kubeGenerateCmd = &cobra.Command{ + generateKubeCmd = &cobra.Command{ Use: "kube [options] {CONTAINER...|POD...|VOLUME...}", - Short: "Generate Kubernetes YAML from containers, pods or volumes.", - Long: kubeGenerateDescription, - RunE: kubeGenerate, - Args: cobra.MinimumNArgs(1), - ValidArgsFunction: common.AutocompleteForGenerate, - Example: `podman kube generate ctrID - podman kube generate podID - podman kube generate --service podID - podman kube generate volumeName - podman kube generate ctrID podID volumeName --service`, + Short: kubeGenerateCmd.Short, + Long: kubeGenerateCmd.Long, + RunE: kubeGenerateCmd.RunE, + Args: kubeGenerateCmd.Args, + ValidArgsFunction: kubeGenerateCmd.ValidArgsFunction, + Example: kubeGenerateCmd.Example, } ) func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ Command: generateKubeCmd, - Parent: kubeCmd, + Parent: generate.GenerateCmd, }) generateFlags(generateKubeCmd) registry.Commands = append(registry.Commands, registry.CliCommand{ Command: kubeGenerateCmd, - Parent: generate.GenerateCmd, + Parent: kubeCmd, }) generateFlags(kubeGenerateCmd) } @@ -103,7 +98,3 @@ func generateKube(cmd *cobra.Command, args []string) error { fmt.Println(string(content)) return nil } - -func kubeGenerate(cmd *cobra.Command, args []string) error { - return generateKube(cmd, args) -} diff --git a/cmd/podman/kube/play.go b/cmd/podman/kube/play.go index d7719e28e..c846ec32c 100644 --- a/cmd/podman/kube/play.go +++ b/cmd/podman/kube/play.go @@ -5,7 +5,9 @@ import ( "errors" "fmt" "io" + "io/ioutil" "net" + "net/http" "os" "strings" @@ -13,6 +15,7 @@ import ( "github.com/containers/common/pkg/completion" "github.com/containers/image/v5/types" "github.com/containers/podman/v4/cmd/podman/common" + "github.com/containers/podman/v4/cmd/podman/parse" "github.com/containers/podman/v4/cmd/podman/registry" "github.com/containers/podman/v4/cmd/podman/utils" "github.com/containers/podman/v4/libpod/define" @@ -52,7 +55,8 @@ var ( ValidArgsFunction: common.AutocompleteDefaultOneArg, Example: `podman kube play nginx.yml cat nginx.yml | podman kube play - - podman kube play --creds user:password --seccomp-profile-root /custom/path apache.yml`, + podman kube play --creds user:password --seccomp-profile-root /custom/path apache.yml + podman kube play https://example.com/nginx.yml`, } ) @@ -67,7 +71,8 @@ var ( ValidArgsFunction: common.AutocompleteDefaultOneArg, Example: `podman play kube nginx.yml cat nginx.yml | podman play kube - - podman play kube --creds user:password --seccomp-profile-root /custom/path apache.yml`, + podman play kube --creds user:password --seccomp-profile-root /custom/path apache.yml + podman play kube https://example.com/nginx.yml`, } ) @@ -167,7 +172,7 @@ func playFlags(cmd *cobra.Command) { _ = cmd.RegisterFlagCompletionFunc(contextDirFlagName, completion.AutocompleteDefault) // NOTE: The service-container flag is marked as hidden as it - // is purely designed for running kube-play in systemd units. + // is purely designed for running kube-play or play-kube in systemd units. // It is not something users should need to know or care about. // // Having a flag rather than an env variable is cleaner. @@ -255,6 +260,7 @@ func play(cmd *cobra.Command, args []string) error { return err } } + return kubeplay(reader) } @@ -263,6 +269,7 @@ func playKube(cmd *cobra.Command, args []string) error { } func readerFromArg(fileName string) (*bytes.Reader, error) { + errURL := parse.ValidURL(fileName) if fileName == "-" { // Read from stdin data, err := io.ReadAll(os.Stdin) if err != nil { @@ -270,6 +277,19 @@ func readerFromArg(fileName string) (*bytes.Reader, error) { } return bytes.NewReader(data), nil } + if errURL == nil { + response, err := http.Get(fileName) + if err != nil { + return nil, err + } + defer response.Body.Close() + + data, err := ioutil.ReadAll(response.Body) + if err != nil { + return nil, err + } + return bytes.NewReader(data), nil + } f, err := os.Open(fileName) if err != nil { return nil, err diff --git a/cmd/podman/manifest/add.go b/cmd/podman/manifest/add.go index 35583ffcb..09a1a9a36 100644 --- a/cmd/podman/manifest/add.go +++ b/cmd/podman/manifest/add.go @@ -2,6 +2,7 @@ package manifest import ( "context" + "errors" "fmt" "github.com/containers/common/pkg/auth" @@ -20,6 +21,7 @@ type manifestAddOptsWrapper struct { entities.ManifestAddOptions TLSVerifyCLI bool // CLI only + Insecure bool // CLI only CredentialsCLI string } @@ -77,6 +79,8 @@ func init() { flags.StringVar(&manifestAddOpts.OSVersion, osVersionFlagName, "", "override the OS `version` of the specified image") _ = addCmd.RegisterFlagCompletionFunc(osVersionFlagName, completion.AutocompleteNone) + flags.BoolVar(&manifestAddOpts.Insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry") + _ = flags.MarkHidden("insecure") flags.BoolVar(&manifestAddOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") variantFlagName := "variant" @@ -89,7 +93,7 @@ func init() { } func add(cmd *cobra.Command, args []string) error { - if err := auth.CheckAuthFile(manifestPushOpts.Authfile); err != nil { + if err := auth.CheckAuthFile(manifestAddOpts.Authfile); err != nil { return err } @@ -109,6 +113,12 @@ func add(cmd *cobra.Command, args []string) error { if cmd.Flags().Changed("tls-verify") { manifestAddOpts.SkipTLSVerify = types.NewOptionalBool(!manifestAddOpts.TLSVerifyCLI) } + if cmd.Flags().Changed("insecure") { + if manifestAddOpts.SkipTLSVerify != types.OptionalBoolUndefined { + return errors.New("--insecure may not be used with --tls-verify") + } + manifestAddOpts.SkipTLSVerify = types.NewOptionalBool(manifestAddOpts.Insecure) + } listID, err := registry.ImageEngine().ManifestAdd(context.Background(), args[0], args[1:], manifestAddOpts.ManifestAddOptions) if err != nil { diff --git a/cmd/podman/manifest/create.go b/cmd/podman/manifest/create.go index 435b4a57c..2ea40d832 100644 --- a/cmd/podman/manifest/create.go +++ b/cmd/podman/manifest/create.go @@ -1,16 +1,26 @@ package manifest import ( + "errors" "fmt" + "github.com/containers/image/v5/types" "github.com/containers/podman/v4/cmd/podman/common" "github.com/containers/podman/v4/cmd/podman/registry" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/spf13/cobra" ) +// manifestCreateOptsWrapper wraps entities.ManifestCreateOptions and prevents leaking +// CLI-only fields into the API types. +type manifestCreateOptsWrapper struct { + entities.ManifestCreateOptions + + TLSVerifyCLI, Insecure bool // CLI only +} + var ( - manifestCreateOpts = entities.ManifestCreateOptions{} + manifestCreateOpts = manifestCreateOptsWrapper{} createCmd = &cobra.Command{ Use: "create [options] LIST [IMAGE...]", Short: "Create manifest list or image index", @@ -32,10 +42,28 @@ func init() { }) flags := createCmd.Flags() flags.BoolVar(&manifestCreateOpts.All, "all", false, "add all of the lists' images if the images to add are lists") + flags.BoolVarP(&manifestCreateOpts.Amend, "amend", "a", false, "modify an existing list if one with the desired name already exists") + flags.BoolVar(&manifestCreateOpts.Insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry") + _ = flags.MarkHidden("insecure") + flags.BoolVar(&manifestCreateOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") } func create(cmd *cobra.Command, args []string) error { - imageID, err := registry.ImageEngine().ManifestCreate(registry.Context(), args[0], args[1:], manifestCreateOpts) + // TLS verification in c/image is controlled via a `types.OptionalBool` + // which allows for distinguishing among set-true, set-false, unspecified + // which is important to implement a sane way of dealing with defaults of + // boolean CLI flags. + if cmd.Flags().Changed("tls-verify") { + manifestCreateOpts.SkipTLSVerify = types.NewOptionalBool(!manifestCreateOpts.TLSVerifyCLI) + } + if cmd.Flags().Changed("insecure") { + if manifestCreateOpts.SkipTLSVerify != types.OptionalBoolUndefined { + return errors.New("--insecure may not be used with --tls-verify") + } + manifestCreateOpts.SkipTLSVerify = types.NewOptionalBool(manifestCreateOpts.Insecure) + } + + imageID, err := registry.ImageEngine().ManifestCreate(registry.Context(), args[0], args[1:], manifestCreateOpts.ManifestCreateOptions) if err != nil { return err } diff --git a/cmd/podman/manifest/push.go b/cmd/podman/manifest/push.go index 756ed2a74..c8893ff2e 100644 --- a/cmd/podman/manifest/push.go +++ b/cmd/podman/manifest/push.go @@ -1,8 +1,10 @@ package manifest import ( + "errors" "fmt" "io/ioutil" + "os" "github.com/containers/common/pkg/auth" "github.com/containers/common/pkg/completion" @@ -20,9 +22,9 @@ import ( type manifestPushOptsWrapper struct { entities.ImagePushOptions - TLSVerifyCLI bool // CLI only - CredentialsCLI string - SignPassphraseFileCLI string + TLSVerifyCLI, Insecure bool // CLI only + CredentialsCLI string + SignPassphraseFileCLI string } var ( @@ -82,6 +84,8 @@ func init() { _ = pushCmd.RegisterFlagCompletionFunc(signPassphraseFileFlagName, completion.AutocompleteDefault) flags.BoolVar(&manifestPushOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") + flags.BoolVar(&manifestPushOpts.Insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry") + _ = flags.MarkHidden("insecure") flags.BoolVarP(&manifestPushOpts.Quiet, "quiet", "q", false, "don't output progress information when pushing lists") flags.SetNormalizeFunc(utils.AliasFlags) @@ -119,6 +123,10 @@ func push(cmd *cobra.Command, args []string) error { manifestPushOpts.Password = creds.Password } + if !manifestPushOpts.Quiet { + manifestPushOpts.Writer = os.Stderr + } + if err := common.PrepareSigningPassphrase(&manifestPushOpts.ImagePushOptions, manifestPushOpts.SignPassphraseFileCLI); err != nil { return err } @@ -130,6 +138,12 @@ func push(cmd *cobra.Command, args []string) error { if cmd.Flags().Changed("tls-verify") { manifestPushOpts.SkipTLSVerify = types.NewOptionalBool(!manifestPushOpts.TLSVerifyCLI) } + if cmd.Flags().Changed("insecure") { + if manifestPushOpts.SkipTLSVerify != types.OptionalBoolUndefined { + return errors.New("--insecure may not be used with --tls-verify") + } + manifestPushOpts.SkipTLSVerify = types.NewOptionalBool(manifestPushOpts.Insecure) + } digest, err := registry.ImageEngine().ManifestPush(registry.Context(), args[0], args[1], manifestPushOpts.ImagePushOptions) if err != nil { return err diff --git a/cmd/podman/parse/net.go b/cmd/podman/parse/net.go index 9228c7127..a5c7a0d95 100644 --- a/cmd/podman/parse/net.go +++ b/cmd/podman/parse/net.go @@ -151,15 +151,6 @@ func parseEnvOrLabelFile(envOrLabel map[string]string, filename, configType stri return scanner.Err() } -// ValidateFileName returns an error if filename contains ":" -// as it is currently not supported -func ValidateFileName(filename string) error { - if strings.Contains(filename, ":") { - return fmt.Errorf("invalid filename (should not contain ':') %q", filename) - } - return nil -} - // ValidURL checks a string urlStr is a url or not func ValidURL(urlStr string) error { url, err := url.ParseRequestURI(urlStr) diff --git a/cmd/podman/parse/parse.go b/cmd/podman/parse/parse.go new file mode 100644 index 000000000..47db066d3 --- /dev/null +++ b/cmd/podman/parse/parse.go @@ -0,0 +1,18 @@ +//go:build !windows +// +build !windows + +package parse + +import ( + "fmt" + "strings" +) + +// ValidateFileName returns an error if filename contains ":" +// as it is currently not supported +func ValidateFileName(filename string) error { + if strings.Contains(filename, ":") { + return fmt.Errorf("invalid filename (should not contain ':') %q", filename) + } + return nil +} diff --git a/cmd/podman/parse/parse_windows.go b/cmd/podman/parse/parse_windows.go new file mode 100644 index 000000000..794f4216d --- /dev/null +++ b/cmd/podman/parse/parse_windows.go @@ -0,0 +1,5 @@ +package parse + +func ValidateFileName(filename string) error { + return nil +} diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go index cae618b44..a118fdc4d 100644 --- a/cmd/podman/registry/config.go +++ b/cmd/podman/registry/config.go @@ -61,7 +61,7 @@ func newPodmanConfig() { switch runtime.GOOS { case "darwin", "windows": mode = entities.TunnelMode - case "linux": + case "linux", "freebsd": // Some linux clients might only be compiled without ABI // support (e.g., podman-remote). if abiSupport && !IsRemote() { diff --git a/cmd/podman/secrets/create.go b/cmd/podman/secrets/create.go index 8ecfecf69..01775f563 100644 --- a/cmd/podman/secrets/create.go +++ b/cmd/podman/secrets/create.go @@ -46,7 +46,7 @@ func init() { cfg := registry.PodmanConfig() - flags.StringVar(&createOpts.Driver, driverFlagName, cfg.Secrets.Driver, "Specify secret driver") + flags.StringVarP(&createOpts.Driver, driverFlagName, "d", cfg.Secrets.Driver, "Specify secret driver") flags.StringToStringVar(&createOpts.DriverOpts, optsFlagName, cfg.Secrets.Opts, "Specify driver specific options") _ = createCmd.RegisterFlagCompletionFunc(driverFlagName, completion.AutocompleteNone) _ = createCmd.RegisterFlagCompletionFunc(optsFlagName, completion.AutocompleteNone) diff --git a/cmd/podman/secrets/inspect.go b/cmd/podman/secrets/inspect.go index 1fcc676b4..c99e555ba 100644 --- a/cmd/podman/secrets/inspect.go +++ b/cmd/podman/secrets/inspect.go @@ -34,7 +34,7 @@ func init() { }) flags := inspectCmd.Flags() formatFlagName := "format" - flags.StringVar(&format, formatFlagName, "", "Format volume output using Go template") + flags.StringVarP(&format, formatFlagName, "f", "", "Format volume output using Go template") _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.SecretInfoReport{})) } diff --git a/cmd/podman/secrets/list.go b/cmd/podman/secrets/list.go index 8b1956eab..afa9b8887 100644 --- a/cmd/podman/secrets/list.go +++ b/cmd/podman/secrets/list.go @@ -34,6 +34,7 @@ type listFlagType struct { format string noHeading bool filter []string + quiet bool } func init() { @@ -43,13 +44,20 @@ func init() { }) flags := lsCmd.Flags() + formatFlagName := "format" flags.StringVar(&listFlag.format, formatFlagName, "{{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}\t\n", "Format volume output using Go template") _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.SecretInfoReport{})) + filterFlagName := "filter" flags.StringSliceVarP(&listFlag.filter, filterFlagName, "f", []string{}, "Filter secret output") _ = lsCmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteSecretFilters) - flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers") + + noHeadingFlagName := "noheading" + flags.BoolVar(&listFlag.noHeading, noHeadingFlagName, false, "Do not print headers") + + quietFlagName := "quiet" + flags.BoolVarP(&listFlag.quiet, quietFlagName, "q", false, "Print secret IDs only") } func ls(cmd *cobra.Command, args []string) error { @@ -76,9 +84,21 @@ func ls(cmd *cobra.Command, args []string) error { Driver: response.Spec.Driver.Name, }) } + + if listFlag.quiet && !cmd.Flags().Changed("format") { + return quietOut(listed) + } + return outputTemplate(cmd, listed) } +func quietOut(responses []*entities.SecretListReport) error { + for _, response := range responses { + fmt.Println(response.ID) + } + return nil +} + func outputTemplate(cmd *cobra.Command, responses []*entities.SecretListReport) error { headers := report.Headers(entities.SecretListReport{}, map[string]string{ "CreatedAt": "CREATED", diff --git a/cmd/podman/syslog_linux.go b/cmd/podman/syslog_common.go index ac7bbfe0f..e035e6365 100644 --- a/cmd/podman/syslog_linux.go +++ b/cmd/podman/syslog_common.go @@ -1,3 +1,6 @@ +//go:build linux || freebsd +// +build linux freebsd + package main import ( diff --git a/cmd/podman/syslog_unsupported.go b/cmd/podman/syslog_unsupported.go index 42a7851ab..365e5b2b4 100644 --- a/cmd/podman/syslog_unsupported.go +++ b/cmd/podman/syslog_unsupported.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build !linux && !freebsd +// +build !linux,!freebsd package main diff --git a/cmd/podman/system/service_abi.go b/cmd/podman/system/service_abi.go index 8d0240a8d..68ac8902b 100644 --- a/cmd/podman/system/service_abi.go +++ b/cmd/podman/system/service_abi.go @@ -105,7 +105,9 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities } if err := utils.MaybeMoveToSubCgroup(); err != nil { - return err + // it is a best effort operation, so just print the + // error for debugging purposes. + logrus.Debugf("Could not move to subcgroup: %v", err) } servicereaper.Start() diff --git a/cmd/rootlessport/main.go b/cmd/rootlessport/main.go index 5410cd14a..d8d6ffcee 100644 --- a/cmd/rootlessport/main.go +++ b/cmd/rootlessport/main.go @@ -225,7 +225,7 @@ outer: // https://github.com/containers/podman/issues/11248 // Copy /dev/null to stdout and stderr to prevent SIGPIPE errors - if f, err := os.OpenFile("/dev/null", os.O_WRONLY, 0755); err == nil { + if f, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0755); err == nil { unix.Dup2(int(f.Fd()), 1) //nolint:errcheck unix.Dup2(int(f.Fd()), 2) //nolint:errcheck f.Close() diff --git a/contrib/cirrus/cirrus_yaml_test.py b/contrib/cirrus/cirrus_yaml_test.py index 3968b8b1b..a7fff8d3f 100755 --- a/contrib/cirrus/cirrus_yaml_test.py +++ b/contrib/cirrus/cirrus_yaml_test.py @@ -26,7 +26,7 @@ class TestCaseBase(unittest.TestCase): class TestDependsOn(TestCaseBase): ALL_TASK_NAMES = None - SUCCESS_DEPS_EXCLUDE = set(['success', 'artifacts', 'podman_machine', + SUCCESS_DEPS_EXCLUDE = set(['success', 'artifacts', 'test_image_build', 'release', 'release_test']) def setUp(self): diff --git a/contrib/pkginstaller/Makefile b/contrib/pkginstaller/Makefile index c84a08482..b7636fe14 100644 --- a/contrib/pkginstaller/Makefile +++ b/contrib/pkginstaller/Makefile @@ -1,7 +1,6 @@ SHELL := bash ARCH ?= aarch64 -PODMAN_VERSION ?= 4.1.0 GVPROXY_VERSION ?= 0.4.0 QEMU_VERSION ?= 7.0.0-2 GVPROXY_RELEASE_URL ?= https://github.com/containers/gvisor-tap-vsock/releases/download/v$(GVPROXY_VERSION)/gvproxy-darwin @@ -13,6 +12,9 @@ PKG_NAME := podman-installer-macos-$(ARCH).pkg default: pkginstaller +podman_version: + make -C ../../ test/version/version + $(TMP_DOWNLOAD)/gvproxy: mkdir -p $(TMP_DOWNLOAD) cd $(TMP_DOWNLOAD) && curl -sLo gvproxy $(GVPROXY_RELEASE_URL) @@ -21,7 +23,7 @@ $(TMP_DOWNLOAD)/podman-machine-qemu-$(ARCH)-$(QEMU_VERSION).tar.xz: mkdir -p $(TMP_DOWNLOAD) cd $(TMP_DOWNLOAD) && curl -sLO $(QEMU_RELEASE_URL) -packagedir: package_root Distribution welcome.html +packagedir: podman_version package_root Distribution welcome.html mkdir -p $(PACKAGE_DIR) cp -r Resources $(PACKAGE_DIR)/ cp welcome.html $(PACKAGE_DIR)/Resources/ @@ -30,7 +32,7 @@ packagedir: package_root Distribution welcome.html cp -r $(PACKAGE_ROOT) $(PACKAGE_DIR)/ cp package.sh $(PACKAGE_DIR)/ cd $(PACKAGE_DIR) && pkgbuild --analyze --root ./root component.plist - echo -n $(PODMAN_VERSION) > $(PACKAGE_DIR)/VERSION + ../../test/version/version > $(PACKAGE_DIR)/VERSION echo -n $(ARCH) > $(PACKAGE_DIR)/ARCH cp ../../LICENSE $(PACKAGE_DIR)/Resources/LICENSE.txt cp hvf.entitlements $(PACKAGE_DIR)/ @@ -41,8 +43,8 @@ package_root: clean-pkgroot $(TMP_DOWNLOAD)/podman-machine-qemu-$(ARCH)-$(QEMU_V cp $(TMP_DOWNLOAD)/gvproxy $(PACKAGE_ROOT)/podman/bin/ chmod a+x $(PACKAGE_ROOT)/podman/bin/* -%: %.in - @sed -e 's/__VERSION__/'$(PODMAN_VERSION)'/g' $< >$@ +%: %.in podman_version + @sed -e 's/__VERSION__/'$(shell ../../test/version/version)'/g' $< >$@ pkginstaller: packagedir cd $(PACKAGE_DIR) && ./package.sh .. @@ -55,7 +57,7 @@ notarize: _notarize .PHONY: clean clean-pkgroot clean: - rm -rf $(TMP_DOWNLOAD) $(PACKAGE_ROOT) $(PACKAGE_DIR) Distribution welcome.html + rm -rf $(TMP_DOWNLOAD) $(PACKAGE_ROOT) $(PACKAGE_DIR) Distribution welcome.html ../../test/version/version clean-pkgroot: rm -rf $(PACKAGE_ROOT) $(PACKAGE_DIR) Distribution welcome.html diff --git a/contrib/systemd/system/podman-docker.conf b/contrib/systemd/system/podman-docker.conf index e12f19bce..9d5f43101 100644 --- a/contrib/systemd/system/podman-docker.conf +++ b/contrib/systemd/system/podman-docker.conf @@ -1 +1 @@ -L+ /run/docker.sock - - - - /run/podman/podman.sock +L+ %t/docker.sock - - - - %t/podman/podman.sock diff --git a/docs/source/markdown/.gitignore b/docs/source/markdown/.gitignore index 6689b5b71..8a0d553ba 100644 --- a/docs/source/markdown/.gitignore +++ b/docs/source/markdown/.gitignore @@ -1,8 +1,28 @@ +podman-auto-update.1.md podman-build.1.md podman-container-clone.1.md +podman-container-runlabel.1.md podman-create.1.md +podman-exec.1.md +podman-image-sign.1.md +podman-kill.1.md podman-kube-play.1.md +podman-login.1.md +podman-logout.1.md +podman-logs.1.md +podman-manifest-add.1.md +podman-manifest-push.1.md +podman-pause.1.md podman-pod-clone.1.md podman-pod-create.1.md +podman-pod-logs.1.md +podman-pod-rm.1.md +podman-pod-start.1.md +podman-pod-stop.1.md podman-pull.1.md +podman-push.1.md +podman-rm.1.md podman-run.1.md +podman-search.1.md +podman-stop.1.md +podman-unpause.1.md diff --git a/docs/source/markdown/options/annotation.container.md b/docs/source/markdown/options/annotation.container.md index bd561a15f..0d155e5e4 100644 --- a/docs/source/markdown/options/annotation.container.md +++ b/docs/source/markdown/options/annotation.container.md @@ -1,3 +1,3 @@ #### **--annotation**=*key=value* -Add an annotation to the container<| or pod>. This option can be set multiple times. +Add an annotation to the container<<| or pod>>. This option can be set multiple times. diff --git a/docs/source/markdown/options/arch.md b/docs/source/markdown/options/arch.md index 005197707..76fb349a0 100644 --- a/docs/source/markdown/options/arch.md +++ b/docs/source/markdown/options/arch.md @@ -1,2 +1,3 @@ #### **--arch**=*ARCH* Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. +Unless overridden, subsequent lookups of the same image in the local storage will match this architecture, regardless of the host. diff --git a/docs/source/markdown/options/authfile.md b/docs/source/markdown/options/authfile.md new file mode 100644 index 000000000..d6198aa24 --- /dev/null +++ b/docs/source/markdown/options/authfile.md @@ -0,0 +1,6 @@ +#### **--authfile**=*path* + +Path of the authentication file. Default is `${XDG_RUNTIME_DIR}/containers/auth.json`, which is set using **[podman login](podman-login.1.md)**. +If the authorization state is not found there, `$HOME/.docker/config.json` is checked, which is set using **docker login**. + +Note: There is also the option to override the default path of the authentication file by setting the `REGISTRY_AUTH_FILE` environment variable. This can be done with **export REGISTRY_AUTH_FILE=_path_**. diff --git a/docs/source/markdown/options/blkio-weight.md b/docs/source/markdown/options/blkio-weight.md index eb8e94144..04a1071c0 100644 --- a/docs/source/markdown/options/blkio-weight.md +++ b/docs/source/markdown/options/blkio-weight.md @@ -1,3 +1,5 @@ #### **--blkio-weight**=*weight* Block IO relative weight. The _weight_ is a value between **10** and **1000**. + +This option is not supported on cgroups V1 rootless systems. diff --git a/docs/source/markdown/options/cert-dir.md b/docs/source/markdown/options/cert-dir.md new file mode 100644 index 000000000..4d05075cf --- /dev/null +++ b/docs/source/markdown/options/cert-dir.md @@ -0,0 +1,5 @@ +#### **--cert-dir**=*path* + +Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) +Please refer to **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)** for details. +(This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) diff --git a/docs/source/markdown/options/cidfile.read.md b/docs/source/markdown/options/cidfile.read.md new file mode 100644 index 000000000..414700fca --- /dev/null +++ b/docs/source/markdown/options/cidfile.read.md @@ -0,0 +1,4 @@ +#### **--cidfile**=*file* + +Read container ID from the specified *file* and <<subcommand>> the container. +Can be specified multiple times. diff --git a/docs/source/markdown/options/cidfile.write.md b/docs/source/markdown/options/cidfile.write.md new file mode 100644 index 000000000..b5e7435b2 --- /dev/null +++ b/docs/source/markdown/options/cidfile.write.md @@ -0,0 +1,3 @@ +#### **--cidfile**=*file* + +Write the container ID to *file*. diff --git a/docs/source/markdown/options/color.md b/docs/source/markdown/options/color.md new file mode 100644 index 000000000..343c79c88 --- /dev/null +++ b/docs/source/markdown/options/color.md @@ -0,0 +1,3 @@ +#### **--color** + +Output the containers with different colors in the log. diff --git a/docs/source/markdown/options/cpu-period.md b/docs/source/markdown/options/cpu-period.md index 8df6445e9..5c5eb56e7 100644 --- a/docs/source/markdown/options/cpu-period.md +++ b/docs/source/markdown/options/cpu-period.md @@ -5,6 +5,8 @@ duration in microseconds. Once the container's CPU quota is used up, it will not be scheduled to run until the current period ends. Defaults to 100000 microseconds. -On some systems, changing the CPU limits may not be allowed for non-root +On some systems, changing the resource limits may not be allowed for non-root users. For more details, see -https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error +https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-resource-limits-fails-with-a-permissions-error + +This option is not supported on cgroups V1 rootless systems. diff --git a/docs/source/markdown/options/cpu-quota.md b/docs/source/markdown/options/cpu-quota.md index 67b9dee8c..81d5db3d2 100644 --- a/docs/source/markdown/options/cpu-quota.md +++ b/docs/source/markdown/options/cpu-quota.md @@ -7,6 +7,8 @@ CPU resource. The limit is a number in microseconds. If a number is provided, the container will be allowed to use that much CPU time until the CPU period ends (controllable via **--cpu-period**). -On some systems, changing the CPU limits may not be allowed for non-root +On some systems, changing the resource limits may not be allowed for non-root users. For more details, see -https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error +https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-resource-limits-fails-with-a-permissions-error + +This option is not supported on cgroups V1 rootless systems. diff --git a/docs/source/markdown/options/cpu-rt-period.md b/docs/source/markdown/options/cpu-rt-period.md index 9014beb33..36e88632e 100644 --- a/docs/source/markdown/options/cpu-rt-period.md +++ b/docs/source/markdown/options/cpu-rt-period.md @@ -4,4 +4,4 @@ Limit the CPU real-time period in microseconds. Limit the container's Real Time CPU usage. This option tells the kernel to restrict the container's Real Time CPU usage to the period specified. -This option is not supported on cgroups V2 systems. +This option is only supported on cgroups V1 rootful systems. diff --git a/docs/source/markdown/options/cpu-rt-runtime.md b/docs/source/markdown/options/cpu-rt-runtime.md index 05b1d3b96..64f0ec38b 100644 --- a/docs/source/markdown/options/cpu-rt-runtime.md +++ b/docs/source/markdown/options/cpu-rt-runtime.md @@ -7,4 +7,4 @@ Period of 1,000,000us and Runtime of 950,000us means that this container could c The sum of all runtimes across containers cannot exceed the amount allotted to the parent cgroup. -This option is not supported on cgroups V2 systems. +This option is only supported on cgroups V1 rootful systems. diff --git a/docs/source/markdown/options/cpu-shares.md b/docs/source/markdown/options/cpu-shares.md index a5aacd2ca..c0e2c3035 100644 --- a/docs/source/markdown/options/cpu-shares.md +++ b/docs/source/markdown/options/cpu-shares.md @@ -33,3 +33,9 @@ this can result in the following division of CPU shares: | 100 | C0 | 0 | 100% of CPU0 | | 101 | C1 | 1 | 100% of CPU1 | | 102 | C1 | 2 | 100% of CPU2 | + +On some systems, changing the resource limits may not be allowed for non-root +users. For more details, see +https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-resource-limits-fails-with-a-permissions-error + +This option is not supported on cgroups V1 rootless systems. diff --git a/docs/source/markdown/options/cpus.container.md b/docs/source/markdown/options/cpus.container.md new file mode 100644 index 000000000..63f243e11 --- /dev/null +++ b/docs/source/markdown/options/cpus.container.md @@ -0,0 +1,11 @@ +#### **--cpus**=*number* + +Number of CPUs. The default is *0.0* which means no limit. This is shorthand +for **--cpu-period** and **--cpu-quota**, so you may only set either +**--cpus** or **--cpu-period** and **--cpu-quota**. + +On some systems, changing the CPU limits may not be allowed for non-root +users. For more details, see +https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-resource-limits-fails-with-a-permissions-error + +This option is not supported on cgroups V1 rootless systems. diff --git a/docs/source/markdown/options/cpuset-cpus.md b/docs/source/markdown/options/cpuset-cpus.md index d717516a0..8a2a82e9f 100644 --- a/docs/source/markdown/options/cpuset-cpus.md +++ b/docs/source/markdown/options/cpuset-cpus.md @@ -3,3 +3,9 @@ CPUs in which to allow execution. Can be specified as a comma-separated list (e.g. **0,1**), as a range (e.g. **0-3**), or any combination thereof (e.g. **0-3,7,11-15**). + +On some systems, changing the resource limits may not be allowed for non-root +users. For more details, see +https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-resource-limits-fails-with-a-permissions-error + +This option is not supported on cgroups V1 rootless systems. diff --git a/docs/source/markdown/options/cpuset-mems.md b/docs/source/markdown/options/cpuset-mems.md index d2d13eb54..b86d0ef6b 100644 --- a/docs/source/markdown/options/cpuset-mems.md +++ b/docs/source/markdown/options/cpuset-mems.md @@ -6,3 +6,9 @@ NUMA systems. If there are four memory nodes on the system (0-3), use **--cpuset-mems=0,1** then processes in the container will only use memory from the first two memory nodes. + +On some systems, changing the resource limits may not be allowed for non-root +users. For more details, see +https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-resource-limits-fails-with-a-permissions-error + +This option is not supported on cgroups V1 rootless systems. diff --git a/docs/source/markdown/options/creds.md b/docs/source/markdown/options/creds.md new file mode 100644 index 000000000..23399dda4 --- /dev/null +++ b/docs/source/markdown/options/creds.md @@ -0,0 +1,5 @@ +#### **--creds**=*[username[:password]]* + +The [username[:password]] to use to authenticate with the registry if required. +If one or both values are not supplied, a command line prompt will appear and the +value can be entered. The password is entered without echo. diff --git a/docs/source/markdown/options/device-cgroup-rule.md b/docs/source/markdown/options/device-cgroup-rule.md new file mode 100644 index 000000000..0ba3d4668 --- /dev/null +++ b/docs/source/markdown/options/device-cgroup-rule.md @@ -0,0 +1,6 @@ +#### **--device-cgroup-rule**=*"type major:minor mode"* + +Add a rule to the cgroup allowed devices list. The rule is expected to be in the format specified in the Linux kernel documentation (Documentation/cgroup-v1/devices.txt): + - type: a (all), c (char), or b (block); + - major and minor: either a number, or * for all; + - mode: a composition of r (read), w (write), and m (mknod(2)). diff --git a/docs/source/markdown/options/disable-content-trust.md b/docs/source/markdown/options/disable-content-trust.md new file mode 100644 index 000000000..a2d1d8ad7 --- /dev/null +++ b/docs/source/markdown/options/disable-content-trust.md @@ -0,0 +1,5 @@ +#### **--disable-content-trust** + +This is a Docker-specific option to disable image verification to a container +registry and is not supported by Podman. This option is a NOOP and provided +solely for scripting compatibility. diff --git a/docs/source/markdown/options/dns-opt.container.md b/docs/source/markdown/options/dns-opt.container.md new file mode 100644 index 000000000..ea26fd013 --- /dev/null +++ b/docs/source/markdown/options/dns-opt.container.md @@ -0,0 +1,3 @@ +#### **--dns-opt**=*option* + +Set custom DNS options. Invalid if using **--dns-opt** with **--network** that is set to **none** or **container:**_id_. diff --git a/docs/source/markdown/options/dns-search.container.md b/docs/source/markdown/options/dns-search.container.md new file mode 100644 index 000000000..5a803ba39 --- /dev/null +++ b/docs/source/markdown/options/dns-search.container.md @@ -0,0 +1,4 @@ +#### **--dns-search**=*domain* + +Set custom DNS search domains. Invalid if using **--dns-search** with **--network** that is set to **none** or **container:**_id_. +Use **--dns-search=.** if you don't wish to set the search domain. diff --git a/docs/source/markdown/options/env-merge.md b/docs/source/markdown/options/env-merge.md new file mode 100644 index 000000000..aa1aa003d --- /dev/null +++ b/docs/source/markdown/options/env-merge.md @@ -0,0 +1,5 @@ +#### **--env-merge**=*env* + +Preprocess default environment variables for the containers. For example +if image contains environment variable `hello=world` user can preprocess +it using `--env-merge hello=${hello}-some` so new value will be `hello=world-some`. diff --git a/docs/source/markdown/options/follow.md b/docs/source/markdown/options/follow.md new file mode 100644 index 000000000..75b65cf49 --- /dev/null +++ b/docs/source/markdown/options/follow.md @@ -0,0 +1,7 @@ +#### **--follow**, **-f** + +Follow log output. Default is false. + +Note: If you are following a <<container|pod>> which is removed by `podman <<container|pod>> rm` +or removed on exit (`podman run --rm ...`), then there is a chance that the log +file will be removed before `podman<< pod|>> logs` reads the final content. diff --git a/docs/source/markdown/options/gidmap.container.md b/docs/source/markdown/options/gidmap.container.md new file mode 100644 index 000000000..a3c9df33d --- /dev/null +++ b/docs/source/markdown/options/gidmap.container.md @@ -0,0 +1,8 @@ +#### **--gidmap**=*container_gid:host_gid:amount* + +Run the container in a new user namespace using the supplied GID mapping. This +option conflicts with the **--userns** and **--subgidname** options. This +option provides a way to map host GIDs to container GIDs in the same way as +__--uidmap__ maps host UIDs to container UIDs. For details see __--uidmap__. + +Note: the **--gidmap** flag cannot be called in conjunction with the **--pod** flag as a gidmap cannot be set on the container level when in a pod. diff --git a/docs/source/markdown/options/gidmap.pod.md b/docs/source/markdown/options/gidmap.pod.md new file mode 100644 index 000000000..0d58cc527 --- /dev/null +++ b/docs/source/markdown/options/gidmap.pod.md @@ -0,0 +1,4 @@ +#### **--gidmap**=*pod_gid:host_gid:amount* + +GID map for the user namespace. Using this flag will run all containers in the pod with user namespace enabled. +It conflicts with the **--userns** and **--subgidname** flags. diff --git a/docs/source/markdown/options/ignore.md b/docs/source/markdown/options/ignore.md new file mode 100644 index 000000000..231d75957 --- /dev/null +++ b/docs/source/markdown/options/ignore.md @@ -0,0 +1,5 @@ +#### **--ignore**, **-i** + +Ignore errors when specified <<containers|pods>> are not in the container store. A user +might have decided to manually remove a <<container|pod>> which would lead to a failure +during the ExecStop directive of a systemd service referencing that <<container|pod>>. diff --git a/docs/source/markdown/options/ipc.md b/docs/source/markdown/options/ipc.md new file mode 100644 index 000000000..699b64eec --- /dev/null +++ b/docs/source/markdown/options/ipc.md @@ -0,0 +1,12 @@ +#### **--ipc**=*ipc* + +Set the IPC namespace mode for a container. The default is to create +a private IPC namespace. + +- "": Use Podman's default, defined in containers.conf. +- **container:**_id_: reuses another container's shared memory, semaphores, and message queues +- **host**: use the host's shared memory, semaphores, and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. +- **none**: private IPC namespace, with /dev/shm not mounted. +- **ns:**_path_: path to an IPC namespace to join. +- **private**: private IPC namespace. += **shareable**: private IPC namespace with a possibility to share it with other containers. diff --git a/docs/source/markdown/options/memory-swappiness.md b/docs/source/markdown/options/memory-swappiness.md index 65f0ef310..1e6a51188 100644 --- a/docs/source/markdown/options/memory-swappiness.md +++ b/docs/source/markdown/options/memory-swappiness.md @@ -2,4 +2,4 @@ Tune a container's memory swappiness behavior. Accepts an integer between *0* and *100*. -This flag is not supported on cgroups V2 systems. +This flag is only supported on cgroups V1 rootful systems. diff --git a/docs/source/markdown/options/names.md b/docs/source/markdown/options/names.md new file mode 100644 index 000000000..54fda40ee --- /dev/null +++ b/docs/source/markdown/options/names.md @@ -0,0 +1,3 @@ +#### **--names**, **-n** + +Output the container names instead of the container IDs in the log. diff --git a/docs/source/markdown/options/pid.md b/docs/source/markdown/options/pid.md new file mode 100644 index 000000000..d0cbef1d5 --- /dev/null +++ b/docs/source/markdown/options/pid.md @@ -0,0 +1,9 @@ +#### **--pid**=*mode* + +Set the PID namespace mode for the container. +The default is to create a private PID namespace for the container. + +- **container:**_id_: join another container's PID namespace; +- **host**: use the host's PID namespace for the container. Note the host mode gives the container full access to local PID and is therefore considered insecure; +- **ns:**_path_: join the specified PID namespace; +- **private**: create a new namespace for the container (default). diff --git a/docs/source/markdown/options/platform.md b/docs/source/markdown/options/platform.md index edfa428ff..b66efdfb2 100644 --- a/docs/source/markdown/options/platform.md +++ b/docs/source/markdown/options/platform.md @@ -2,3 +2,4 @@ Specify the platform for selecting the image. (Conflicts with --arch and --os) The `--platform` option can be used to override the current architecture and operating system. +Unless overridden, subsequent lookups of the same image in the local storage will match this platform, regardless of the host. diff --git a/docs/source/markdown/options/pod-id-file.container.md b/docs/source/markdown/options/pod-id-file.container.md new file mode 100644 index 000000000..1c102dc6b --- /dev/null +++ b/docs/source/markdown/options/pod-id-file.container.md @@ -0,0 +1,4 @@ +#### **--pod-id-file**=*file* + +Run container in an existing pod and read the pod's ID from the specified *file*. +If a container is run within a pod, and the pod has an infra-container, the infra-container will be started before the container is. diff --git a/docs/source/markdown/options/pod-id-file.pod.md b/docs/source/markdown/options/pod-id-file.pod.md new file mode 100644 index 000000000..69e2ac6e9 --- /dev/null +++ b/docs/source/markdown/options/pod-id-file.pod.md @@ -0,0 +1,3 @@ +#### **--pod-id-file**=*file* + +Read pod ID from the specified *file* and <<subcommand>> the pod. Can be specified multiple times. diff --git a/docs/source/markdown/options/since.md b/docs/source/markdown/options/since.md new file mode 100644 index 000000000..9f20722df --- /dev/null +++ b/docs/source/markdown/options/since.md @@ -0,0 +1,6 @@ +#### **--since**=*TIMESTAMP* + +Show logs since TIMESTAMP. The --since option can be Unix timestamps, date formatted timestamps, or Go duration +strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Supported formats for date formatted +time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00, +and 2006-01-02. diff --git a/docs/source/markdown/options/systemd.md b/docs/source/markdown/options/systemd.md new file mode 100644 index 000000000..a341edbc2 --- /dev/null +++ b/docs/source/markdown/options/systemd.md @@ -0,0 +1,29 @@ +#### **--systemd**=*true* | *false* | *always* + +Run container in systemd mode. The default is **true**. + +The value *always* enforces the systemd mode is enforced without +looking at the executable name. Otherwise, if set to true and the +command you are running inside the container is **systemd**, **/usr/sbin/init**, +**/sbin/init** or **/usr/local/sbin/init**. + +Running the container in systemd mode causes the following changes: + +* Podman mounts tmpfs file systems on the following directories + * _/run_ + * _/run/lock_ + * _/tmp_ + * _/sys/fs/cgroup/systemd_ + * _/var/lib/journal_ +* Podman sets the default stop signal to **SIGRTMIN+3**. +* Podman sets **container_uuid** environment variable in the container to the +first 32 characters of the container id. + +This allows systemd to run in a confined container without any modifications. + +Note that on **SELinux** systems, systemd attempts to write to the cgroup +file system. Containers writing to the cgroup file system are denied by default. +The **container_manage_cgroup** boolean must be enabled for this to be allowed on an SELinux separated system. +``` +setsebool -P container_manage_cgroup true +``` diff --git a/docs/source/markdown/options/tail.md b/docs/source/markdown/options/tail.md new file mode 100644 index 000000000..463b6fc3f --- /dev/null +++ b/docs/source/markdown/options/tail.md @@ -0,0 +1,4 @@ +#### **--tail**=*LINES* + +Output the specified number of LINES at the end of the logs. LINES must be an integer. Defaults to -1, +which prints all lines diff --git a/docs/source/markdown/options/timestamps.md b/docs/source/markdown/options/timestamps.md new file mode 100644 index 000000000..a449216aa --- /dev/null +++ b/docs/source/markdown/options/timestamps.md @@ -0,0 +1,3 @@ +#### **--timestamps**, **-t** + +Show timestamps in the log outputs. The default is false diff --git a/docs/source/markdown/options/until.md b/docs/source/markdown/options/until.md new file mode 100644 index 000000000..d656d976b --- /dev/null +++ b/docs/source/markdown/options/until.md @@ -0,0 +1,6 @@ +#### **--until**=*TIMESTAMP* + +Show logs until TIMESTAMP. The --until option can be Unix timestamps, date formatted timestamps, or Go duration +strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Supported formats for date formatted +time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00, +and 2006-01-02. diff --git a/docs/source/markdown/options/workdir.md b/docs/source/markdown/options/workdir.md new file mode 100644 index 000000000..12f3ddd44 --- /dev/null +++ b/docs/source/markdown/options/workdir.md @@ -0,0 +1,7 @@ +#### **--workdir**, **-w**=*dir* + +Working directory inside the container. + +The default working directory for running binaries within a container is the root directory (**/**). +The image developer can set a different default with the WORKDIR instruction. The operator +can override the working directory by using the **-w** option. diff --git a/docs/source/markdown/podman-auto-update.1.md b/docs/source/markdown/podman-auto-update.1.md.in index 992c87432..bc92d6165 100644 --- a/docs/source/markdown/podman-auto-update.1.md +++ b/docs/source/markdown/podman-auto-update.1.md.in @@ -34,12 +34,8 @@ Systemd units that start and stop a container cannot run a new image. Podman ships with a `podman-auto-update.service` systemd unit. This unit is triggered daily at midnight by the `podman-auto-update.timer` systemd timer. The timer can be altered for custom time-based updates if desired. The unit can further be invoked by other systemd units (e.g., via the dependency tree) or manually via **systemctl start podman-auto-update.service**. ## OPTIONS -#### **--authfile**=*path* -Path of the authentication file. Default is `${XDG_RUNTIME_DIR}/containers/auth.json`, which is set using **[podman login](podman-login.1.md)**. -If the authorization state is not found there, `$HOME/.docker/config.json` is checked, which is set using **docker login**. - -Note: There is also the option to override the default path of the authentication file by setting the `REGISTRY_AUTH_FILE` environment variable. This can be done with **export REGISTRY_AUTH_FILE=_path_**. +@@option authfile #### **--dry-run** diff --git a/docs/source/markdown/podman-build.1.md.in b/docs/source/markdown/podman-build.1.md.in index c0cf08f3c..693e0d3b9 100644 --- a/docs/source/markdown/podman-build.1.md.in +++ b/docs/source/markdown/podman-build.1.md.in @@ -65,19 +65,11 @@ discarded when writing images in Docker formats. Set the architecture of the image to be built, and that of the base image to be pulled, if the build uses one, to the provided value instead of using the -architecture of the build host. (Examples: arm, arm64, 386, amd64, ppc64le, -s390x) +architecture of the build host. Unless overridden, subsequent lookups of the +same image in the local storage will match this architecture, regardless of the +host. (Examples: arm, arm64, 386, amd64, ppc64le, s390x) -#### **--authfile**=*path* - -Path of the authentication file. Default is -${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. -If the authorization state is not found there, $HOME/.docker/config.json is -checked, which is set using `docker login`. - -Note: You can also override the default path of the authentication file by -setting the REGISTRY\_AUTH\_FILE environment variable. -`export REGISTRY_AUTH_FILE=path` +@@option authfile #### **--build-arg**=*arg=value* @@ -173,10 +165,7 @@ If a capability is specified to both the **--cap-add** and **--cap-drop** options, it will be dropped, regardless of the order in which the options were given. -#### **--cert-dir**=*path* - -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) +@@option cert-dir @@option cgroup-parent @@ -207,11 +196,7 @@ Set additional flags to pass to the C Preprocessor cpp(1). Containerfiles ending @@option cpuset-mems -#### **--creds**=*creds* - -The [username[:password]] to use to authenticate with the registry if required. -If one or both values are not supplied, a command line prompt will appear and -the value can be entered. The password is entered without echo. +@@option creds #### **--decryption-key**=*key[:passphrase]* @@ -245,11 +230,7 @@ registries, and images being written to local storage would only need to be decompressed again to be stored. Compression can be forced in all cases by specifying **--disable-compression=false**. -#### **--disable-content-trust** - -This is a Docker specific option to disable image verification to a container -registry and is not supported by Podman. This option is a NOOP and provided -solely for scripting compatibility. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) +@@option disable-content-trust #### **--dns**=*dns* @@ -312,6 +293,12 @@ environment variable. `export BUILDAH_FORMAT=docker` Overrides the first `FROM` instruction within the Containerfile. If there are multiple FROM instructions in a Containerfile, only the first is changed. +With the remote podman client, not all container transports will work as +expected. For example, oci-archive:/x.tar will reference /x.tar on the remote +machine instead of on the client. If you need to support remote podman clients, +it is best to restrict yourself to containers-storage: and docker:// +transports. + #### **--help**, **-h** Print usage statement @@ -463,7 +450,8 @@ do not include `History` information in their images. Set the OS of the image to be built, and that of the base image to be pulled, if the build uses one, instead of using the current operating system of the -build host. +build host. Unless overridden, subsequent lookups of the same image in the +local storage will match this OS, regardless of the host. #### **--os-feature**=*feature* @@ -515,9 +503,12 @@ process. Set the *os/arch* of the built image (and its base image, if your build uses one) to the provided value instead of using the current operating system and -architecture of the host (for example `linux/arm`). If `--platform` is set, -then the values of the `--arch`, `--os`, and `--variant` options will be -overridden. +architecture of the host (for example `linux/arm`). Unless overridden, +subsequent lookups of the same image in the local storage will match this +platform, regardless of the host. + +If `--platform` is set, then the values of the `--arch`, `--os`, and +`--variant` options will be overridden. The `--platform` option can be specified more than once, or given a comma-separated list of values as its argument. When more than one platform is diff --git a/docs/source/markdown/podman-container-clone.1.md.in b/docs/source/markdown/podman-container-clone.1.md.in index cf760d7a2..26f414b62 100644 --- a/docs/source/markdown/podman-container-clone.1.md.in +++ b/docs/source/markdown/podman-container-clone.1.md.in @@ -40,6 +40,8 @@ Set a number of CPUs for the container that overrides the original containers CP This is shorthand for **--cpu-period** and **--cpu-quota**, so only **--cpus** or either both the **--cpu-period** and **--cpu-quota** options can be set. +This option is not supported on cgroups V1 rootless systems. + @@option cpuset-cpus If none are specified, the original container's CPUset is used. @@ -54,10 +56,14 @@ If none are specified, the original container's CPU memory nodes are used. Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb). +This option is not supported on cgroups V1 rootless systems. + #### **--device-write-bps**=*path* Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb) +This option is not supported on cgroups V1 rootless systems. + #### **--force**, **-f** Force removal of the original container that we are cloning. Can only be used in conjunction with **--destroy**. @@ -74,6 +80,8 @@ system's page size (the value would be very large, that's millions of trillions) If no memory limits are specified, the original container's will be used. +This option is not supported on cgroups V1 rootless systems. + #### **--memory-reservation**=*limit* Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes)) @@ -84,6 +92,8 @@ reservation. So you should always set the value below **--memory**, otherwise th hard limit will take precedence. By default, memory reservation will be the same as memory limit from the container being cloned. +This option is not supported on cgroups V1 rootless systems. + #### **--memory-swap**=*limit* A limit value equal to memory plus swap. Must be used with the **-m** @@ -95,6 +105,8 @@ The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes), `k` (kibibytes), `m` (mebibytes), or `g` (gibibytes). If you don't specify a unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap. +This option is not supported on cgroups V1 rootless systems. + @@option memory-swappiness #### **--name** diff --git a/docs/source/markdown/podman-container-runlabel.1.md b/docs/source/markdown/podman-container-runlabel.1.md.in index 40e5392ce..f5fb8ca60 100644 --- a/docs/source/markdown/podman-container-runlabel.1.md +++ b/docs/source/markdown/podman-container-runlabel.1.md.in @@ -29,20 +29,12 @@ As specified by the `--name` option. The format is identical to the one of the Will be replaced with the current working directory. ## OPTIONS -#### **--authfile**=*path* -Path of the containers-auth.json(5) file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. +@@option authfile -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` +@@option cert-dir -#### **--cert-dir**=*path* - -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) - -#### **--creds**=*[username[:password]]* - -The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. +@@option creds #### **--display** diff --git a/docs/source/markdown/podman-create.1.md.in b/docs/source/markdown/podman-create.1.md.in index f5301c60a..0a880951d 100644 --- a/docs/source/markdown/podman-create.1.md.in +++ b/docs/source/markdown/podman-create.1.md.in @@ -83,12 +83,7 @@ error. It can even pretend to be a TTY (this is what most command line executables expect) and pass along signals. The **-a** option can be set for each of stdin, stdout, and stderr. -#### **--authfile**=*path* - -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json - -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` +@@option authfile @@option blkio-weight @@ -110,9 +105,7 @@ Block IO relative device weight. @@option chrootdirs -#### **--cidfile**=*id* - -Write the container ID to the file +@@option cidfile.write @@option conmon-pidfile @@ -126,15 +119,7 @@ Write the container ID to the file @@option cpu-shares -#### **--cpus**=*number* - -Number of CPUs. The default is *0.0* which means no limit. This is shorthand -for **--cpu-period** and **--cpu-quota**, so you may only set either -**--cpus** or **--cpu-period** and **--cpu-quota**. - -On some systems, changing the CPU limits may not be allowed for non-root -users. For more details, see -https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error +@@option cpus.container @@option cpuset-cpus @@ -159,34 +144,33 @@ Podman may load kernel modules required for using the specified device. The devices that podman will load modules when necessary are: /dev/fuse. -#### **--device-cgroup-rule**=*"type major:minor mode"* - -Add a rule to the cgroup allowed devices list. The rule is expected to be in the format specified in the Linux kernel documentation (Documentation/cgroup-v1/devices.txt): - - type: a (all), c (char), or b (block); - - major and minor: either a number, or * for all; - - mode: a composition of r (read), w (write), and m (mknod(2)). +@@option device-cgroup-rule #### **--device-read-bps**=*path* Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb) +This option is not supported on cgroups V1 rootless systems. + #### **--device-read-iops**=*path* Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000) +This option is not supported on cgroups V1 rootless systems. + #### **--device-write-bps**=*path* Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb) +This option is not supported on cgroups V1 rootless systems. + #### **--device-write-iops**=*path* Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000) -#### **--disable-content-trust** +This option is not supported on cgroups V1 rootless systems. -This is a Docker specific option to disable image verification to a Docker -registry and is not supported by Podman. This flag is a NOOP and provided -solely for scripting compatibility. +@@option disable-content-trust #### **--dns**=*dns* @@ -200,13 +184,9 @@ is the case the **--dns** flag is necessary for every run. The special value **none** can be specified to disable creation of **/etc/resolv.conf** in the container by Podman. The **/etc/resolv.conf** file in the image will be used without changes. -#### **--dns-opt**=*option* - -Set custom DNS options. Invalid if using **--dns-opt** and **--network** that is set to 'none' or `container:<name|id>`. +@@option dns-opt.container -#### **--dns-search**=*domain* - -Set custom DNS search domains. Invalid if using **--dns-search** and **--network** that is set to 'none' or `container:<name|id>`. (Use --dns-search=. if you don't wish to set the search domain) +@@option dns-search.container @@option entrypoint @@ -224,16 +204,11 @@ Read in a line delimited file of environment variables. See **Environment** note @@option env-host -@@option expose +@@option env-merge -#### **--gidmap**=*container_gid:host_gid:amount* - -Run the container in a new user namespace using the supplied GID mapping. This -option conflicts with the **--userns** and **--subgidname** options. This -option provides a way to map host GIDs to container GIDs in the same way as -__--uidmap__ maps host UIDs to container UIDs. For details see __--uidmap__. +@@option expose -Note: the **--gidmap** flag cannot be called in conjunction with the **--pod** flag as a gidmap cannot be set on the container level when in a pod. +@@option gidmap.container @@option group-add @@ -319,18 +294,7 @@ The address must be within the network's IPv6 address pool. To specify multiple static IPv6 addresses per container, set multiple networks using the **--network** option with a static IPv6 address specified for each using the `ip6` mode for that option. -#### **--ipc**=*ipc* - -Set the IPC namespace mode for a container. The default is to create -a private IPC namespace. - -- "": Use Podman's default, defined in containers.conf. -- **container:**_id_: reuses another container's shared memory, semaphores, and message queues -- **host**: use the host's shared memory, semaphores, and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. -- **none**: private IPC namespace, with /dev/shm not mounted. -- **ns:**_path_: path to an IPC namespace to join. -- **private**: private IPC namespace. -= **shareable**: private IPC namespace with a possibility to share it with other containers. +@@option ipc #### **--label**, **-l**=*label* @@ -371,6 +335,8 @@ RAM. If a limit of 0 is specified (not using **-m**), the container's memory is not limited. The actual limit may be rounded up to a multiple of the operating system's page size (the value would be very large, that's millions of trillions). +This option is not supported on cgroups V1 rootless systems. + #### **--memory-reservation**=*limit* Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes)) @@ -381,6 +347,8 @@ reservation. So you should always set the value below **--memory**, otherwise th hard limit will take precedence. By default, memory reservation will be the same as memory limit. +This option is not supported on cgroups V1 rootless systems. + #### **--memory-swap**=*limit* A limit value equal to memory plus swap. Must be used with the **-m** @@ -392,6 +360,8 @@ The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes), `k` (kibibytes), `m` (mebibytes), or `g` (gibibytes). If you don't specify a unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap. +This option is not supported on cgroups V1 rootless systems. + @@option memory-swappiness @@option mount @@ -457,19 +427,13 @@ This option conflicts with **--add-host**. #### **--os**=*OS* Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. +Unless overridden, subsequent lookups of the same image in the local storage will match this OS, regardless of the host. @@option passwd-entry @@option personality -#### **--pid**=*pid* - -Set the PID mode for the container -Default is to create a private PID namespace for the container -- `container:<name|id>`: join another container's PID namespace -- `host`: use the host's PID namespace for the container. Note: the host mode gives the container full access to local PID and is therefore considered insecure. -- `ns`: join the specified PID namespace -- `private`: create a new namespace for the container (default) +@@option pid @@option pidfile @@ -482,9 +446,7 @@ Default is to create a private PID namespace for the container Run container in an existing pod. If you want Podman to make the pod for you, preference the pod name with `new:`. To make a pod with more granular options, use the `podman pod create` command before creating a container. -#### **--pod-id-file**=*path* - -Run container in an existing pod and read the pod's ID from the specified file. If a container is run within a pod, and the pod has an infra-container, the infra-container will be started before the container is. +@@option pod-id-file.container #### **--privileged** @@ -666,34 +628,7 @@ Network Namespace - current sysctls allowed: Note: if you use the --network=host option these sysctls will not be allowed. -#### **--systemd**=*true* | *false* | *always* - -Run container in systemd mode. The default is *true*. - -The value *always* enforces the systemd mode is enforced without -looking at the executable name. Otherwise, if set to true and the -command you are running inside the container is **systemd**, **/usr/sbin/init**, -**/sbin/init** or **/usr/local/sbin/init**. - -Running the container in systemd mode causes the following changes: - -* Podman mounts tmpfs file systems on the following directories - * _/run_ - * _/run/lock_ - * _/tmp_ - * _/sys/fs/cgroup/systemd_ - * _/var/lib/journal_ -* Podman sets the default stop signal to **SIGRTMIN+3**. -* Podman sets **container_uuid** environment variable in the container to the -first 32 characters of the container id. - -This allows systemd to run in a confined container without any modifications. - -Note: On `SELinux` systems, systemd attempts to write to the cgroup -file system. Containers writing to the cgroup file system are denied by default. -The `container_manage_cgroup` boolean must be enabled for this to be allowed on an SELinux separated system. - -`setsebool -P container_manage_cgroup true` +@@option systemd @@option timeout @@ -986,13 +921,7 @@ If the location of the volume from the source container overlaps with data residing on a target container, then the volume hides that data on the target. -#### **--workdir**, **-w**=*dir* - -Working directory inside the container - -The default working directory for running binaries within a container is the root directory (/). -The image developer can set a different default with the WORKDIR instruction. The operator -can override the working directory by using the **-w** option. +@@option workdir ## EXAMPLES diff --git a/docs/source/markdown/podman-exec.1.md b/docs/source/markdown/podman-exec.1.md.in index da61f3456..4f78f1c31 100644 --- a/docs/source/markdown/podman-exec.1.md +++ b/docs/source/markdown/podman-exec.1.md.in @@ -70,13 +70,7 @@ Sets the username or UID used and optionally the groupname or GID for the specif The following examples are all valid: --user [user | user:group | uid | uid:gid | user:gid | uid:group ] -#### **--workdir**, **-w**=*path* - -Working directory inside the container - -The default working directory for running binaries within a container is the root directory (/). -The image developer can set a different default with the WORKDIR instruction, which can be overridden -when creating the container. +@@option workdir ## Exit Status diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md index fc2ce171e..88dff2a45 100644 --- a/docs/source/markdown/podman-generate-systemd.1.md +++ b/docs/source/markdown/podman-generate-systemd.1.md @@ -26,7 +26,7 @@ therefore the overridden default value._ A Kubernetes YAML can be executed in systemd via the `podman-kube@.service` systemd template. The template's argument is the path to the YAML file. Given a `workload.yaml` file in the home directory, it can be executed as follows: ``` -$ escaped=$(systemd-escape ~/sysadmin.yaml) +$ escaped=$(systemd-escape ~/workload.yaml) $ systemctl --user start podman-kube@$escaped.service $ systemctl --user is-active podman-kube@$escaped.service active diff --git a/docs/source/markdown/podman-image-sign.1.md b/docs/source/markdown/podman-image-sign.1.md.in index 035e10743..d5efabc1a 100644 --- a/docs/source/markdown/podman-image-sign.1.md +++ b/docs/source/markdown/podman-image-sign.1.md.in @@ -19,17 +19,9 @@ By default, the signature will be written into `/var/lib/containers/sigstore` fo Sign all the manifests of the multi-architecture image (default false). -#### **--authfile**=*path* +@@option authfile -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json - -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` - -#### **--cert-dir**=*path* - -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) +@@option cert-dir #### **--directory**, **-d**=*dir* diff --git a/docs/source/markdown/podman-image-trust.1.md b/docs/source/markdown/podman-image-trust.1.md index 4e80bdcf5..2a7da82cc 100644 --- a/docs/source/markdown/podman-image-trust.1.md +++ b/docs/source/markdown/podman-image-trust.1.md @@ -32,7 +32,8 @@ Trust **type** provides a way to: Allowlist ("accept") or Denylist ("reject") registries or -Require signature (“signedBy”). +Require a simple signing signature (“signedBy”), +Require a sigstore signature ("sigstoreSigned"). Trust may be updated using the command **podman image trust set** for an existing trust scope. @@ -45,12 +46,14 @@ Trust may be updated using the command **podman image trust set** for an existin #### **--pubkeysfile**, **-f**=*KEY1* A path to an exported public key on the local system. Key paths will be referenced in policy.json. Any path to a file may be used but locating the file in **/etc/pki/containers** is recommended. Options may be used multiple times to - require an image be signed by multiple keys. The **--pubkeysfile** option is required for the **signedBy** type. + require an image be signed by multiple keys. The **--pubkeysfile** option is required for the **signedBy** and **sigstoreSigned** types. #### **--type**, **-t**=*value* The trust type for this policy entry. Accepted values: - **signedBy** (default): Require signatures with corresponding list of + **signedBy** (default): Require simple signing signatures with corresponding list of + public keys + **sigstoreSigned**: Require sigstore signatures with corresponding list of public keys **accept**: do not require any signatures for this registry scope diff --git a/docs/source/markdown/podman-kill.1.md b/docs/source/markdown/podman-kill.1.md.in index a4f80ac81..2788cc694 100644 --- a/docs/source/markdown/podman-kill.1.md +++ b/docs/source/markdown/podman-kill.1.md.in @@ -16,9 +16,7 @@ The main process inside each container specified will be sent SIGKILL, or any si Signal all running and paused containers. -#### **--cidfile** - -Read container ID from the specified file and remove the container. Can be specified multiple times. +@@option cidfile.read #### **--latest**, **-l** diff --git a/docs/source/markdown/podman-kube-down.1.md b/docs/source/markdown/podman-kube-down.1.md index 92abd4ba3..c345abbd1 100644 --- a/docs/source/markdown/podman-kube-down.1.md +++ b/docs/source/markdown/podman-kube-down.1.md @@ -4,10 +4,14 @@ podman-kube-down - Remove containers and pods based on Kubernetes YAML ## SYNOPSIS -**podman kube down** *file.yml|-* +**podman kube down** *file.yml|-|https://website.io/file.yml* ## DESCRIPTION -**podman kube down** reads a specified Kubernetes YAML file, tearing down pods that were created by the `podman kube play` command via the same Kubernetes YAML file. Any volumes that were created by the previous `podman kube play` command remain intact. If the YAML file is specified as `-`, `podman kube down` reads the YAML from stdin. +**podman kube down** reads a specified Kubernetes YAML file, tearing down pods that were created by the `podman kube play` command via the same Kubernetes YAML +file. Any volumes that were created by the previous `podman kube play` command remain intact. If the YAML file is specified as `-`, `podman kube down` reads the +YAML from stdin. The input can also be a URL that points to a YAML file such as https://podman.io/demo.yml. `podman kube down` will then teardown the pods and +containers created by `podman kube play` via the same Kubernetes YAML from the URL. However, `podman kube down` will not work with a URL if the YAML file the URL +points to has been changed or altered since the creation of the pods and containers using `podman kube play`. ## EXAMPLES @@ -30,14 +34,31 @@ spec: Remove the pod and containers as described in the `demo.yml` file ``` $ podman kube down demo.yml +Pods stopped: +52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 +Pods removed: 52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 ``` -Remove the pod and containers as described in the`demo.yml` file YAML sent to stdin +Remove the pod and containers as described in the `demo.yml` file YAML sent to stdin ``` $ cat demo.yml | podman kube play - +Pods stopped: +52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 +Pods removed: +52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 +``` + +Remove the pods and containers as described in the `demo.yml` file YAML read from a URL +``` +$ podman kube down https://podman.io/demo.yml +Pods stopped: +52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 +Pods removed: 52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 ``` +`podman kube down` will not work with a URL if the YAML file the URL points to has been changed +or altered since it was used to create the pods and containers. ## SEE ALSO **[podman(1)](podman.1.md)**, **[podman-kube(1)](podman-kube.1.md)**, **[podman-kube-play(1)](podman-kube-play.1.md)**, **[podman-kube-generate(1)](podman-kube-generate.1.md)**, **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)** diff --git a/docs/source/markdown/podman-kube-play.1.md.in b/docs/source/markdown/podman-kube-play.1.md.in index 5fc183ee2..f0b404057 100644 --- a/docs/source/markdown/podman-kube-play.1.md.in +++ b/docs/source/markdown/podman-kube-play.1.md.in @@ -4,13 +4,14 @@ podman-kube-play - Create containers, pods and volumes based on Kubernetes YAML ## SYNOPSIS -**podman kube play** [*options*] *file.yml|-* +**podman kube play** [*options*] *file.yml|-|https://website.io/file.yml* ## DESCRIPTION **podman kube play** will read in a structured file of Kubernetes YAML. It will then recreate the containers, pods or volumes described in the YAML. Containers within a pod are then started and the ID of the new Pod or the name of the new Volume is output. If the yaml file is specified as "-" then `podman kube play` will read the YAML file from stdin. Using the `--down` command line option, it is also capable of tearing down the pods created by a previous run of `podman kube play`. Using the `--replace` command line option, it will tear down the pods(if any) created by a previous run of `podman kube play` and recreate the pods with the Kubernetes YAML file. Ideally the input file would be one created by Podman (see podman-kube-generate(1)). This would guarantee a smooth import and expected results. +The input can also be a URL that points to a YAML file such as https://podman.io/demo.yml. `podman kube play` will read the YAML from the URL and create pods and containers from it. Currently, the supported Kubernetes kinds are: - Pod @@ -112,22 +113,13 @@ and as a result environment variable `FOO` will be set to `bar` for container `c @@option annotation.container -#### **--authfile**=*path* - -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. -If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. - -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` +@@option authfile #### **--build** Build images even if they are found in the local storage. Use `--build=false` to completely disable builds. (This option is not available with the remote Podman client) -#### **--cert-dir**=*path* - -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) +@@option cert-dir #### **--configmap**=*path* @@ -139,11 +131,7 @@ Note: The *--configmap* option can be used multiple times or a comma-separated l Use *path* as the build context directory for each image. Requires --build option be true. (This option is not available with the remote Podman client) -#### **--creds** - -The [username[:password]] to use to authenticate with the registry if required. -If one or both values are not supplied, a command line prompt will appear and the -value can be entered. The password is entered without echo. +@@option creds #### **--help**, **-h** @@ -313,8 +301,23 @@ Create a pod connected to two networks (called net1 and net2) with a static ip $ podman kube play demo.yml --network net1:ip=10.89.1.5 --network net2:ip=10.89.10.10 52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 ``` - Please take into account that networks must be created first using podman-network-create(1). +Create and teardown from a URL pointing to a YAML file +``` +$ podman kube play https://podman.io/demo.yml +52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 + +$ podman kube play --down https://podman.io/demo.yml +Pods stopped: +52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 +Pods removed: +52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 +``` +`podman kube play --down` will not work with a URL if the YAML file the URL points to +has been changed or altered. + + + ## SEE ALSO **[podman(1)](podman.1.md)**, **[podman-kube(1)](podman-kube.1.md)**, **[podman-kube-down(1)](podman-kube-down.1.md)**, **[podman-network-create(1)](podman-network-create.1.md)**, **[podman-kube-generate(1)](podman-kube-generate.1.md)**, **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)** diff --git a/docs/source/markdown/podman-login.1.md b/docs/source/markdown/podman-login.1.md.in index c84b0cc99..4537988eb 100644 --- a/docs/source/markdown/podman-login.1.md +++ b/docs/source/markdown/podman-login.1.md.in @@ -28,17 +28,9 @@ For more details about format and configurations of the auth.json file, please r ## OPTIONS -#### **--authfile**=*path* +@@option authfile -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json. - -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` - -#### **--cert-dir**=*path* - -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) +@@option cert-dir #### **--get-login** diff --git a/docs/source/markdown/podman-logout.1.md b/docs/source/markdown/podman-logout.1.md.in index 96ac98f35..6997bb36e 100644 --- a/docs/source/markdown/podman-logout.1.md +++ b/docs/source/markdown/podman-logout.1.md.in @@ -25,12 +25,7 @@ All the cached credentials can be removed by setting the **all** flag. Remove the cached credentials for all registries in the auth file -#### **--authfile**=*path* - -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json. - -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` +@@option authfile #### **--help**, **-h** diff --git a/docs/source/markdown/podman-logs.1.md b/docs/source/markdown/podman-logs.1.md.in index 6ce6c3812..7b0c45cf0 100644 --- a/docs/source/markdown/podman-logs.1.md +++ b/docs/source/markdown/podman-logs.1.md.in @@ -15,49 +15,24 @@ any logs at the time you execute podman logs). ## OPTIONS -#### **--color** +@@option color -Output the containers with different colors in the log. - -#### **--follow**, **-f** - -Follow log output. Default is false. - -Note: If you are following a container which is removed `podman container rm` -or removed on exit `podman run --rm ...`, then there is a chance that the log -file will be removed before `podman logs` reads the final content. +@@option follow #### **--latest**, **-l** Instead of providing the container name or ID, use the last created container. If you use methods other than Podman to run containers such as CRI-O, the last started container could be from either of those methods. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) -#### **--names**, **-n** - -Output the container name in the log - -#### **--since**=*TIMESTAMP* - -Show logs since TIMESTAMP. The --since option can be Unix timestamps, date formatted timestamps, or Go duration -strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Supported formats for date formatted -time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00, -and 2006-01-02. - -#### **--tail**=*LINES* - -Output the specified number of LINES at the end of the logs. LINES must be an integer. Defaults to -1, -which prints all lines +@@option names -#### **--timestamps**, **-t** +@@option since -Show timestamps in the log outputs. The default is false +@@option tail -#### **--until**=*TIMESTAMP* +@@option timestamps -Show logs until TIMESTAMP. The --until option can be Unix timestamps, date formatted timestamps, or Go duration -strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Supported formats for date formatted -time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00, -and 2006-01-02. +@@option until ## EXAMPLE diff --git a/docs/source/markdown/podman-manifest-add.1.md b/docs/source/markdown/podman-manifest-add.1.md.in index 5aa7f8341..e82c04985 100644 --- a/docs/source/markdown/podman-manifest-add.1.md +++ b/docs/source/markdown/podman-manifest-add.1.md.in @@ -33,24 +33,11 @@ the image. If *imageName* refers to a manifest list or image index, the architecture information will be retrieved from it. Otherwise, it will be retrieved from the image's configuration information. -#### **--authfile**=*path* +@@option authfile -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. -If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. +@@option cert-dir -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` - -#### **--cert-dir**=*path* - -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) - -#### **--creds**=*creds* - -The [username[:password]] to use to authenticate with the registry if required. -If one or both values are not supplied, a command line prompt will appear and the -value can be entered. The password is entered without echo. +@@option creds #### **--features** diff --git a/docs/source/markdown/podman-manifest-create.1.md b/docs/source/markdown/podman-manifest-create.1.md index 77a4b9db6..06a24da2b 100644 --- a/docs/source/markdown/podman-manifest-create.1.md +++ b/docs/source/markdown/podman-manifest-create.1.md @@ -22,11 +22,23 @@ If any of the images which should be added to the new list or index are themselves lists or indexes, add all of their contents. By default, only one image from such a list will be added to the newly-created list or index. +#### **--amend**, **-a** + +If a manifest list named *listnameorindexname* already exists, modify the +preexisting list instead of exiting with an error. The contents of +*listnameorindexname* are not modified if no *imagename*s are given. + +#### **--tls-verify** + +Require HTTPS and verify certificates when talking to container registries. (defaults to true) + ## EXAMPLES ``` podman manifest create mylist:v1.11 9cfd24048d5fc80903f088f1531a21bff01172abe66effa8941a4c2308dc745f +podman manifest create --amend mylist:v1.11 +9cfd24048d5fc80903f088f1531a21bff01172abe66effa8941a4c2308dc745f ``` ``` diff --git a/docs/source/markdown/podman-manifest-push.1.md b/docs/source/markdown/podman-manifest-push.1.md.in index cfe2b9230..88d070c3f 100644 --- a/docs/source/markdown/podman-manifest-push.1.md +++ b/docs/source/markdown/podman-manifest-push.1.md.in @@ -19,28 +19,15 @@ The list image's ID and the digest of the image's manifest. Push the images mentioned in the manifest list or image index, in addition to the list or index itself. (Default true) -#### **--authfile**=*path* +@@option authfile -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. -If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. - -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` - -#### **--cert-dir**=*path* - -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) +@@option cert-dir #### **--compression-format**=**gzip** | *zstd* | *zstd:chunked* Specifies the compression format to use. Supported values are: `gzip`, `zstd` and `zstd:chunked`. The default is `gzip` unless overridden in the containers.conf file. -#### **--creds**=*creds* - -The [username[:password]] to use to authenticate with the registry if required. -If one or both values are not supplied, a command line prompt will appear and the -value can be entered. The password is entered without echo. +@@option creds #### **--digestfile**=*Digestfile* diff --git a/docs/source/markdown/podman-pause.1.md b/docs/source/markdown/podman-pause.1.md.in index f374d96f3..af308f034 100644 --- a/docs/source/markdown/podman-pause.1.md +++ b/docs/source/markdown/podman-pause.1.md.in @@ -17,9 +17,7 @@ Pauses all the processes in one or more containers. You may use container IDs o Pause all running containers. -#### **--cidfile** - -Read container ID from the specified file and pause the container. Can be specified multiple times. +@@option cidfile.read #### **--filter**, **-f**=*filter* diff --git a/docs/source/markdown/podman-pod-clone.1.md.in b/docs/source/markdown/podman-pod-clone.1.md.in index a5746fd84..c040f1c27 100644 --- a/docs/source/markdown/podman-pod-clone.1.md.in +++ b/docs/source/markdown/podman-pod-clone.1.md.in @@ -56,9 +56,7 @@ Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sd Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb) -#### **--gidmap**=*pod_gid:host_gid:amount* - -GID map for the user namespace. Using this flag will run all containers in the pod with user namespace enabled. It conflicts with the `--userns` and `--subgidname` flags. +@@option gidmap.pod #### **--help**, **-h** diff --git a/docs/source/markdown/podman-pod-create.1.md.in b/docs/source/markdown/podman-pod-create.1.md.in index 73b634548..702780c65 100644 --- a/docs/source/markdown/podman-pod-create.1.md.in +++ b/docs/source/markdown/podman-pod-create.1.md.in @@ -89,14 +89,12 @@ Set custom DNS search domains in the /etc/resolv.conf file that will be shared b Set the exit policy of the pod when the last container exits. Supported policies are: -| Exit Policy | Description | -| ------------------ | --------------------------------------------------------------------------- | -| *continue* | The pod continues running when the last container exits. Used by default. | -| *stop* | The pod is stopped when the last container exits. Used in `kube play`. | +| Exit Policy | Description | +| ------------------ | -------------------------------------------------------------------------------------------------------------------------- | +| *continue* | The pod continues running, by keeping its infra container alive, when the last container exits. Used by default. | +| *stop* | The pod (including its infra container) is stopped when the last container exits. Used in `kube play`. | -#### **--gidmap**=*container_gid:host_gid:amount* - -GID map for the user namespace. Using this flag will run the container with user namespace enabled. It conflicts with the `--userns` and `--subgidname` flags. +@@option gidmap.pod #### **--help**, **-h** diff --git a/docs/source/markdown/podman-pod-logs.1.md b/docs/source/markdown/podman-pod-logs.1.md.in index 7fc1d4b90..391f620f8 100644 --- a/docs/source/markdown/podman-pod-logs.1.md +++ b/docs/source/markdown/podman-pod-logs.1.md.in @@ -13,51 +13,27 @@ Note: Long running command of `podman pod log` with a `-f` or `--follow` needs t ## OPTIONS -#### **--color** - -Output the containers with different colors in the log. +@@option color #### **--container**, **-c** By default `podman pod logs` retrieves logs for all the containers available within the pod differentiate by field `container`. However there are use-cases where user would want to limit the log stream only to a particular container of a pod for such cases `-c` can be used like `podman pod logs -c ctrNameorID podname`. -#### **--follow**, **-f** - -Follow log output. Default is false. - -Note: If you are following a pod which is removed `podman pod rm`, then there is a -chance that the log file will be removed before `podman pod logs` reads the final content. +@@option follow #### **--latest**, **-l** Instead of providing the pod name or id, get logs of the last created pod. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) -#### **--names**, **-n** - -Output the container names instead of the container IDs in the log. - -#### **--since**=*TIMESTAMP* - -Show logs since TIMESTAMP. The --since option can be Unix timestamps, date formatted timestamps, or Go duration -strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Supported formats for date formatted -time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00, -and 2006-01-02. - -#### **--tail**=*LINES* - -Output the specified number of LINES at the end of the logs. LINES must be an integer. Defaults to -1, -which prints all lines +@@option names -#### **--timestamps**, **-t** +@@option since -Show timestamps in the log outputs. The default is false +@@option tail -#### **--until**=*TIMESTAMP* +@@option timestamps -Show logs until TIMESTAMP. The --until option can be Unix timestamps, date formatted timestamps, or Go duration -strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Supported formats for date formatted -time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00, -and 2006-01-02. +@@option until ## EXAMPLE diff --git a/docs/source/markdown/podman-pod-restart.1.md b/docs/source/markdown/podman-pod-restart.1.md index 677eca3a3..51f13dbf8 100644 --- a/docs/source/markdown/podman-pod-restart.1.md +++ b/docs/source/markdown/podman-pod-restart.1.md @@ -24,17 +24,27 @@ Instead of providing the pod name or ID, restart the last created pod. (This opt ## EXAMPLE +Restart pod with a given name ``` podman pod restart mywebserverpod cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907 +``` +Restart multiple pods with given IDs +``` podman pod restart 490eb 3557fb 490eb241aaf704d4dd2629904410fe4aa31965d9310a735f8755267f4ded1de5 3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab +``` +Restart the last created pod +``` podman pod restart --latest 3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab +``` +Restart all pods +``` podman pod restart --all 19456b4cd557eaf9629825113a552681a6013f8c8cad258e36ab825ef536e818 3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab @@ -42,7 +52,6 @@ podman pod restart --all 70c358daecf71ef9be8f62404f926080ca0133277ef7ce4f6aa2d5af6bb2d3e9 cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907 ``` - ## SEE ALSO **[podman(1)](podman.1.md)**, **[podman-pod(1)](podman-pod.1.md)**, **[podman-restart(1)](podman-restart.1.md)** diff --git a/docs/source/markdown/podman-pod-rm.1.md b/docs/source/markdown/podman-pod-rm.1.md.in index befab6791..82e28acb1 100644 --- a/docs/source/markdown/podman-pod-rm.1.md +++ b/docs/source/markdown/podman-pod-rm.1.md.in @@ -19,19 +19,13 @@ Remove all pods. Can be used in conjunction with \-f as well. Stop running containers and delete all stopped containers before removal of pod. -#### **--ignore**, **-i** - -Ignore errors when specified pods are not in the container store. A user might -have decided to manually remove a pod which would lead to a failure during the -ExecStop directive of a systemd service referencing that pod. +@@option ignore #### **--latest**, **-l** Instead of providing the pod name or ID, remove the last created pod. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) -#### **--pod-id-file** - -Read pod ID from the specified file and remove the pod. Can be specified multiple times. +@@option pod-id-file.pod #### **--time**, **-t**=*seconds* diff --git a/docs/source/markdown/podman-pod-start.1.md b/docs/source/markdown/podman-pod-start.1.md.in index 45fc50c51..6a47ce1b9 100644 --- a/docs/source/markdown/podman-pod-start.1.md +++ b/docs/source/markdown/podman-pod-start.1.md.in @@ -20,9 +20,7 @@ Starts all pods Instead of providing the pod name or ID, start the last created pod. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) -#### **--pod-id-file** - -Read pod ID from the specified file and start the pod. Can be specified multiple times. +@@option pod-id-file.pod ## EXAMPLE diff --git a/docs/source/markdown/podman-pod-stop.1.md b/docs/source/markdown/podman-pod-stop.1.md.in index bded0ba7d..abcc69e9e 100644 --- a/docs/source/markdown/podman-pod-stop.1.md +++ b/docs/source/markdown/podman-pod-stop.1.md.in @@ -15,19 +15,13 @@ Stop containers in one or more pods. You may use pod IDs or names as input. Stops all pods -#### **--ignore**, **-i** - -Ignore errors when specified pods are not in the container store. A user might -have decided to manually remove a pod which would lead to a failure during the -ExecStop directive of a systemd service referencing that pod. +@@option ignore #### **--latest**, **-l** Instead of providing the pod name or ID, stop the last created pod. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) -#### **--pod-id-file** - -Read pod ID from the specified file and stop the pod. Can be specified multiple times. +@@option pod-id-file.pod #### **--time**, **-t**=*seconds* @@ -35,20 +29,20 @@ Seconds to wait before forcibly stopping the containers in the pod. ## EXAMPLE -Stop a pod called *mywebserverpod* +Stop pod with a given name ``` $ podman pod stop mywebserverpod cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907 ``` -Stop two pods by their short IDs. +Stop multiple pods with given IDs. ``` $ podman pod stop 490eb 3557fb 490eb241aaf704d4dd2629904410fe4aa31965d9310a735f8755267f4ded1de5 3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab ``` -Stop the most recent pod +Stop the last created pod ``` $ podman pod stop --latest 3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab @@ -71,7 +65,7 @@ $ podman pod stop --pod-id-file file1 --pod-id-file file2 cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907 ``` -Stop all pods with a timeout of 1 second. +Stop all pods with a timeout of 1 second ``` $ podman pod stop -a -t 1 3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab diff --git a/docs/source/markdown/podman-pull.1.md.in b/docs/source/markdown/podman-pull.1.md.in index 29c4f865d..03f9b8fd7 100644 --- a/docs/source/markdown/podman-pull.1.md.in +++ b/docs/source/markdown/podman-pull.1.md.in @@ -51,30 +51,13 @@ All tagged images in the repository will be pulled. @@option arch -#### **--authfile**=*path* +@@option authfile -Path of the authentication file. If the authorization state is not found there, `$HOME/.docker/config.json` is checked, which is set using `docker login`. +@@option cert-dir -Default is `${XDG\_RUNTIME\_DIR}/containers/auth.json`, which is set using `podman login`. +@@option creds -*IMPORTANT: The default path of the authentication file can be overwritten by setting the `REGISTRY\_AUTH\_FILE` environment variable. `export REGISTRY_AUTH_FILE=path`* - -#### **--cert-dir**=*path* - -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) -Please refer to **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)** for details. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) - -#### **--creds**=*[username[:password]]* - -The [username[:password]] to use to authenticate with the registry if required. -If one or both values are not supplied, a command line prompt will appear and the -value can be entered. The password is entered without echo. - -#### **--disable-content-trust** - -This is a Docker specific option to disable image verification to a Docker -registry and is not supported by Podman. This flag is a NOOP and provided -solely for scripting compatibility. +@@option disable-content-trust #### **--help**, **-h** @@ -83,6 +66,7 @@ Print the usage statement. #### **--os**=*OS* Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. +Unless overridden, subsequent lookups of the same image in the local storage will match this OS, regardless of the host. @@option platform diff --git a/docs/source/markdown/podman-push.1.md b/docs/source/markdown/podman-push.1.md.in index d674975b0..a98964e45 100644 --- a/docs/source/markdown/podman-push.1.md +++ b/docs/source/markdown/podman-push.1.md.in @@ -47,18 +47,9 @@ $ podman push myimage oci-archive:/tmp/myimage ## OPTIONS -#### **--authfile**=*path* +@@option authfile -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. -If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. - -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` - -#### **--cert-dir**=*path* - -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. (Default: /etc/containers/certs.d) -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) +@@option cert-dir #### **--compress** @@ -69,21 +60,13 @@ Note: This flag can only be set when using the **dir** transport Specifies the compression format to use. Supported values are: `gzip`, `zstd` and `zstd:chunked`. The default is `gzip` unless overridden in the containers.conf file. -#### **--creds**=*[username[:password]]* - -The [username[:password]] to use to authenticate with the registry if required. -If one or both values are not supplied, a command line prompt will appear and the -value can be entered. The password is entered without echo. +@@option creds #### **--digestfile**=*Digestfile* After copying the image, write the digest of the resulting image to the file. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) -#### **--disable-content-trust** - -This is a Docker specific option to disable image verification to a Docker -registry and is not supported by Podman. This flag is a NOOP and provided -solely for scripting compatibility. +@@option disable-content-trust #### **--format**, **-f**=*format* diff --git a/docs/source/markdown/podman-rename.1.md b/docs/source/markdown/podman-rename.1.md index 4017db505..0a807e6de 100644 --- a/docs/source/markdown/podman-rename.1.md +++ b/docs/source/markdown/podman-rename.1.md @@ -19,18 +19,18 @@ At present, only containers are supported; pods and volumes cannot be renamed. ## EXAMPLES +Rename container with a given name ``` -# Rename a container by name $ podman rename oldContainer aNewName ``` +Rename container with a given ID ``` -# Rename a container by ID $ podman rename 717716c00a6b testcontainer ``` +Create an alias for container with a given ID ``` -# Use the container rename alias $ podman container rename 6e7514b47180 databaseCtr ``` diff --git a/docs/source/markdown/podman-restart.1.md b/docs/source/markdown/podman-restart.1.md index 323087069..b9da413f7 100644 --- a/docs/source/markdown/podman-restart.1.md +++ b/docs/source/markdown/podman-restart.1.md @@ -14,14 +14,46 @@ Containers will be stopped if they are running and then restarted. Stopped containers will not be stopped and will only be started. ## OPTIONS + #### **--all**, **-a** + Restart all containers regardless of their current state. +#### **--cidfile** + +Read container ID from the specified file and restart the container. Can be specified multiple times. + +#### **--filter**, **-f**=*filter* + +Filter what containers restart. +Multiple filters can be given with multiple uses of the --filter flag. +Filters with the same key work inclusive with the only exception being +`label` which is exclusive. Filters with different keys always work exclusive. + +Valid filters are listed below: + +| **Filter** | **Description** | +| --------------- | -------------------------------------------------------------------------------- | +| id | [ID] Container's ID (accepts regex) | +| name | [Name] Container's name (accepts regex) | +| label | [Key] or [Key=Value] Label assigned to a container | +| exited | [Int] Container's exit code | +| status | [Status] Container's status: 'created', 'exited', 'paused', 'running', 'unknown' | +| ancestor | [ImageName] Image or descendant used to create container | +| before | [ID] or [Name] Containers created before this container | +| since | [ID] or [Name] Containers created since this container | +| volume | [VolumeName] or [MountpointDestination] Volume mounted in container | +| health | [Status] healthy or unhealthy | +| pod | [Pod] name or full or partial ID of pod | +| network | [Network] name or full ID of network | + #### **--latest**, **-l** + Instead of providing the container name or ID, use the last created container. If you use methods other than Podman to run containers such as CRI-O, the last started container could be from either of those methods. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) #### **--running** + Restart all containers that are already in the *running* state. #### **--time**, **-t**=*seconds* @@ -59,6 +91,12 @@ Restart all containers $ podman restart --all ``` +Restart container using ID specified in a given files. +``` +$ podman restart --cidfile /home/user/cidfile-1 +$ podman restart --cidfile /home/user/cidfile-1 --cidfile ./cidfile-2 +``` + ## SEE ALSO **[podman(1)](podman.1.md)** diff --git a/docs/source/markdown/podman-rm.1.md b/docs/source/markdown/podman-rm.1.md.in index 1dbd1d0c3..9eb44dcc1 100644 --- a/docs/source/markdown/podman-rm.1.md +++ b/docs/source/markdown/podman-rm.1.md.in @@ -18,9 +18,7 @@ Running or unusable containers will not be removed without the **-f** option. Remove all containers. Can be used in conjunction with **-f** as well. -#### **--cidfile** - -Read container ID from the specified file and remove the container. Can be specified multiple times. +@@option cidfile.read #### **--depend** @@ -58,11 +56,7 @@ Containers could have been created by a different container engine. In addition, forcing can be used to remove unusable containers, e.g. containers whose OCI runtime has become unavailable. -#### **--ignore**, **-i** - -Ignore errors when specified containers are not in the container store. A user -might have decided to manually remove a container which would lead to a failure -during the ExecStop directive of a systemd service referencing that container. +@@option ignore #### **--latest**, **-l** @@ -79,37 +73,37 @@ Remove anonymous volumes associated with the container. This does not include na created with **podman volume create**, or the **--volume** option of **podman run** and **podman create**. ## EXAMPLE -Remove a container by its name *mywebserver* +Remove container with a given name ``` $ podman rm mywebserver ``` -Remove a *mywebserver* container and all of the containers that depend on it +Remove container with a given name and all of the containers that depend on it ``` $ podman rm --depend mywebserver ``` -Remove several containers by name and container id. +Remove multiple containers with given names or IDs ``` $ podman rm mywebserver myflaskserver 860a4b23 ``` -Remove several containers reading their IDs from files. +Remove multiple containers with IDs read from files ``` $ podman rm --cidfile ./cidfile-1 --cidfile /home/user/cidfile-2 ``` -Forcibly remove a container by container ID. +Forcibly remove container with a given ID ``` $ podman rm -f 860a4b23 ``` -Remove all containers regardless of its run state. +Remove all containers regardless of the run state ``` $ podman rm -f -a ``` -Forcibly remove the latest container created. +Forcibly remove the last created container ``` $ podman rm -f --latest ``` diff --git a/docs/source/markdown/podman-run.1.md.in b/docs/source/markdown/podman-run.1.md.in index 81b635bc8..6798c65da 100644 --- a/docs/source/markdown/podman-run.1.md.in +++ b/docs/source/markdown/podman-run.1.md.in @@ -100,12 +100,7 @@ error. It can even pretend to be a TTY (this is what most commandline executables expect) and pass along signals. The **-a** option can be set for each of **stdin**, **stdout**, and **stderr**. -#### **--authfile**=*[path]* - -Path to the authentication file. Default is *${XDG_RUNTIME_DIR}/containers/auth.json*. - -Note: You can also override the default path of the authentication file by setting the **REGISTRY_AUTH_FILE** -environment variable. +@@option authfile @@option blkio-weight @@ -125,9 +120,7 @@ environment variable. @@option chrootdirs -#### **--cidfile**=*file* - -Write the container ID to *file*. +@@option cidfile.write @@option conmon-pidfile @@ -141,15 +134,7 @@ Write the container ID to *file*. @@option cpu-shares -#### **--cpus**=*number* - -Number of CPUs. The default is *0.0* which means no limit. This is shorthand -for **--cpu-period** and **--cpu-quota**, so you may only set either -**--cpus** or **--cpu-period** and **--cpu-quota**. - -On some systems, changing the CPU limits may not be allowed for non-root -users. For more details, see -https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error +@@option cpus.container @@option cpuset-cpus @@ -193,31 +178,33 @@ Podman may load kernel modules required for using the specified device. The devices that Podman will load modules when necessary are: /dev/fuse. -#### **--device-cgroup-rule**=*rule* - -Add a rule to the cgroup allowed devices list +@@option device-cgroup-rule #### **--device-read-bps**=*path:rate* Limit read rate (in bytes per second) from a device (e.g. **--device-read-bps=/dev/sda:1mb**). +This option is not supported on cgroups V1 rootless systems. + #### **--device-read-iops**=*path:rate* Limit read rate (in IO operations per second) from a device (e.g. **--device-read-iops=/dev/sda:1000**). +This option is not supported on cgroups V1 rootless systems. + #### **--device-write-bps**=*path:rate* Limit write rate (in bytes per second) to a device (e.g. **--device-write-bps=/dev/sda:1mb**). +This option is not supported on cgroups V1 rootless systems. + #### **--device-write-iops**=*path:rate* Limit write rate (in IO operations per second) to a device (e.g. **--device-write-iops=/dev/sda:1000**). -#### **--disable-content-trust** +This option is not supported on cgroups V1 rootless systems. -This is a Docker specific option to disable image verification to a Docker -registry and is not supported by Podman. This flag is a NOOP and provided -solely for scripting compatibility. +@@option disable-content-trust #### **--dns**=*ipaddr* @@ -231,14 +218,9 @@ is the case the **--dns** flag is necessary for every run. The special value **none** can be specified to disable creation of _/etc/resolv.conf_ in the container by Podman. The _/etc/resolv.conf_ file in the image will be used without changes. -#### **--dns-opt**=*option* - -Set custom DNS options. Invalid if using **--dns-opt** with **--network** that is set to **none** or **container:**_id_. +@@option dns-opt.container -#### **--dns-search**=*domain* - -Set custom DNS search domains. Invalid if using **--dns-search** and **--network** that is set to **none** or **container:**_id_. -Use **--dns-search=.** if you don't wish to set the search domain. +@@option dns-search.container @@option entrypoint @@ -256,16 +238,11 @@ Read in a line delimited file of environment variables. See **Environment** note @@option env-host -@@option expose - -#### **--gidmap**=*container_gid:host_gid:amount* +@@option env-merge -Run the container in a new user namespace using the supplied GID mapping. This -option conflicts with the **--userns** and **--subgidname** options. This -option provides a way to map host GIDs to container GIDs in the same way as -__--uidmap__ maps host UIDs to container UIDs. For details see __--uidmap__. +@@option expose -Note: the **--gidmap** flag cannot be called in conjunction with the **--pod** flag as a gidmap cannot be set on the container level when in a pod. +@@option gidmap.container @@option group-add @@ -330,18 +307,7 @@ The address must be within the network's IPv6 address pool. To specify multiple static IPv6 addresses per container, set multiple networks using the **--network** option with a static IPv6 address specified for each using the `ip6` mode for that option. -#### **--ipc**=*mode* - -Set the IPC namespace mode for a container. The default is to create -a private IPC namespace. - -- "": Use Podman's default, defined in containers.conf. -- **container:**_id_: reuses another container shared memory, semaphores and message queues -- **host**: use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. -- **none**: private IPC namespace, with /dev/shm not mounted. -- **ns:**_path_: path to an IPC namespace to join. -- **private**: private IPC namespace. -= **shareable**: private IPC namespace with a possibility to share it with other containers. +@@option ipc #### **--label**, **-l**=*key=value* @@ -382,6 +348,8 @@ RAM. If a limit of 0 is specified (not using **-m**), the container's memory is not limited. The actual limit may be rounded up to a multiple of the operating system's page size (the value would be very large, that's millions of trillions). +This option is not supported on cgroups V1 rootless systems. + #### **--memory-reservation**=*number[unit]* Memory soft limit. A _unit_ can be **b** (bytes), **k** (kibibytes), **m** (mebibytes), or **g** (gibibytes). @@ -392,6 +360,8 @@ reservation. So you should always set the value below **--memory**, otherwise th hard limit will take precedence. By default, memory reservation will be the same as memory limit. +This option is not supported on cgroups V1 rootless systems. + #### **--memory-swap**=*number[unit]* A limit value equal to memory plus swap. @@ -404,6 +374,8 @@ the value of **--memory**. Set _number_ to **-1** to enable unlimited swap. +This option is not supported on cgroups V1 rootless systems. + @@option memory-swappiness @@option mount @@ -470,6 +442,7 @@ This option conflicts with **--add-host**. #### **--os**=*OS* Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. +Unless overridden, subsequent lookups of the same image in the local storage will match this OS, regardless of the host. #### **--passwd** @@ -480,15 +453,7 @@ This is used to override the Podman provided user setup in favor of entrypoint c @@option personality -#### **--pid**=*mode* - -Set the PID namespace mode for the container. -The default is to create a private PID namespace for the container. - -- **container:**_id_: join another container's PID namespace; -- **host**: use the host's PID namespace for the container. Note the host mode gives the container full access to local PID and is therefore considered insecure; -- **private**: create a new namespace for the container (default) -- **ns:**_path_: join the specified PID namespace. +@@option pid @@option pidfile @@ -502,10 +467,7 @@ Run container in an existing pod. If you want Podman to make the pod for you, pr To make a pod with more granular options, use the **podman pod create** command before creating a container. If a container is run with a pod, and the pod has an infra-container, the infra-container will be started before the container is. -#### **--pod-id-file**=*path* - -Run container in an existing pod and read the pod's ID from the specified file. -If a container is run within a pod, and the pod has an infra-container, the infra-container will be started before the container is. +@@option pod-id-file.container #### **--preserve-fds**=*N* @@ -715,35 +677,7 @@ For the network namespace, the following sysctls are allowed: Note: if you use the **--network=host** option, these sysctls will not be allowed. -#### **--systemd**=*true* | *false* | *always* - -Run container in systemd mode. The default is **true**. - -The value *always* enforces the systemd mode is enforced without -looking at the executable name. Otherwise, if set to true and the -command you are running inside the container is **systemd**, **/usr/sbin/init**, -**/sbin/init** or **/usr/local/sbin/init**. - -Running the container in systemd mode causes the following changes: - -* Podman mounts tmpfs file systems on the following directories - * _/run_ - * _/run/lock_ - * _/tmp_ - * _/sys/fs/cgroup/systemd_ - * _/var/lib/journal_ -* Podman sets the default stop signal to **SIGRTMIN+3**. -* Podman sets **container_uuid** environment variable in the container to the -first 32 characters of the container id. - -This allows systemd to run in a confined container without any modifications. - -Note that on **SELinux** systems, systemd attempts to write to the cgroup -file system. Containers writing to the cgroup file system are denied by default. -The **container_manage_cgroup** boolean must be enabled for this to be allowed on an SELinux separated system. -``` -setsebool -P container_manage_cgroup true -``` +@@option systemd @@option timeout @@ -1043,13 +977,7 @@ If the location of the volume from the source container overlaps with data residing on a target container, then the volume hides that data on the target. -#### **--workdir**, **-w**=*dir* - -Working directory inside the container. - -The default working directory for running binaries within a container is the root directory (**/**). -The image developer can set a different default with the WORKDIR instruction. The operator -can override the working directory by using the **-w** option. +@@option workdir ## Exit Status diff --git a/docs/source/markdown/podman-search.1.md b/docs/source/markdown/podman-search.1.md.in index 5b49d7f8e..9dd8cebf8 100644 --- a/docs/source/markdown/podman-search.1.md +++ b/docs/source/markdown/podman-search.1.md.in @@ -30,12 +30,7 @@ Further note that searching without a search term will only work for registries ## OPTIONS -#### **--authfile**=*path* - -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json - -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` +@@option authfile #### **--compatible** diff --git a/docs/source/markdown/podman-secret-create.1.md b/docs/source/markdown/podman-secret-create.1.md index e08afb388..39e0c6843 100644 --- a/docs/source/markdown/podman-secret-create.1.md +++ b/docs/source/markdown/podman-secret-create.1.md @@ -20,7 +20,7 @@ Secrets will not be committed to an image with `podman commit`, and will not be ## OPTIONS -#### **--driver**=*driver* +#### **--driver**, **-d**=*driver* Specify the secret driver (default **file**, which is unencrypted). diff --git a/docs/source/markdown/podman-secret-inspect.1.md b/docs/source/markdown/podman-secret-inspect.1.md index df16ba6fa..1a7115f63 100644 --- a/docs/source/markdown/podman-secret-inspect.1.md +++ b/docs/source/markdown/podman-secret-inspect.1.md @@ -15,7 +15,7 @@ Secrets can be queried individually by providing their full name or a unique par ## OPTIONS -#### **--format**=*format* +#### **--format**, **-f**=*format* Format secret output using Go template. diff --git a/docs/source/markdown/podman-secret-ls.1.md b/docs/source/markdown/podman-secret-ls.1.md index 3b8535b5d..dcd10c9cf 100644 --- a/docs/source/markdown/podman-secret-ls.1.md +++ b/docs/source/markdown/podman-secret-ls.1.md @@ -30,7 +30,11 @@ Format secret output using Go template. #### **--noheading** -Omit the table headings from the listing of secrets. . +Omit the table headings from the listing of secrets. + +#### **--quiet**, **-q** + +Print secret IDs only. ## EXAMPLES diff --git a/docs/source/markdown/podman-stats.1.md b/docs/source/markdown/podman-stats.1.md index d87da6a60..8d07be1a0 100644 --- a/docs/source/markdown/podman-stats.1.md +++ b/docs/source/markdown/podman-stats.1.md @@ -61,6 +61,10 @@ Do not clear the terminal/screen in between reporting intervals Disable streaming stats and only pull the first result, default setting is false +#### **--no-trunc** + +Do not truncate output + ## EXAMPLE ``` @@ -77,6 +81,12 @@ a9f807ffaacd frosty_hodgkin -- 3.092MB / 16.7GB 0.02% -- / -- -- ``` ``` +$ podman stats --no-trunc 3667 --format 'table {{ .ID }} {{ .MemUsage }}' +ID MEM USAGE / LIMIT +3667c6aacb06aac2eaffce914c01736420023d56ef9b0f4cfe58b6d6a78b7503 49.15kB / 67.17GB +``` + +``` # podman stats --no-stream --format=json a9f80 [ { diff --git a/docs/source/markdown/podman-stop.1.md b/docs/source/markdown/podman-stop.1.md.in index cfc49afa1..9aaccdfaa 100644 --- a/docs/source/markdown/podman-stop.1.md +++ b/docs/source/markdown/podman-stop.1.md.in @@ -21,9 +21,7 @@ container and also via command line when creating the container. Stop all running containers. This does not include paused containers. -#### **--cidfile** - -Read container ID from the specified file and remove the container. Can be specified multiple times. +@@option cidfile.read #### **--filter**, **-f**=*filter* @@ -49,11 +47,7 @@ Valid filters are listed below: | pod | [Pod] name or full or partial ID of pod | | network | [Network] name or full ID of network | -#### **--ignore**, **-i** - -Ignore errors when specified containers are not in the container store. A user -might have decided to manually remove a container which would lead to a failure -during the ExecStop directive of a systemd service referencing that container. +@@option ignore #### **--latest**, **-l** diff --git a/docs/source/markdown/podman-system-service.1.md b/docs/source/markdown/podman-system-service.1.md index 99fde8ce4..3e7a00362 100644 --- a/docs/source/markdown/podman-system-service.1.md +++ b/docs/source/markdown/podman-system-service.1.md @@ -8,7 +8,7 @@ podman\-system\-service - Run an API service ## DESCRIPTION The **podman system service** command creates a listening service that will answer API calls for Podman. You may -optionally provide an endpoint for the API in URI form. For example, *unix:///tmp/foobar.sock* or *tcp:localhost:8080*. +optionally provide an endpoint for the API in URI form. For example, *unix:///tmp/foobar.sock* or *tcp://localhost:8080*. If no endpoint is provided, defaults will be used. The default endpoint for a rootful service is *unix:///run/podman/podman.sock* and rootless is *unix://$XDG_RUNTIME_DIR/podman/podman.sock* (for example *unix:///run/user/1000/podman/podman.sock*) diff --git a/docs/source/markdown/podman-unpause.1.md b/docs/source/markdown/podman-unpause.1.md.in index b94ace89e..7bd46e171 100644 --- a/docs/source/markdown/podman-unpause.1.md +++ b/docs/source/markdown/podman-unpause.1.md.in @@ -17,9 +17,7 @@ Unpauses the processes in one or more containers. You may use container IDs or Unpause all paused containers. -#### **--cidfile** - -Read container ID from the specified file and unpause the container. Can be specified multiple times. +@@option cidfile.read #### **--filter**, **-f**=*filter* @@ -12,11 +12,11 @@ require ( github.com/containernetworking/cni v1.1.2 github.com/containernetworking/plugins v1.1.1 github.com/containers/buildah v1.27.0 - github.com/containers/common v0.49.2-0.20220809074359-b0ea008ba661 + github.com/containers/common v0.49.2-0.20220823130605-72a7da3358ac github.com/containers/conmon v2.0.20+incompatible github.com/containers/image/v5 v5.22.0 github.com/containers/ocicrypt v1.1.5 - github.com/containers/psgo v1.7.2 + github.com/containers/psgo v1.7.3 github.com/containers/storage v1.42.0 github.com/coreos/go-systemd/v22 v22.3.2 github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3 @@ -49,6 +49,7 @@ require ( github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab github.com/opencontainers/runtime-tools v0.9.1-0.20220714195903-17b3287fafb7 github.com/opencontainers/selinux v1.10.1 + github.com/openshift/imagebuilder v1.2.4-0.20220711175835-4151e43600df github.com/rootless-containers/rootlesskit v1.0.1 github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.5.0 @@ -57,11 +58,11 @@ require ( github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 github.com/uber/jaeger-client-go v2.30.0+incompatible github.com/ulikunitz/xz v0.5.10 - github.com/vbauerster/mpb/v7 v7.4.2 + github.com/vbauerster/mpb/v7 v7.5.2 github.com/vishvananda/netlink v1.1.1-0.20220115184804-dd687eb2f2d4 go.etcd.io/bbolt v1.3.6 golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab + golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 golang.org/x/text v0.3.7 google.golang.org/protobuf v1.28.1 @@ -101,7 +101,6 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -140,8 +139,9 @@ github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwT github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0= github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= -github.com/Microsoft/hcsshim v0.9.3 h1:k371PzBuRrz2b+ebGuI2nVgVhgsVX60jMfSw80NECxo= github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.4 h1:mnUj0ivWy6UzbB1uLFqKR6F+ZyiDc7j4iGgHTpO+5+I= +github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= @@ -323,8 +323,9 @@ github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0 github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= github.com/containerd/containerd v1.5.9/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ= github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE= -github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0= github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0= +github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs= +github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= @@ -361,7 +362,6 @@ github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oM github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= github.com/containerd/stargz-snapshotter/estargz v0.9.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0= -github.com/containerd/stargz-snapshotter/estargz v0.10.1/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0= github.com/containerd/stargz-snapshotter/estargz v0.11.4/go.mod h1:7vRJIcImfY8bpifnMjt+HTJoQxASq7T28MYbP15/Nf0= github.com/containerd/stargz-snapshotter/estargz v0.12.0 h1:idtwRTLjk2erqiYhPWy2L844By8NRFYEwYHcXhoIWPM= github.com/containerd/stargz-snapshotter/estargz v0.12.0/go.mod h1:AIQ59TewBFJ4GOPEQXujcrJ/EKxh5xXZegW1rkR1P/M= @@ -395,8 +395,8 @@ github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19 github.com/containers/buildah v1.27.0 h1:LJ1ks7vKxwPzJGr5BWVvigbtVL9w7XeHtNEmiIOPJqI= github.com/containers/buildah v1.27.0/go.mod h1:anH3ExvDXRNP9zLQCrOc1vWb5CrhqLF/aYFim4tslvA= github.com/containers/common v0.49.1/go.mod h1:ueM5hT0itKqCQvVJDs+EtjornAQtrHYxQJzP2gxeGIg= -github.com/containers/common v0.49.2-0.20220809074359-b0ea008ba661 h1:2Ldzg1st4REr5uUJRhjsye1zCbu0i/89RBh87Xc/cTY= -github.com/containers/common v0.49.2-0.20220809074359-b0ea008ba661/go.mod h1:eT2iSsNzjOlF5VFLkyj9OU2SXznURvEYndsioQImuoE= +github.com/containers/common v0.49.2-0.20220823130605-72a7da3358ac h1:rLbTzosxPKrQd+EgMRxfC1WYm3azPiQfig+Lr7mCQ4k= +github.com/containers/common v0.49.2-0.20220823130605-72a7da3358ac/go.mod h1:xC4qkLfW9R+YSDknlT9xU+NDNxIw017U8AyohGtr9Ec= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.22.0 h1:KemxPmD4D2YYOFZN2SgoTk7nBFcnwPiPW0MqjYtknSE= @@ -410,10 +410,9 @@ github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B github.com/containers/ocicrypt v1.1.3/go.mod h1:xpdkbVAuaH3WzbEabUd5yDsl9SwJA5pABH85425Es2g= github.com/containers/ocicrypt v1.1.5 h1:UO+gBnBXvMvC7HTXLh0bPgLslfW8HlY+oxYcoSHBcZQ= github.com/containers/ocicrypt v1.1.5/go.mod h1:WgjxPWdTJMqYMjf3M6cuIFFA1/MpyyhIM99YInA+Rvc= -github.com/containers/psgo v1.7.2 h1:WbCvsY9w+nCv3j4der0mbD3PSRUv/W8l+G0YrZrdSDc= -github.com/containers/psgo v1.7.2/go.mod h1:SLpqxsPOHtTqRygjutCPXmeU2PoEFzV3gzJplN4BMx0= +github.com/containers/psgo v1.7.3 h1:KTNurTMXpZjDJHWmlieVO7k7jgKJ4CR/HpPeSaAKtgc= +github.com/containers/psgo v1.7.3/go.mod h1:PfaNzzHmMb8M9/blPgyD4BB3ZEj/0ApZIxN6nNtA+t4= github.com/containers/storage v1.37.0/go.mod h1:kqeJeS0b7DO2ZT1nVWs0XufrmPFbgV3c+Q/45RlH6r4= -github.com/containers/storage v1.38.0/go.mod h1:lBzt28gAk5ADZuRtwdndRJyqX22vnRaXmlF+7ktfMYc= github.com/containers/storage v1.42.0 h1:zm2AQD4NDeTB3JQ8X+Wo5+VRqNB+b4ocEd7Qj6ylPJA= github.com/containers/storage v1.42.0/go.mod h1:JiUJwOgOo1dr2DdOUc1MRe2GCAXABYoYmOdPF8yvH78= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -1030,7 +1029,6 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.14.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.4/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.15.7/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= @@ -1595,8 +1593,9 @@ github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/V github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= -github.com/vbauerster/mpb/v7 v7.4.2 h1:n917F4d8EWdUKc9c81wFkksyG6P6Mg7IETfKCE1Xqng= github.com/vbauerster/mpb/v7 v7.4.2/go.mod h1:UmOiIUI8aPqWXIps0ciik3RKMdzx7+ooQpq+fBcXwBA= +github.com/vbauerster/mpb/v7 v7.5.2 h1:Ph3JvpBcoIwzIG1QwbUq97KQifrTRbKcMXN9rN5BYAs= +github.com/vbauerster/mpb/v7 v7.5.2/go.mod h1:UmOiIUI8aPqWXIps0ciik3RKMdzx7+ooQpq+fBcXwBA= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= @@ -2064,8 +2063,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 h1:TyKJRhyo17yWxOMCTHKWrc5rddHORMlnZ/j57umaUd8= +golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/hack/markdown-preprocess-review b/hack/markdown-preprocess-review index a487265ad..a3e237fb6 100755 --- a/hack/markdown-preprocess-review +++ b/hack/markdown-preprocess-review @@ -114,8 +114,60 @@ for my $i (0..$#all_opts) { next if $ans =~ /^n/i; exit 0 if $ans =~ /^q/i; - system("diffuse", "-w", glob("*")) == 0 - or die "Diffuse failed\n"; + # Try to cull the files (remove identical ones) + my @files = glob("*"); + my $winner = pop @files; + + for my $f (@files) { + system('cmp', '-s', $f, $winner); + if ($? == 0) { + print "[ $f is the one we went with; removing from list ]\n"; + unlink $f; + next; + } + + system('wdiff', '-1', '-2', '-3', $f, $winner); + if ($? == 0) { + print "[ $f is whitespace-identical with what we went with ]\n"; + unlink $f; + next; + } + } + + # Recompute @files, in case some were deleted above + @files = glob("*"); pop @files; + + for (my $i=0; $i < $#files; $i++) { + my $f1 = $files[$i]; + next unless -e $f1; + + for (my $j=$i+1; $j <= $#files; $j++) { + my $f2 = $files[$j]; + next unless -e $f2; + + system('wdiff', '-1', '-2', '-3', $f1, $f2); + if ($? == 0) { + print "[ $f2 : removing, it =~ $f1 ]\n"; + unlink $f2; + } + } + } + + # Recompute @files, in case some were deleted above + @files = glob("*"); + + # diffuse works great for 3-4 files, passable for 5, not at all for >5 + if (@files <= 5) { + system("diffuse", "-w", @files) == 0 + or die "Diffuse failed\n"; + } + else { + # Too many files. Go by threes. + my $winner = pop @files; + for (my $i=0; $i < @files; $i += 3) { + system("diffuse", "-w", @files[$i..$i+2], $winner); + } + } } diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 81f11410b..e5a7e20fc 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -1278,7 +1278,7 @@ func (s *BoltState) NetworkConnect(ctr *Container, network string, opts types.Pe } netConnected := ctrNetworksBkt.Get([]byte(network)) if netConnected != nil { - return fmt.Errorf("container %s is already connected to network %q: %w", ctr.ID(), network, define.ErrNetworkExists) + return fmt.Errorf("container %s is already connected to network %q: %w", ctr.ID(), network, define.ErrNetworkConnected) } // Add the network diff --git a/libpod/boltdb_state_freebsd.go b/libpod/boltdb_state_freebsd.go new file mode 100644 index 000000000..d7f2736fc --- /dev/null +++ b/libpod/boltdb_state_freebsd.go @@ -0,0 +1,17 @@ +//go:build freebsd +// +build freebsd + +package libpod + +// replaceNetNS handle network namespace transitions after updating a +// container's state. +func replaceNetNS(netNSPath string, ctr *Container, newState *ContainerState) error { + // On FreeBSD, we just record the network jail's name in our state. + newState.NetworkJail = netNSPath + return nil +} + +// getNetNSPath retrieves the netns path to be stored in the database +func getNetNSPath(ctr *Container) string { + return ctr.state.NetworkJail +} diff --git a/libpod/boltdb_state_unsupported.go b/libpod/boltdb_state_unsupported.go new file mode 100644 index 000000000..9db1e3c4b --- /dev/null +++ b/libpod/boltdb_state_unsupported.go @@ -0,0 +1,19 @@ +//go:build !linux && !freebsd +// +build !linux,!freebsd + +package libpod + +import ( + "errors" +) + +// replaceNetNS handle network namespace transitions after updating a +// container's state. +func replaceNetNS(netNSPath string, ctr *Container, newState *ContainerState) error { + return errors.New("replaceNetNS not supported on this platform") +} + +// getNetNSPath retrieves the netns path to be stored in the database +func getNetNSPath(ctr *Container) string { + return "" +} diff --git a/libpod/container_copy_unsupported.go b/libpod/container_copy_unsupported.go new file mode 100644 index 000000000..62937279a --- /dev/null +++ b/libpod/container_copy_unsupported.go @@ -0,0 +1,17 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "errors" + "io" +) + +func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir bool, rename map[string]string, reader io.Reader) (func() error, error) { + return nil, errors.New("not implemented (*Container) copyFromArchive") +} + +func (c *Container) copyToArchive(path string, writer io.Writer) (func() error, error) { + return nil, errors.New("not implemented (*Container) copyToArchive") +} diff --git a/libpod/container_freebsd.go b/libpod/container_freebsd.go new file mode 100644 index 000000000..f9fbc4daa --- /dev/null +++ b/libpod/container_freebsd.go @@ -0,0 +1,12 @@ +//go:build freebsd +// +build freebsd + +package libpod + +type containerPlatformState struct { + // NetworkJail is the name of the container's network VNET + // jail. Will only be set if config.CreateNetNS is true, or + // the container was told to join another container's network + // namespace. + NetworkJail string `json:"-"` +} diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 7cef067b0..60fb29607 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -293,20 +293,8 @@ func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr err } // set up slirp4netns again because slirp4netns will die when conmon exits - if c.config.NetMode.IsSlirp4netns() { - err := c.runtime.setupSlirp4netns(c, c.state.NetNS) - if err != nil { - return false, err - } - } - - // set up rootlesskit port forwarder again since it dies when conmon exits - // we use rootlesskit port forwarder only as rootless and when bridge network is used - if rootless.IsRootless() && c.config.NetMode.IsBridge() && len(c.config.PortMappings) > 0 { - err := c.runtime.setupRootlessPortMappingViaRLK(c, c.state.NetNS.Path(), c.state.NetworkStatus) - if err != nil { - return false, err - } + if err := c.setupRootlessNetwork(); err != nil { + return false, err } if c.state.State == define.ContainerStateStopped { @@ -1557,7 +1545,7 @@ func (c *Container) mountStorage() (_ string, deferredErr error) { rootUID, rootGID := c.RootUID(), c.RootGID() - dirfd, err := unix.Open(mountPoint, unix.O_RDONLY|unix.O_PATH, 0) + dirfd, err := openDirectory(mountPoint) if err != nil { return "", fmt.Errorf("open mount point: %w", err) } @@ -1580,7 +1568,7 @@ func (c *Container) mountStorage() (_ string, deferredErr error) { return "", fmt.Errorf("resolve /etc in the container: %w", err) } - etcInTheContainerFd, err := unix.Open(etcInTheContainerPath, unix.O_RDONLY|unix.O_PATH, 0) + etcInTheContainerFd, err := openDirectory(etcInTheContainerPath) if err != nil { return "", fmt.Errorf("open /etc in the container: %w", err) } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 3c77cb18c..5c5fd471b 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -3228,3 +3228,28 @@ func (c *Container) ChangeHostPathOwnership(src string, recurse bool, uid, gid i } return chown.ChangeHostPathOwnership(src, recurse, uid, gid) } + +// If the container is rootless, set up the slirp4netns network +func (c *Container) setupRootlessNetwork() error { + // set up slirp4netns again because slirp4netns will die when conmon exits + if c.config.NetMode.IsSlirp4netns() { + err := c.runtime.setupSlirp4netns(c, c.state.NetNS) + if err != nil { + return err + } + } + + // set up rootlesskit port forwarder again since it dies when conmon exits + // we use rootlesskit port forwarder only as rootless and when bridge network is used + if rootless.IsRootless() && c.config.NetMode.IsBridge() && len(c.config.PortMappings) > 0 { + err := c.runtime.setupRootlessPortMappingViaRLK(c, c.state.NetNS.Path(), c.state.NetworkStatus) + if err != nil { + return err + } + } + return nil +} + +func openDirectory(path string) (fd int, err error) { + return unix.Open(path, unix.O_RDONLY|unix.O_PATH, 0) +} diff --git a/libpod/container_internal_unsupported.go b/libpod/container_internal_unsupported.go new file mode 100644 index 000000000..074aeee47 --- /dev/null +++ b/libpod/container_internal_unsupported.go @@ -0,0 +1,99 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "context" + "errors" + + "github.com/containers/common/libnetwork/etchosts" + "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/pkg/lookup" + spec "github.com/opencontainers/runtime-spec/specs-go" +) + +func (c *Container) mountSHM(shmOptions string) error { + return errors.New("not implemented (*Container) mountSHM") +} + +func (c *Container) unmountSHM(mount string) error { + return errors.New("not implemented (*Container) unmountSHM") +} + +func (c *Container) cleanupOverlayMounts() error { + return errors.New("not implemented (*Container) cleanupOverlayMounts") +} + +// prepare mounts the container and sets up other required resources like net +// namespaces +func (c *Container) prepare() error { + return errors.New("not implemented (*Container) prepare") +} + +// resolveWorkDir resolves the container's workdir and, depending on the +// configuration, will create it, or error out if it does not exist. +// Note that the container must be mounted before. +func (c *Container) resolveWorkDir() error { + return errors.New("not implemented (*Container) resolveWorkDir") +} + +// cleanupNetwork unmounts and cleans up the container's network +func (c *Container) cleanupNetwork() error { + return errors.New("not implemented (*Container) cleanupNetwork") +} + +// reloadNetwork reloads the network for the given container, recreating +// firewall rules. +func (c *Container) reloadNetwork() error { + return errors.New("not implemented (*Container) reloadNetwork") +} + +// Generate spec for a container +// Accepts a map of the container's dependencies +func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { + return nil, errors.New("not implemented (*Container) generateSpec") +} + +func (c *Container) getUserOverrides() *lookup.Overrides { + return &lookup.Overrides{} +} + +func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) (*define.CRIUCheckpointRestoreStatistics, int64, error) { + return nil, 0, errors.New("not implemented (*Container) checkpoint") +} + +func (c *Container) restore(ctx context.Context, options ContainerCheckpointOptions) (criuStatistics *define.CRIUCheckpointRestoreStatistics, runtimeRestoreDuration int64, retErr error) { + return nil, 0, errors.New("not implemented (*Container) restore") +} + +// getHostsEntries returns the container ip host entries for the correct netmode +func (c *Container) getHostsEntries() (etchosts.HostEntries, error) { + return nil, errors.New("unsupported (*Container) getHostsEntries") +} + +// Fix ownership and permissions of the specified volume if necessary. +func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error { + return errors.New("unsupported (*Container) fixVolumePermissions") +} + +func (c *Container) expectPodCgroup() (bool, error) { + return false, errors.New("unsupported (*Container) expectPodCgroup") +} + +// Get cgroup path in a format suitable for the OCI spec +func (c *Container) getOCICgroupPath() (string, error) { + return "", errors.New("unsupported (*Container) getOCICgroupPath") +} + +func getLocalhostHostEntry(c *Container) etchosts.HostEntries { + return nil +} + +func isRootlessCgroupSet(cgroup string) bool { + return false +} + +func openDirectory(path string) (fd int, err error) { + return -1, errors.New("unsupported openDirectory") +} diff --git a/libpod/container_stat_unsupported.go b/libpod/container_stat_unsupported.go new file mode 100644 index 000000000..2f1acd44d --- /dev/null +++ b/libpod/container_stat_unsupported.go @@ -0,0 +1,14 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "errors" + + "github.com/containers/podman/v4/libpod/define" +) + +func (c *Container) stat(containerMountPoint string, containerPath string) (*define.FileInfo, string, string, error) { + return nil, "", "", errors.New("Containers stat not supported on this platform") +} diff --git a/libpod/container_top_unsupported.go b/libpod/container_top_unsupported.go new file mode 100644 index 000000000..a8d9b970b --- /dev/null +++ b/libpod/container_top_unsupported.go @@ -0,0 +1,14 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "errors" +) + +// Top gathers statistics about the running processes in a container. It returns a +// []string for output +func (c *Container) Top(descriptors []string) ([]string, error) { + return nil, errors.New("not implemented (*Container) Top") +} diff --git a/libpod/container_unsupported.go b/libpod/container_unsupported.go new file mode 100644 index 000000000..16bf11622 --- /dev/null +++ b/libpod/container_unsupported.go @@ -0,0 +1,7 @@ +//go:build !linux && !freebsd +// +build !linux,!freebsd + +package libpod + +type containerPlatformState struct { +} diff --git a/libpod/define/errors.go b/libpod/define/errors.go index fd27e89de..be471c27e 100644 --- a/libpod/define/errors.go +++ b/libpod/define/errors.go @@ -179,6 +179,9 @@ var ( // ErrNetworkInUse indicates the requested operation failed because the network was in use ErrNetworkInUse = errors.New("network is being used") + // ErrNetworkConnected indicates that the required operation failed because the container is already a network endpoint + ErrNetworkConnected = errors.New("network is already connected") + // ErrStoreNotInitialized indicates that the container storage was never // initialized. ErrStoreNotInitialized = errors.New("the container storage was never initialized") diff --git a/libpod/define/exec_codes.go b/libpod/define/exec_codes.go index 3f2da4910..a84730e72 100644 --- a/libpod/define/exec_codes.go +++ b/libpod/define/exec_codes.go @@ -11,8 +11,8 @@ const ( // ExecErrorCodeGeneric is the default error code to return from an exec session if libpod failed // prior to calling the runtime ExecErrorCodeGeneric = 125 - // ExecErrorCodeCannotInvoke is the error code to return when the runtime fails to invoke a command - // an example of this can be found by trying to execute a directory: + // ExecErrorCodeCannotInvoke is the error code to return when the runtime fails to invoke a command. + // An example of this can be found by trying to execute a directory: // `podman exec -l /etc` ExecErrorCodeCannotInvoke = 126 // ExecErrorCodeNotFound is the error code to return when a command cannot be found diff --git a/libpod/define/volume_inspect.go b/libpod/define/volume_inspect.go index 9279812da..76120647c 100644 --- a/libpod/define/volume_inspect.go +++ b/libpod/define/volume_inspect.go @@ -57,7 +57,7 @@ type InspectVolumeData struct { // UID/GID. NeedsChown bool `json:"NeedsChown,omitempty"` // Timeout is the specified driver timeout if given - Timeout int `json:"Timeout,omitempty"` + Timeout uint `json:"Timeout,omitempty"` } type VolumeReload struct { diff --git a/libpod/events/events_freebsd.go b/libpod/events/events_freebsd.go new file mode 100644 index 000000000..17d410089 --- /dev/null +++ b/libpod/events/events_freebsd.go @@ -0,0 +1,23 @@ +package events + +import ( + "fmt" + "strings" + + "github.com/sirupsen/logrus" +) + +// NewEventer creates an eventer based on the eventer type +func NewEventer(options EventerOptions) (Eventer, error) { + logrus.Debugf("Initializing event backend %s", options.EventerType) + switch strings.ToUpper(options.EventerType) { + case strings.ToUpper(LogFile.String()): + return EventLogFile{options}, nil + case strings.ToUpper(Null.String()): + return NewNullEventer(), nil + case strings.ToUpper(Memory.String()): + return NewMemoryEventer(), nil + default: + return nil, fmt.Errorf("unknown event logger type: %s", strings.ToUpper(options.EventerType)) + } +} diff --git a/libpod/events/events_unsupported.go b/libpod/events/events_unsupported.go index d766402a9..01031c225 100644 --- a/libpod/events/events_unsupported.go +++ b/libpod/events/events_unsupported.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build !linux && !freebsd +// +build !linux,!freebsd package events diff --git a/libpod/events/logfile.go b/libpod/events/logfile.go index c7dbf4850..519e16629 100644 --- a/libpod/events/logfile.go +++ b/libpod/events/logfile.go @@ -1,5 +1,5 @@ -//go:build linux -// +build linux +//go:build linux || freebsd +// +build linux freebsd package events diff --git a/libpod/healthcheck_unsupported.go b/libpod/healthcheck_unsupported.go new file mode 100644 index 000000000..92cd5d0a3 --- /dev/null +++ b/libpod/healthcheck_unsupported.go @@ -0,0 +1,25 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "context" + "errors" +) + +// createTimer systemd timers for healthchecks of a container +func (c *Container) createTimer() error { + return errors.New("not implemented (*Container) createTimer") +} + +// startTimer starts a systemd timer for the healthchecks +func (c *Container) startTimer() error { + return errors.New("not implemented (*Container) startTimer") +} + +// removeTransientFiles removes the systemd timer and unit files +// for the container +func (c *Container) removeTransientFiles(ctx context.Context) error { + return errors.New("not implemented (*Container) removeTransientFiles") +} diff --git a/libpod/info.go b/libpod/info.go index c4193b40d..1990dc044 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -5,27 +5,21 @@ import ( "bytes" "errors" "fmt" - "io/ioutil" "math" "os" - "os/exec" "runtime" - "strconv" "strings" "syscall" "time" "github.com/containers/buildah" - "github.com/containers/common/pkg/apparmor" - "github.com/containers/common/pkg/cgroups" - "github.com/containers/common/pkg/seccomp" + "github.com/containers/buildah/pkg/util" "github.com/containers/image/v5/pkg/sysregistriesv2" "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/libpod/linkmode" "github.com/containers/podman/v4/pkg/rootless" "github.com/containers/storage" "github.com/containers/storage/pkg/system" - "github.com/opencontainers/selinux/go-selinux" "github.com/sirupsen/logrus" ) @@ -91,7 +85,7 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) { hostDistributionInfo := r.GetHostDistributionInfo() - kv, err := readKernelVersion() + kv, err := util.ReadKernelVersion() if err != nil { return nil, fmt.Errorf("error reading kernel version: %w", err) } @@ -101,94 +95,30 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) { return nil, fmt.Errorf("error getting hostname: %w", err) } - seccompProfilePath, err := DefaultSeccompPath() - if err != nil { - return nil, fmt.Errorf("error getting Seccomp profile path: %w", err) - } - - // Cgroups version - unified, err := cgroups.IsCgroup2UnifiedMode() - if err != nil { - return nil, fmt.Errorf("error reading cgroups mode: %w", err) - } - - // Get Map of all available controllers - availableControllers, err := cgroups.GetAvailableControllers(nil, unified) - if err != nil { - return nil, fmt.Errorf("error getting available cgroup controllers: %w", err) - } cpuUtil, err := getCPUUtilization() if err != nil { return nil, err } info := define.HostInfo{ - Arch: runtime.GOARCH, - BuildahVersion: buildah.Version, - CgroupManager: r.config.Engine.CgroupManager, - CgroupControllers: availableControllers, - Linkmode: linkmode.Linkmode(), - CPUs: runtime.NumCPU(), - CPUUtilization: cpuUtil, - Distribution: hostDistributionInfo, - LogDriver: r.config.Containers.LogDriver, - EventLogger: r.eventer.String(), - Hostname: host, - IDMappings: define.IDMappings{}, - Kernel: kv, - MemFree: mi.MemFree, - MemTotal: mi.MemTotal, - NetworkBackend: r.config.Network.NetworkBackend, - OS: runtime.GOOS, - Security: define.SecurityInfo{ - AppArmorEnabled: apparmor.IsEnabled(), - DefaultCapabilities: strings.Join(r.config.Containers.DefaultCapabilities, ","), - Rootless: rootless.IsRootless(), - SECCOMPEnabled: seccomp.IsEnabled(), - SECCOMPProfilePath: seccompProfilePath, - SELinuxEnabled: selinux.GetEnabled(), - }, - Slirp4NetNS: define.SlirpInfo{}, - SwapFree: mi.SwapFree, - SwapTotal: mi.SwapTotal, - } - - cgroupVersion := "v1" - if unified { - cgroupVersion = "v2" - } - info.CgroupsVersion = cgroupVersion - - slirp4netnsPath := r.config.Engine.NetworkCmdPath - if slirp4netnsPath == "" { - slirp4netnsPath, _ = exec.LookPath("slirp4netns") - } - if slirp4netnsPath != "" { - version, err := programVersion(slirp4netnsPath) - if err != nil { - logrus.Warnf("Failed to retrieve program version for %s: %v", slirp4netnsPath, err) - } - program := define.SlirpInfo{ - Executable: slirp4netnsPath, - Package: packageVersion(slirp4netnsPath), - Version: version, - } - info.Slirp4NetNS = program - } - - if rootless.IsRootless() { - uidmappings, err := rootless.ReadMappingsProc("/proc/self/uid_map") - if err != nil { - return nil, fmt.Errorf("error reading uid mappings: %w", err) - } - gidmappings, err := rootless.ReadMappingsProc("/proc/self/gid_map") - if err != nil { - return nil, fmt.Errorf("error reading gid mappings: %w", err) - } - idmappings := define.IDMappings{ - GIDMap: gidmappings, - UIDMap: uidmappings, - } - info.IDMappings = idmappings + Arch: runtime.GOARCH, + BuildahVersion: buildah.Version, + Linkmode: linkmode.Linkmode(), + CPUs: runtime.NumCPU(), + CPUUtilization: cpuUtil, + Distribution: hostDistributionInfo, + LogDriver: r.config.Containers.LogDriver, + EventLogger: r.eventer.String(), + Hostname: host, + Kernel: kv, + MemFree: mi.MemFree, + MemTotal: mi.MemTotal, + NetworkBackend: r.config.Network.NetworkBackend, + OS: runtime.GOOS, + SwapFree: mi.SwapFree, + SwapTotal: mi.SwapTotal, + } + if err := r.setPlatformHostInfo(&info); err != nil { + return nil, err } conmonInfo, ociruntimeInfo, err := r.defaultOCIRuntime.RuntimeInfo() @@ -199,7 +129,7 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) { info.OCIRuntime = ociruntimeInfo } - duration, err := procUptime() + duration, err := util.ReadUptime() if err != nil { return nil, fmt.Errorf("error reading up time: %w", err) } @@ -329,31 +259,6 @@ func (r *Runtime) storeInfo() (*define.StoreInfo, error) { return &info, nil } -func readKernelVersion() (string, error) { - buf, err := ioutil.ReadFile("/proc/version") - if err != nil { - return "", err - } - f := bytes.Fields(buf) - if len(f) < 3 { - return string(bytes.TrimSpace(buf)), nil - } - return string(f[2]), nil -} - -func procUptime() (time.Duration, error) { - var zero time.Duration - buf, err := ioutil.ReadFile("/proc/uptime") - if err != nil { - return zero, err - } - f := bytes.Fields(buf) - if len(f) < 1 { - return zero, errors.New("unable to parse uptime from /proc/uptime") - } - return time.ParseDuration(string(f[0]) + "s") -} - // GetHostDistributionInfo returns a map containing the host's distribution and version func (r *Runtime) GetHostDistributionInfo() define.DistributionInfo { // Populate values in case we cannot find the values @@ -385,43 +290,3 @@ func (r *Runtime) GetHostDistributionInfo() define.DistributionInfo { } return dist } - -// getCPUUtilization Returns a CPUUsage object that summarizes CPU -// usage for userspace, system, and idle time. -func getCPUUtilization() (*define.CPUUsage, error) { - f, err := os.Open("/proc/stat") - if err != nil { - return nil, err - } - defer f.Close() - scanner := bufio.NewScanner(f) - // Read first line of /proc/stat that has entries for system ("cpu" line) - for scanner.Scan() { - break - } - // column 1 is user, column 3 is system, column 4 is idle - stats := strings.Fields(scanner.Text()) - return statToPercent(stats) -} - -func statToPercent(stats []string) (*define.CPUUsage, error) { - userTotal, err := strconv.ParseFloat(stats[1], 64) - if err != nil { - return nil, fmt.Errorf("unable to parse user value %q: %w", stats[1], err) - } - systemTotal, err := strconv.ParseFloat(stats[3], 64) - if err != nil { - return nil, fmt.Errorf("unable to parse system value %q: %w", stats[3], err) - } - idleTotal, err := strconv.ParseFloat(stats[4], 64) - if err != nil { - return nil, fmt.Errorf("unable to parse idle value %q: %w", stats[4], err) - } - total := userTotal + systemTotal + idleTotal - s := define.CPUUsage{ - UserPercent: math.Round((userTotal/total*100)*100) / 100, - SystemPercent: math.Round((systemTotal/total*100)*100) / 100, - IdlePercent: math.Round((idleTotal/total*100)*100) / 100, - } - return &s, nil -} diff --git a/libpod/info_freebsd.go b/libpod/info_freebsd.go new file mode 100644 index 000000000..ef7b6817c --- /dev/null +++ b/libpod/info_freebsd.go @@ -0,0 +1,40 @@ +package libpod + +import ( + "fmt" + "unsafe" + + "github.com/containers/podman/v4/libpod/define" + "golang.org/x/sys/unix" +) + +func (r *Runtime) setPlatformHostInfo(info *define.HostInfo) error { + return nil +} + +func timeToPercent(time uint64, total uint64) float64 { + return 100.0 * float64(time) / float64(total) +} + +// getCPUUtilization Returns a CPUUsage object that summarizes CPU +// usage for userspace, system, and idle time. +func getCPUUtilization() (*define.CPUUsage, error) { + buf, err := unix.SysctlRaw("kern.cp_time") + if err != nil { + return nil, fmt.Errorf("error reading sysctl kern.cp_time: %w", err) + } + + var total uint64 = 0 + var times [unix.CPUSTATES]uint64 + + for i := 0; i < unix.CPUSTATES; i++ { + val := *(*uint64)(unsafe.Pointer(&buf[8*i])) + times[i] = val + total += val + } + return &define.CPUUsage{ + UserPercent: timeToPercent(times[unix.CP_USER], total), + SystemPercent: timeToPercent(times[unix.CP_SYS], total), + IdlePercent: timeToPercent(times[unix.CP_IDLE], total), + }, nil +} diff --git a/libpod/info_linux.go b/libpod/info_linux.go new file mode 100644 index 000000000..801dcdb43 --- /dev/null +++ b/libpod/info_linux.go @@ -0,0 +1,132 @@ +package libpod + +import ( + "bufio" + "fmt" + "math" + "os" + "os/exec" + "strconv" + "strings" + + "github.com/containers/common/pkg/apparmor" + "github.com/containers/common/pkg/cgroups" + "github.com/containers/common/pkg/seccomp" + "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/pkg/rootless" + "github.com/opencontainers/selinux/go-selinux" + "github.com/sirupsen/logrus" +) + +func (r *Runtime) setPlatformHostInfo(info *define.HostInfo) error { + seccompProfilePath, err := DefaultSeccompPath() + if err != nil { + return fmt.Errorf("error getting Seccomp profile path: %w", err) + } + + // Cgroups version + unified, err := cgroups.IsCgroup2UnifiedMode() + if err != nil { + return fmt.Errorf("error reading cgroups mode: %w", err) + } + + // Get Map of all available controllers + availableControllers, err := cgroups.GetAvailableControllers(nil, unified) + if err != nil { + return fmt.Errorf("error getting available cgroup controllers: %w", err) + } + + info.CgroupManager = r.config.Engine.CgroupManager + info.CgroupControllers = availableControllers + info.IDMappings = define.IDMappings{} + info.Security = define.SecurityInfo{ + AppArmorEnabled: apparmor.IsEnabled(), + DefaultCapabilities: strings.Join(r.config.Containers.DefaultCapabilities, ","), + Rootless: rootless.IsRootless(), + SECCOMPEnabled: seccomp.IsEnabled(), + SECCOMPProfilePath: seccompProfilePath, + SELinuxEnabled: selinux.GetEnabled(), + } + info.Slirp4NetNS = define.SlirpInfo{} + + cgroupVersion := "v1" + if unified { + cgroupVersion = "v2" + } + info.CgroupsVersion = cgroupVersion + + slirp4netnsPath := r.config.Engine.NetworkCmdPath + if slirp4netnsPath == "" { + slirp4netnsPath, _ = exec.LookPath("slirp4netns") + } + if slirp4netnsPath != "" { + version, err := programVersion(slirp4netnsPath) + if err != nil { + logrus.Warnf("Failed to retrieve program version for %s: %v", slirp4netnsPath, err) + } + program := define.SlirpInfo{ + Executable: slirp4netnsPath, + Package: packageVersion(slirp4netnsPath), + Version: version, + } + info.Slirp4NetNS = program + } + + if rootless.IsRootless() { + uidmappings, err := rootless.ReadMappingsProc("/proc/self/uid_map") + if err != nil { + return fmt.Errorf("error reading uid mappings: %w", err) + } + gidmappings, err := rootless.ReadMappingsProc("/proc/self/gid_map") + if err != nil { + return fmt.Errorf("error reading gid mappings: %w", err) + } + idmappings := define.IDMappings{ + GIDMap: gidmappings, + UIDMap: uidmappings, + } + info.IDMappings = idmappings + } + + return nil +} + +func statToPercent(stats []string) (*define.CPUUsage, error) { + userTotal, err := strconv.ParseFloat(stats[1], 64) + if err != nil { + return nil, fmt.Errorf("unable to parse user value %q: %w", stats[1], err) + } + systemTotal, err := strconv.ParseFloat(stats[3], 64) + if err != nil { + return nil, fmt.Errorf("unable to parse system value %q: %w", stats[3], err) + } + idleTotal, err := strconv.ParseFloat(stats[4], 64) + if err != nil { + return nil, fmt.Errorf("unable to parse idle value %q: %w", stats[4], err) + } + total := userTotal + systemTotal + idleTotal + s := define.CPUUsage{ + UserPercent: math.Round((userTotal/total*100)*100) / 100, + SystemPercent: math.Round((systemTotal/total*100)*100) / 100, + IdlePercent: math.Round((idleTotal/total*100)*100) / 100, + } + return &s, nil +} + +// getCPUUtilization Returns a CPUUsage object that summarizes CPU +// usage for userspace, system, and idle time. +func getCPUUtilization() (*define.CPUUsage, error) { + f, err := os.Open("/proc/stat") + if err != nil { + return nil, err + } + defer f.Close() + scanner := bufio.NewScanner(f) + // Read first line of /proc/stat that has entries for system ("cpu" line) + for scanner.Scan() { + break + } + // column 1 is user, column 3 is system, column 4 is idle + stats := strings.Fields(scanner.Text()) + return statToPercent(stats) +} diff --git a/libpod/info_unsupported.go b/libpod/info_unsupported.go new file mode 100644 index 000000000..0aed51247 --- /dev/null +++ b/libpod/info_unsupported.go @@ -0,0 +1,14 @@ +//go:build !linux && !freebsd +// +build !linux,!freebsd + +package libpod + +import ( + "errors" + + "github.com/containers/podman/v4/libpod/define" +) + +func (r *Runtime) info() (*define.Info, error) { + return nil, errors.New("not implemented (*Runtime) info") +} diff --git a/libpod/kube.go b/libpod/kube.go index 8c09a6bb5..a0fb52973 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -267,6 +267,8 @@ func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) (Y } service.Spec = serviceSpec service.ObjectMeta = pod.ObjectMeta + // Reset the annotations for the service as the pod annotations are not needed for the service + service.ObjectMeta.Annotations = nil tm := v12.TypeMeta{ Kind: "Service", APIVersion: pod.TypeMeta.APIVersion, diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index c05796768..c10c3c0b2 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -1357,6 +1357,11 @@ func (c *Container) NetworkConnect(nameOrID, netName string, netOpts types.PerNe } if err := c.runtime.state.NetworkConnect(c, netName, netOpts); err != nil { + // Docker compat: treat requests to attach already attached networks as a no-op, ignoring opts + if errors.Is(err, define.ErrNetworkConnected) && c.ensureState(define.ContainerStateConfigured) { + return nil + } + return err } c.newNetworkEvent(events.NetworkConnect, netName) diff --git a/libpod/networking_unsupported.go b/libpod/networking_unsupported.go new file mode 100644 index 000000000..76ffabb5e --- /dev/null +++ b/libpod/networking_unsupported.go @@ -0,0 +1,86 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "errors" + "path/filepath" + + "github.com/containers/common/libnetwork/types" + "github.com/containers/podman/v4/libpod/define" + "github.com/containers/storage/pkg/lockfile" +) + +type RootlessNetNS struct { + dir string + Lock lockfile.Locker +} + +// ocicniPortsToNetTypesPorts convert the old port format to the new one +// while deduplicating ports into ranges +func ocicniPortsToNetTypesPorts(ports []types.OCICNIPortMapping) []types.PortMapping { + return []types.PortMapping{} +} + +func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, error) { + return nil, errors.New("not implemented (*Container) getContainerNetworkInfo") +} + +func (c *Container) setupRootlessNetwork() error { + return errors.New("not implemented (*Container) setupRootlessNetwork") +} + +func (r *Runtime) setupNetNS(ctr *Container) error { + return errors.New("not implemented (*Runtime) setupNetNS") +} + +// normalizeNetworkName takes a network name, a partial or a full network ID and returns the network name. +// If the network is not found a errors is returned. +func (r *Runtime) normalizeNetworkName(nameOrID string) (string, error) { + return "", errors.New("not implemented (*Runtime) normalizeNetworkName") +} + +// DisconnectContainerFromNetwork removes a container from its CNI network +func (r *Runtime) DisconnectContainerFromNetwork(nameOrID, netName string, force bool) error { + return errors.New("not implemented (*Runtime) DisconnectContainerFromNetwork") +} + +// ConnectContainerToNetwork connects a container to a CNI network +func (r *Runtime) ConnectContainerToNetwork(nameOrID, netName string, netOpts types.PerNetworkOptions) error { + return errors.New("not implemented (*Runtime) ConnectContainerToNetwork") +} + +// getPath will join the given path to the rootless netns dir +func (r *RootlessNetNS) getPath(path string) string { + return filepath.Join(r.dir, path) +} + +// Do - run the given function in the rootless netns. +// It does not lock the rootlessCNI lock, the caller +// should only lock when needed, e.g. for cni operations. +func (r *RootlessNetNS) Do(toRun func() error) error { + return errors.New("not implemented (*RootlessNetNS) Do") +} + +// Cleanup the rootless network namespace if needed. +// It checks if we have running containers with the bridge network mode. +// Cleanup() expects that r.Lock is locked +func (r *RootlessNetNS) Cleanup(runtime *Runtime) error { + return errors.New("not implemented (*RootlessNetNS) Cleanup") +} + +// GetRootlessNetNs returns the rootless netns object. If create is set to true +// the rootless network namespace will be created if it does not exists already. +// If called as root it returns always nil. +// On success the returned RootlessCNI lock is locked and must be unlocked by the caller. +func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) { + return nil, errors.New("not implemented (*Runtime) GetRootlessNetNs") +} + +// convertPortMappings will remove the HostIP part from the ports when running inside podman machine. +// This is need because a HostIP of 127.0.0.1 would now allow the gvproxy forwarder to reach to open ports. +// For machine the HostIP must only be used by gvproxy and never in the VM. +func (c *Container) convertPortMappings() []types.PortMapping { + return []types.PortMapping{} +} diff --git a/libpod/oci_conmon_attach_common.go b/libpod/oci_conmon_attach_common.go new file mode 100644 index 000000000..a9e9b2bb5 --- /dev/null +++ b/libpod/oci_conmon_attach_common.go @@ -0,0 +1,305 @@ +//go:build linux || freebsd +// +build linux freebsd + +package libpod + +import ( + "errors" + "fmt" + "io" + "net" + "os" + "path/filepath" + "syscall" + + "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/resize" + "github.com/containers/common/pkg/util" + "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/pkg/errorhandling" + "github.com/moby/term" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +/* Sync with stdpipe_t in conmon.c */ +const ( + AttachPipeStdin = 1 + AttachPipeStdout = 2 + AttachPipeStderr = 3 +) + +// Attach to the given container. +// Does not check if state is appropriate. +// started is only required if startContainer is true. +func (r *ConmonOCIRuntime) Attach(c *Container, params *AttachOptions) error { + passthrough := c.LogDriver() == define.PassthroughLogging + + if params == nil || params.Streams == nil { + return fmt.Errorf("must provide parameters to Attach: %w", define.ErrInternal) + } + + if !params.Streams.AttachOutput && !params.Streams.AttachError && !params.Streams.AttachInput && !passthrough { + return fmt.Errorf("must provide at least one stream to attach to: %w", define.ErrInvalidArg) + } + if params.Start && params.Started == nil { + return fmt.Errorf("started chan not passed when startContainer set: %w", define.ErrInternal) + } + + keys := config.DefaultDetachKeys + if params.DetachKeys != nil { + keys = *params.DetachKeys + } + + detachKeys, err := processDetachKeys(keys) + if err != nil { + return err + } + + var conn *net.UnixConn + if !passthrough { + logrus.Debugf("Attaching to container %s", c.ID()) + + // If we have a resize, do it. + if params.InitialSize != nil { + if err := r.AttachResize(c, *params.InitialSize); err != nil { + return err + } + } + + attachSock, err := c.AttachSocketPath() + if err != nil { + return err + } + + conn, err = openUnixSocket(attachSock) + if err != nil { + return fmt.Errorf("failed to connect to container's attach socket: %v: %w", attachSock, err) + } + defer func() { + if err := conn.Close(); err != nil { + logrus.Errorf("unable to close socket: %q", err) + } + }() + } + + // If starting was requested, start the container and notify when that's + // done. + if params.Start { + if err := c.start(); err != nil { + return err + } + params.Started <- true + } + + if passthrough { + return nil + } + + receiveStdoutError, stdinDone := setupStdioChannels(params.Streams, conn, detachKeys) + if params.AttachReady != nil { + params.AttachReady <- true + } + return readStdio(conn, params.Streams, receiveStdoutError, stdinDone) +} + +// Attach to the given container's exec session +// attachFd and startFd must be open file descriptors +// attachFd must be the output side of the fd. attachFd is used for two things: +// conmon will first send a nonce value across the pipe indicating it has set up its side of the console socket +// this ensures attachToExec gets all of the output of the called process +// conmon will then send the exit code of the exec process, or an error in the exec session +// startFd must be the input side of the fd. +// newSize resizes the tty to this size before the process is started, must be nil if the exec session has no tty +// conmon will wait to start the exec session until the parent process has set up the console socket. +// Once attachToExec successfully attaches to the console socket, the child conmon process responsible for calling runtime exec +// will read from the output side of start fd, thus learning to start the child process. +// Thus, the order goes as follow: +// 1. conmon parent process sets up its console socket. sends on attachFd +// 2. attachToExec attaches to the console socket after reading on attachFd and resizes the tty +// 3. child waits on startFd for attachToExec to attach to said console socket +// 4. attachToExec sends on startFd, signalling it has attached to the socket and child is ready to go +// 5. child receives on startFd, runs the runtime exec command +// attachToExec is responsible for closing startFd and attachFd +func (c *Container) attachToExec(streams *define.AttachStreams, keys *string, sessionID string, startFd, attachFd *os.File, newSize *resize.TerminalSize) error { + if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput { + return fmt.Errorf("must provide at least one stream to attach to: %w", define.ErrInvalidArg) + } + if startFd == nil || attachFd == nil { + return fmt.Errorf("start sync pipe and attach sync pipe must be defined for exec attach: %w", define.ErrInvalidArg) + } + + defer errorhandling.CloseQuiet(startFd) + defer errorhandling.CloseQuiet(attachFd) + + detachString := config.DefaultDetachKeys + if keys != nil { + detachString = *keys + } + detachKeys, err := processDetachKeys(detachString) + if err != nil { + return err + } + + logrus.Debugf("Attaching to container %s exec session %s", c.ID(), sessionID) + + // set up the socket path, such that it is the correct length and location for exec + sockPath, err := c.execAttachSocketPath(sessionID) + if err != nil { + return err + } + + // 2: read from attachFd that the parent process has set up the console socket + if _, err := readConmonPipeData(c.ociRuntime.Name(), attachFd, ""); err != nil { + return err + } + + // resize before we start the container process + if newSize != nil { + err = c.ociRuntime.ExecAttachResize(c, sessionID, *newSize) + if err != nil { + logrus.Warnf("Resize failed: %v", err) + } + } + + // 2: then attach + conn, err := openUnixSocket(sockPath) + if err != nil { + return fmt.Errorf("failed to connect to container's attach socket: %v: %w", sockPath, err) + } + defer func() { + if err := conn.Close(); err != nil { + logrus.Errorf("Unable to close socket: %q", err) + } + }() + + // start listening on stdio of the process + receiveStdoutError, stdinDone := setupStdioChannels(streams, conn, detachKeys) + + // 4: send start message to child + if err := writeConmonPipeData(startFd); err != nil { + return err + } + + return readStdio(conn, streams, receiveStdoutError, stdinDone) +} + +func processDetachKeys(keys string) ([]byte, error) { + // Check the validity of the provided keys first + if len(keys) == 0 { + return []byte{}, nil + } + detachKeys, err := term.ToBytes(keys) + if err != nil { + return nil, fmt.Errorf("invalid detach keys: %w", err) + } + return detachKeys, nil +} + +func registerResizeFunc(r <-chan resize.TerminalSize, bundlePath string) { + resize.HandleResizing(r, func(size resize.TerminalSize) { + controlPath := filepath.Join(bundlePath, "ctl") + controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0) + if err != nil { + logrus.Debugf("Could not open ctl file: %v", err) + return + } + defer controlFile.Close() + + logrus.Debugf("Received a resize event: %+v", size) + if _, err = fmt.Fprintf(controlFile, "%d %d %d\n", 1, size.Height, size.Width); err != nil { + logrus.Warnf("Failed to write to control file to resize terminal: %v", err) + } + }) +} + +func setupStdioChannels(streams *define.AttachStreams, conn *net.UnixConn, detachKeys []byte) (chan error, chan error) { + receiveStdoutError := make(chan error) + go func() { + receiveStdoutError <- redirectResponseToOutputStreams(streams.OutputStream, streams.ErrorStream, streams.AttachOutput, streams.AttachError, conn) + }() + + stdinDone := make(chan error) + go func() { + var err error + if streams.AttachInput { + _, err = util.CopyDetachable(conn, streams.InputStream, detachKeys) + } + stdinDone <- err + }() + + return receiveStdoutError, stdinDone +} + +func redirectResponseToOutputStreams(outputStream, errorStream io.Writer, writeOutput, writeError bool, conn io.Reader) error { + var err error + buf := make([]byte, 8192+1) /* Sync with conmon STDIO_BUF_SIZE */ + for { + nr, er := conn.Read(buf) + if nr > 0 { + var dst io.Writer + var doWrite bool + switch buf[0] { + case AttachPipeStdout: + dst = outputStream + doWrite = writeOutput + case AttachPipeStderr: + dst = errorStream + doWrite = writeError + default: + logrus.Infof("Received unexpected attach type %+d", buf[0]) + } + if dst == nil { + return errors.New("output destination cannot be nil") + } + + if doWrite { + nw, ew := dst.Write(buf[1:nr]) + if ew != nil { + err = ew + break + } + if nr != nw+1 { + err = io.ErrShortWrite + break + } + } + } + if errors.Is(er, io.EOF) || errors.Is(er, syscall.ECONNRESET) { + break + } + if er != nil { + err = er + break + } + } + return err +} + +func readStdio(conn *net.UnixConn, streams *define.AttachStreams, receiveStdoutError, stdinDone chan error) error { + var err error + select { + case err = <-receiveStdoutError: + if err := conn.CloseWrite(); err != nil { + logrus.Errorf("Failed to close stdin: %v", err) + } + return err + case err = <-stdinDone: + if err == define.ErrDetach { + if err := conn.CloseWrite(); err != nil { + logrus.Errorf("Failed to close stdin: %v", err) + } + return err + } + if err == nil { + // copy stdin is done, close it + if connErr := conn.CloseWrite(); connErr != nil { + logrus.Errorf("Unable to close conn: %v", connErr) + } + } + if streams.AttachOutput || streams.AttachError { + return <-receiveStdoutError + } + } + return nil +} diff --git a/libpod/oci_conmon_attach_freebsd.go b/libpod/oci_conmon_attach_freebsd.go new file mode 100644 index 000000000..de0054381 --- /dev/null +++ b/libpod/oci_conmon_attach_freebsd.go @@ -0,0 +1,21 @@ +package libpod + +import ( + "net" + "os" + "path/filepath" +) + +func openUnixSocket(path string) (*net.UnixConn, error) { + // socket paths can be too long to fit into a sockaddr_un so we create a shorter symlink. + tmpdir, err := os.MkdirTemp("", "podman") + if err != nil { + return nil, err + } + defer os.RemoveAll(tmpdir) + tmpsockpath := filepath.Join(tmpdir, "sock") + if err := os.Symlink(path, tmpsockpath); err != nil { + return nil, err + } + return net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: tmpsockpath, Net: "unixpacket"}) +} diff --git a/libpod/oci_conmon_attach_linux.go b/libpod/oci_conmon_attach_linux.go index aa55aa6f5..f1aa89d3e 100644 --- a/libpod/oci_conmon_attach_linux.go +++ b/libpod/oci_conmon_attach_linux.go @@ -1,34 +1,12 @@ -//go:build linux -// +build linux - package libpod import ( - "errors" "fmt" - "io" "net" - "os" - "path/filepath" - "syscall" - "github.com/containers/common/pkg/config" - "github.com/containers/common/pkg/resize" - "github.com/containers/common/pkg/util" - "github.com/containers/podman/v4/libpod/define" - "github.com/containers/podman/v4/pkg/errorhandling" - "github.com/moby/term" - "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) -/* Sync with stdpipe_t in conmon.c */ -const ( - AttachPipeStdin = 1 - AttachPipeStdout = 2 - AttachPipeStderr = 3 -) - func openUnixSocket(path string) (*net.UnixConn, error) { fd, err := unix.Open(path, unix.O_PATH, 0) if err != nil { @@ -37,278 +15,3 @@ func openUnixSocket(path string) (*net.UnixConn, error) { defer unix.Close(fd) return net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: fmt.Sprintf("/proc/self/fd/%d", fd), Net: "unixpacket"}) } - -// Attach to the given container. -// Does not check if state is appropriate. -// started is only required if startContainer is true. -func (r *ConmonOCIRuntime) Attach(c *Container, params *AttachOptions) error { - passthrough := c.LogDriver() == define.PassthroughLogging - - if params == nil || params.Streams == nil { - return fmt.Errorf("must provide parameters to Attach: %w", define.ErrInternal) - } - - if !params.Streams.AttachOutput && !params.Streams.AttachError && !params.Streams.AttachInput && !passthrough { - return fmt.Errorf("must provide at least one stream to attach to: %w", define.ErrInvalidArg) - } - if params.Start && params.Started == nil { - return fmt.Errorf("started chan not passed when startContainer set: %w", define.ErrInternal) - } - - keys := config.DefaultDetachKeys - if params.DetachKeys != nil { - keys = *params.DetachKeys - } - - detachKeys, err := processDetachKeys(keys) - if err != nil { - return err - } - - var conn *net.UnixConn - if !passthrough { - logrus.Debugf("Attaching to container %s", c.ID()) - - // If we have a resize, do it. - if params.InitialSize != nil { - if err := r.AttachResize(c, *params.InitialSize); err != nil { - return err - } - } - - attachSock, err := c.AttachSocketPath() - if err != nil { - return err - } - - conn, err = openUnixSocket(attachSock) - if err != nil { - return fmt.Errorf("failed to connect to container's attach socket: %v: %w", attachSock, err) - } - defer func() { - if err := conn.Close(); err != nil { - logrus.Errorf("unable to close socket: %q", err) - } - }() - } - - // If starting was requested, start the container and notify when that's - // done. - if params.Start { - if err := c.start(); err != nil { - return err - } - params.Started <- true - } - - if passthrough { - return nil - } - - receiveStdoutError, stdinDone := setupStdioChannels(params.Streams, conn, detachKeys) - if params.AttachReady != nil { - params.AttachReady <- true - } - return readStdio(conn, params.Streams, receiveStdoutError, stdinDone) -} - -// Attach to the given container's exec session -// attachFd and startFd must be open file descriptors -// attachFd must be the output side of the fd. attachFd is used for two things: -// conmon will first send a nonce value across the pipe indicating it has set up its side of the console socket -// this ensures attachToExec gets all of the output of the called process -// conmon will then send the exit code of the exec process, or an error in the exec session -// startFd must be the input side of the fd. -// newSize resizes the tty to this size before the process is started, must be nil if the exec session has no tty -// conmon will wait to start the exec session until the parent process has set up the console socket. -// Once attachToExec successfully attaches to the console socket, the child conmon process responsible for calling runtime exec -// will read from the output side of start fd, thus learning to start the child process. -// Thus, the order goes as follow: -// 1. conmon parent process sets up its console socket. sends on attachFd -// 2. attachToExec attaches to the console socket after reading on attachFd and resizes the tty -// 3. child waits on startFd for attachToExec to attach to said console socket -// 4. attachToExec sends on startFd, signalling it has attached to the socket and child is ready to go -// 5. child receives on startFd, runs the runtime exec command -// attachToExec is responsible for closing startFd and attachFd -func (c *Container) attachToExec(streams *define.AttachStreams, keys *string, sessionID string, startFd, attachFd *os.File, newSize *resize.TerminalSize) error { - if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput { - return fmt.Errorf("must provide at least one stream to attach to: %w", define.ErrInvalidArg) - } - if startFd == nil || attachFd == nil { - return fmt.Errorf("start sync pipe and attach sync pipe must be defined for exec attach: %w", define.ErrInvalidArg) - } - - defer errorhandling.CloseQuiet(startFd) - defer errorhandling.CloseQuiet(attachFd) - - detachString := config.DefaultDetachKeys - if keys != nil { - detachString = *keys - } - detachKeys, err := processDetachKeys(detachString) - if err != nil { - return err - } - - logrus.Debugf("Attaching to container %s exec session %s", c.ID(), sessionID) - - // set up the socket path, such that it is the correct length and location for exec - sockPath, err := c.execAttachSocketPath(sessionID) - if err != nil { - return err - } - - // 2: read from attachFd that the parent process has set up the console socket - if _, err := readConmonPipeData(c.ociRuntime.Name(), attachFd, ""); err != nil { - return err - } - - // resize before we start the container process - if newSize != nil { - err = c.ociRuntime.ExecAttachResize(c, sessionID, *newSize) - if err != nil { - logrus.Warnf("Resize failed: %v", err) - } - } - - // 2: then attach - conn, err := openUnixSocket(sockPath) - if err != nil { - return fmt.Errorf("failed to connect to container's attach socket: %v: %w", sockPath, err) - } - defer func() { - if err := conn.Close(); err != nil { - logrus.Errorf("Unable to close socket: %q", err) - } - }() - - // start listening on stdio of the process - receiveStdoutError, stdinDone := setupStdioChannels(streams, conn, detachKeys) - - // 4: send start message to child - if err := writeConmonPipeData(startFd); err != nil { - return err - } - - return readStdio(conn, streams, receiveStdoutError, stdinDone) -} - -func processDetachKeys(keys string) ([]byte, error) { - // Check the validity of the provided keys first - if len(keys) == 0 { - return []byte{}, nil - } - detachKeys, err := term.ToBytes(keys) - if err != nil { - return nil, fmt.Errorf("invalid detach keys: %w", err) - } - return detachKeys, nil -} - -func registerResizeFunc(r <-chan resize.TerminalSize, bundlePath string) { - resize.HandleResizing(r, func(size resize.TerminalSize) { - controlPath := filepath.Join(bundlePath, "ctl") - controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0) - if err != nil { - logrus.Debugf("Could not open ctl file: %v", err) - return - } - defer controlFile.Close() - - logrus.Debugf("Received a resize event: %+v", size) - if _, err = fmt.Fprintf(controlFile, "%d %d %d\n", 1, size.Height, size.Width); err != nil { - logrus.Warnf("Failed to write to control file to resize terminal: %v", err) - } - }) -} - -func setupStdioChannels(streams *define.AttachStreams, conn *net.UnixConn, detachKeys []byte) (chan error, chan error) { - receiveStdoutError := make(chan error) - go func() { - receiveStdoutError <- redirectResponseToOutputStreams(streams.OutputStream, streams.ErrorStream, streams.AttachOutput, streams.AttachError, conn) - }() - - stdinDone := make(chan error) - go func() { - var err error - if streams.AttachInput { - _, err = util.CopyDetachable(conn, streams.InputStream, detachKeys) - } - stdinDone <- err - }() - - return receiveStdoutError, stdinDone -} - -func redirectResponseToOutputStreams(outputStream, errorStream io.Writer, writeOutput, writeError bool, conn io.Reader) error { - var err error - buf := make([]byte, 8192+1) /* Sync with conmon STDIO_BUF_SIZE */ - for { - nr, er := conn.Read(buf) - if nr > 0 { - var dst io.Writer - var doWrite bool - switch buf[0] { - case AttachPipeStdout: - dst = outputStream - doWrite = writeOutput - case AttachPipeStderr: - dst = errorStream - doWrite = writeError - default: - logrus.Infof("Received unexpected attach type %+d", buf[0]) - } - if dst == nil { - return errors.New("output destination cannot be nil") - } - - if doWrite { - nw, ew := dst.Write(buf[1:nr]) - if ew != nil { - err = ew - break - } - if nr != nw+1 { - err = io.ErrShortWrite - break - } - } - } - if errors.Is(er, io.EOF) || errors.Is(er, syscall.ECONNRESET) { - break - } - if er != nil { - err = er - break - } - } - return err -} - -func readStdio(conn *net.UnixConn, streams *define.AttachStreams, receiveStdoutError, stdinDone chan error) error { - var err error - select { - case err = <-receiveStdoutError: - if err := conn.CloseWrite(); err != nil { - logrus.Errorf("Failed to close stdin: %v", err) - } - return err - case err = <-stdinDone: - if err == define.ErrDetach { - if err := conn.CloseWrite(); err != nil { - logrus.Errorf("Failed to close stdin: %v", err) - } - return err - } - if err == nil { - // copy stdin is done, close it - if connErr := conn.CloseWrite(); connErr != nil { - logrus.Errorf("Unable to close conn: %v", connErr) - } - } - if streams.AttachOutput || streams.AttachError { - return <-receiveStdoutError - } - } - return nil -} diff --git a/libpod/oci_conmon_common.go b/libpod/oci_conmon_common.go new file mode 100644 index 000000000..b96f92d3a --- /dev/null +++ b/libpod/oci_conmon_common.go @@ -0,0 +1,1591 @@ +//go:build linux || freebsd +// +build linux freebsd + +package libpod + +import ( + "bufio" + "bytes" + "context" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "net/http" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "sync" + "syscall" + "text/template" + "time" + + "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/resize" + cutil "github.com/containers/common/pkg/util" + conmonConfig "github.com/containers/conmon/runner/config" + "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/libpod/logs" + "github.com/containers/podman/v4/pkg/checkpoint/crutils" + "github.com/containers/podman/v4/pkg/errorhandling" + "github.com/containers/podman/v4/pkg/rootless" + "github.com/containers/podman/v4/pkg/specgenutil" + "github.com/containers/podman/v4/pkg/util" + "github.com/containers/podman/v4/utils" + "github.com/containers/storage/pkg/homedir" + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +const ( + // This is Conmon's STDIO_BUF_SIZE. I don't believe we have access to it + // directly from the Go code, so const it here + // Important: The conmon attach socket uses an extra byte at the beginning of each + // message to specify the STREAM so we have to increase the buffer size by one + bufferSize = conmonConfig.BufSize + 1 +) + +// ConmonOCIRuntime is an OCI runtime managed by Conmon. +// TODO: Make all calls to OCI runtime have a timeout. +type ConmonOCIRuntime struct { + name string + path string + conmonPath string + conmonEnv []string + tmpDir string + exitsDir string + logSizeMax int64 + noPivot bool + reservePorts bool + runtimeFlags []string + supportsJSON bool + supportsKVM bool + supportsNoCgroups bool + enableKeyring bool +} + +// Make a new Conmon-based OCI runtime with the given options. +// Conmon will wrap the given OCI runtime, which can be `runc`, `crun`, or +// any runtime with a runc-compatible CLI. +// The first path that points to a valid executable will be used. +// Deliberately private. Someone should not be able to construct this outside of +// libpod. +func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeFlags []string, runtimeCfg *config.Config) (OCIRuntime, error) { + if name == "" { + return nil, fmt.Errorf("the OCI runtime must be provided a non-empty name: %w", define.ErrInvalidArg) + } + + // Make lookup tables for runtime support + supportsJSON := make(map[string]bool, len(runtimeCfg.Engine.RuntimeSupportsJSON)) + supportsNoCgroups := make(map[string]bool, len(runtimeCfg.Engine.RuntimeSupportsNoCgroups)) + supportsKVM := make(map[string]bool, len(runtimeCfg.Engine.RuntimeSupportsKVM)) + for _, r := range runtimeCfg.Engine.RuntimeSupportsJSON { + supportsJSON[r] = true + } + for _, r := range runtimeCfg.Engine.RuntimeSupportsNoCgroups { + supportsNoCgroups[r] = true + } + for _, r := range runtimeCfg.Engine.RuntimeSupportsKVM { + supportsKVM[r] = true + } + + runtime := new(ConmonOCIRuntime) + runtime.name = name + runtime.conmonPath = conmonPath + runtime.runtimeFlags = runtimeFlags + + runtime.conmonEnv = runtimeCfg.Engine.ConmonEnvVars + runtime.tmpDir = runtimeCfg.Engine.TmpDir + runtime.logSizeMax = runtimeCfg.Containers.LogSizeMax + runtime.noPivot = runtimeCfg.Engine.NoPivotRoot + runtime.reservePorts = runtimeCfg.Engine.EnablePortReservation + runtime.enableKeyring = runtimeCfg.Containers.EnableKeyring + + // TODO: probe OCI runtime for feature and enable automatically if + // available. + + base := filepath.Base(name) + runtime.supportsJSON = supportsJSON[base] + runtime.supportsNoCgroups = supportsNoCgroups[base] + runtime.supportsKVM = supportsKVM[base] + + foundPath := false + for _, path := range paths { + stat, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + continue + } + return nil, fmt.Errorf("cannot stat OCI runtime %s path: %w", name, err) + } + if !stat.Mode().IsRegular() { + continue + } + foundPath = true + logrus.Tracef("found runtime %q", path) + runtime.path = path + break + } + + // Search the $PATH as last fallback + if !foundPath { + if foundRuntime, err := exec.LookPath(name); err == nil { + foundPath = true + runtime.path = foundRuntime + logrus.Debugf("using runtime %q from $PATH: %q", name, foundRuntime) + } + } + + if !foundPath { + return nil, fmt.Errorf("no valid executable found for OCI runtime %s: %w", name, define.ErrInvalidArg) + } + + runtime.exitsDir = filepath.Join(runtime.tmpDir, "exits") + + // Create the exit files and attach sockets directories + if err := os.MkdirAll(runtime.exitsDir, 0750); err != nil { + // The directory is allowed to exist + if !os.IsExist(err) { + return nil, fmt.Errorf("error creating OCI runtime exit files directory: %w", err) + } + } + return runtime, nil +} + +// Name returns the name of the runtime being wrapped by Conmon. +func (r *ConmonOCIRuntime) Name() string { + return r.name +} + +// Path returns the path of the OCI runtime being wrapped by Conmon. +func (r *ConmonOCIRuntime) Path() string { + return r.path +} + +// hasCurrentUserMapped checks whether the current user is mapped inside the container user namespace +func hasCurrentUserMapped(ctr *Container) bool { + if len(ctr.config.IDMappings.UIDMap) == 0 && len(ctr.config.IDMappings.GIDMap) == 0 { + return true + } + uid := os.Geteuid() + for _, m := range ctr.config.IDMappings.UIDMap { + if uid >= m.HostID && uid < m.HostID+m.Size { + return true + } + } + return false +} + +// CreateContainer creates a container. +func (r *ConmonOCIRuntime) CreateContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) (int64, error) { + // always make the run dir accessible to the current user so that the PID files can be read without + // being in the rootless user namespace. + if err := makeAccessible(ctr.state.RunDir, 0, 0); err != nil { + return 0, err + } + if !hasCurrentUserMapped(ctr) { + for _, i := range []string{ctr.state.RunDir, ctr.runtime.config.Engine.TmpDir, ctr.config.StaticDir, ctr.state.Mountpoint, ctr.runtime.config.Engine.VolumePath} { + if err := makeAccessible(i, ctr.RootUID(), ctr.RootGID()); err != nil { + return 0, err + } + } + + // if we are running a non privileged container, be sure to umount some kernel paths so they are not + // bind mounted inside the container at all. + if !ctr.config.Privileged && !rootless.IsRootless() { + return r.createRootlessContainer(ctr, restoreOptions) + } + } + return r.createOCIContainer(ctr, restoreOptions) +} + +// UpdateContainerStatus retrieves the current status of the container from the +// runtime. It updates the container's state but does not save it. +// If useRuntime is false, we will not directly hit runc to see the container's +// status, but will instead only check for the existence of the conmon exit file +// and update state to stopped if it exists. +func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error { + runtimeDir, err := util.GetRuntimeDir() + if err != nil { + return err + } + + // Store old state so we know if we were already stopped + oldState := ctr.state.State + + state := new(spec.State) + + cmd := exec.Command(r.path, "state", ctr.ID()) + cmd.Env = append(cmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)) + + outPipe, err := cmd.StdoutPipe() + if err != nil { + return fmt.Errorf("getting stdout pipe: %w", err) + } + errPipe, err := cmd.StderrPipe() + if err != nil { + return fmt.Errorf("getting stderr pipe: %w", err) + } + + if err := cmd.Start(); err != nil { + out, err2 := ioutil.ReadAll(errPipe) + if err2 != nil { + return fmt.Errorf("error getting container %s state: %w", ctr.ID(), err) + } + if strings.Contains(string(out), "does not exist") || strings.Contains(string(out), "No such file") { + if err := ctr.removeConmonFiles(); err != nil { + logrus.Debugf("unable to remove conmon files for container %s", ctr.ID()) + } + ctr.state.ExitCode = -1 + ctr.state.FinishedTime = time.Now() + ctr.state.State = define.ContainerStateExited + return ctr.runtime.state.AddContainerExitCode(ctr.ID(), ctr.state.ExitCode) + } + return fmt.Errorf("error getting container %s state. stderr/out: %s: %w", ctr.ID(), out, err) + } + defer func() { + _ = cmd.Wait() + }() + + if err := errPipe.Close(); err != nil { + return err + } + out, err := ioutil.ReadAll(outPipe) + if err != nil { + return fmt.Errorf("error reading stdout: %s: %w", ctr.ID(), err) + } + if err := json.NewDecoder(bytes.NewBuffer(out)).Decode(state); err != nil { + return fmt.Errorf("error decoding container status for container %s: %w", ctr.ID(), err) + } + ctr.state.PID = state.Pid + + switch state.Status { + case "created": + ctr.state.State = define.ContainerStateCreated + case "paused": + ctr.state.State = define.ContainerStatePaused + case "running": + ctr.state.State = define.ContainerStateRunning + case "stopped": + ctr.state.State = define.ContainerStateStopped + default: + return fmt.Errorf("unrecognized status returned by runtime for container %s: %s: %w", + ctr.ID(), state.Status, define.ErrInternal) + } + + // Handle ContainerStateStopping - keep it unless the container + // transitioned to no longer running. + if oldState == define.ContainerStateStopping && (ctr.state.State == define.ContainerStatePaused || ctr.state.State == define.ContainerStateRunning) { + ctr.state.State = define.ContainerStateStopping + } + + return nil +} + +// StartContainer starts the given container. +// Sets time the container was started, but does not save it. +func (r *ConmonOCIRuntime) StartContainer(ctr *Container) error { + // TODO: streams should probably *not* be our STDIN/OUT/ERR - redirect to buffers? + runtimeDir, err := util.GetRuntimeDir() + if err != nil { + return err + } + env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} + if path, ok := os.LookupEnv("PATH"); ok { + env = append(env, fmt.Sprintf("PATH=%s", path)) + } + if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "start", ctr.ID())...); err != nil { + return err + } + + ctr.state.StartedTime = time.Now() + + return nil +} + +// KillContainer sends the given signal to the given container. +// If all is set, send to all PIDs in the container. +// All is only supported if the container created cgroups. +func (r *ConmonOCIRuntime) KillContainer(ctr *Container, signal uint, all bool) error { + logrus.Debugf("Sending signal %d to container %s", signal, ctr.ID()) + runtimeDir, err := util.GetRuntimeDir() + if err != nil { + return err + } + env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} + var args []string + args = append(args, r.runtimeFlags...) + if all { + args = append(args, "kill", "--all", ctr.ID(), fmt.Sprintf("%d", signal)) + } else { + args = append(args, "kill", ctr.ID(), fmt.Sprintf("%d", signal)) + } + if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, args...); err != nil { + // Update container state - there's a chance we failed because + // the container exited in the meantime. + if err2 := r.UpdateContainerStatus(ctr); err2 != nil { + logrus.Infof("Error updating status for container %s: %v", ctr.ID(), err2) + } + if ctr.ensureState(define.ContainerStateStopped, define.ContainerStateExited) { + return define.ErrCtrStateInvalid + } + return fmt.Errorf("error sending signal to container %s: %w", ctr.ID(), err) + } + + return nil +} + +// StopContainer stops a container, first using its given stop signal (or +// SIGTERM if no signal was specified), then using SIGKILL. +// Timeout is given in seconds. If timeout is 0, the container will be +// immediately kill with SIGKILL. +// Does not set finished time for container, assumes you will run updateStatus +// after to pull the exit code. +func (r *ConmonOCIRuntime) StopContainer(ctr *Container, timeout uint, all bool) error { + logrus.Debugf("Stopping container %s (PID %d)", ctr.ID(), ctr.state.PID) + + // Ping the container to see if it's alive + // If it's not, it's already stopped, return + err := unix.Kill(ctr.state.PID, 0) + if err == unix.ESRCH { + return nil + } + + stopSignal := ctr.config.StopSignal + if stopSignal == 0 { + stopSignal = uint(syscall.SIGTERM) + } + + if timeout > 0 { + if err := r.KillContainer(ctr, stopSignal, all); err != nil { + // Is the container gone? + // If so, it probably died between the first check and + // our sending the signal + // The container is stopped, so exit cleanly + err := unix.Kill(ctr.state.PID, 0) + if err == unix.ESRCH { + return nil + } + + return err + } + + if err := waitContainerStop(ctr, time.Duration(timeout)*time.Second); err != nil { + logrus.Debugf("Timed out stopping container %s with %s, resorting to SIGKILL: %v", ctr.ID(), unix.SignalName(syscall.Signal(stopSignal)), err) + logrus.Warnf("StopSignal %s failed to stop container %s in %d seconds, resorting to SIGKILL", unix.SignalName(syscall.Signal(stopSignal)), ctr.Name(), timeout) + } else { + // No error, the container is dead + return nil + } + } + + if err := r.KillContainer(ctr, 9, all); err != nil { + // Again, check if the container is gone. If it is, exit cleanly. + err := unix.Kill(ctr.state.PID, 0) + if err == unix.ESRCH { + return nil + } + + return fmt.Errorf("error sending SIGKILL to container %s: %w", ctr.ID(), err) + } + + // Give runtime a few seconds to make it happen + if err := waitContainerStop(ctr, killContainerTimeout); err != nil { + return err + } + + return nil +} + +// DeleteContainer deletes a container from the OCI runtime. +func (r *ConmonOCIRuntime) DeleteContainer(ctr *Container) error { + runtimeDir, err := util.GetRuntimeDir() + if err != nil { + return err + } + env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} + return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "delete", "--force", ctr.ID())...) +} + +// PauseContainer pauses the given container. +func (r *ConmonOCIRuntime) PauseContainer(ctr *Container) error { + runtimeDir, err := util.GetRuntimeDir() + if err != nil { + return err + } + env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} + return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "pause", ctr.ID())...) +} + +// UnpauseContainer unpauses the given container. +func (r *ConmonOCIRuntime) UnpauseContainer(ctr *Container) error { + runtimeDir, err := util.GetRuntimeDir() + if err != nil { + return err + } + env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} + return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "resume", ctr.ID())...) +} + +// HTTPAttach performs an attach for the HTTP API. +// The caller must handle closing the HTTP connection after this returns. +// The cancel channel is not closed; it is up to the caller to do so after +// this function returns. +// If this is a container with a terminal, we will stream raw. If it is not, we +// will stream with an 8-byte header to multiplex STDOUT and STDERR. +// Returns any errors that occurred, and whether the connection was successfully +// hijacked before that error occurred. +func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.ResponseWriter, streams *HTTPAttachStreams, detachKeys *string, cancel <-chan bool, hijackDone chan<- bool, streamAttach, streamLogs bool) (deferredErr error) { + isTerminal := false + if ctr.config.Spec.Process != nil { + isTerminal = ctr.config.Spec.Process.Terminal + } + + if streams != nil { + if !streams.Stdin && !streams.Stdout && !streams.Stderr { + return fmt.Errorf("must specify at least one stream to attach to: %w", define.ErrInvalidArg) + } + } + + attachSock, err := r.AttachSocketPath(ctr) + if err != nil { + return err + } + + var conn *net.UnixConn + if streamAttach { + newConn, err := openUnixSocket(attachSock) + if err != nil { + return fmt.Errorf("failed to connect to container's attach socket: %v: %w", attachSock, err) + } + conn = newConn + defer func() { + if err := conn.Close(); err != nil { + logrus.Errorf("Unable to close container %s attach socket: %q", ctr.ID(), err) + } + }() + + logrus.Debugf("Successfully connected to container %s attach socket %s", ctr.ID(), attachSock) + } + + detachString := ctr.runtime.config.Engine.DetachKeys + if detachKeys != nil { + detachString = *detachKeys + } + detach, err := processDetachKeys(detachString) + if err != nil { + return err + } + + attachStdout := true + attachStderr := true + attachStdin := true + if streams != nil { + attachStdout = streams.Stdout + attachStderr = streams.Stderr + attachStdin = streams.Stdin + } + + logrus.Debugf("Going to hijack container %s attach connection", ctr.ID()) + + // Alright, let's hijack. + hijacker, ok := w.(http.Hijacker) + if !ok { + return fmt.Errorf("unable to hijack connection") + } + + httpCon, httpBuf, err := hijacker.Hijack() + if err != nil { + return fmt.Errorf("error hijacking connection: %w", err) + } + + hijackDone <- true + + writeHijackHeader(req, httpBuf) + + // Force a flush after the header is written. + if err := httpBuf.Flush(); err != nil { + return fmt.Errorf("error flushing HTTP hijack header: %w", err) + } + + defer func() { + hijackWriteErrorAndClose(deferredErr, ctr.ID(), isTerminal, httpCon, httpBuf) + }() + + logrus.Debugf("Hijack for container %s attach session done, ready to stream", ctr.ID()) + + // TODO: This is gross. Really, really gross. + // I want to say we should read all the logs into an array before + // calling this, in container_api.go, but that could take a lot of + // memory... + // On the whole, we need to figure out a better way of doing this, + // though. + logSize := 0 + if streamLogs { + logrus.Debugf("Will stream logs for container %s attach session", ctr.ID()) + + // Get all logs for the container + logChan := make(chan *logs.LogLine) + logOpts := new(logs.LogOptions) + logOpts.Tail = -1 + logOpts.WaitGroup = new(sync.WaitGroup) + errChan := make(chan error) + go func() { + var err error + // In non-terminal mode we need to prepend with the + // stream header. + logrus.Debugf("Writing logs for container %s to HTTP attach", ctr.ID()) + for logLine := range logChan { + if !isTerminal { + device := logLine.Device + var header []byte + headerLen := uint32(len(logLine.Msg)) + logSize += len(logLine.Msg) + switch strings.ToLower(device) { + case "stdin": + header = makeHTTPAttachHeader(0, headerLen) + case "stdout": + header = makeHTTPAttachHeader(1, headerLen) + case "stderr": + header = makeHTTPAttachHeader(2, headerLen) + default: + logrus.Errorf("Unknown device for log line: %s", device) + header = makeHTTPAttachHeader(1, headerLen) + } + _, err = httpBuf.Write(header) + if err != nil { + break + } + } + _, err = httpBuf.Write([]byte(logLine.Msg)) + if err != nil { + break + } + if !logLine.Partial() { + _, err = httpBuf.Write([]byte("\n")) + if err != nil { + break + } + } + err = httpBuf.Flush() + if err != nil { + break + } + } + errChan <- err + }() + if err := ctr.ReadLog(context.Background(), logOpts, logChan, 0); err != nil { + return err + } + go func() { + logOpts.WaitGroup.Wait() + close(logChan) + }() + logrus.Debugf("Done reading logs for container %s, %d bytes", ctr.ID(), logSize) + if err := <-errChan; err != nil { + return err + } + } + if !streamAttach { + logrus.Debugf("Done streaming logs for container %s attach, exiting as attach streaming not requested", ctr.ID()) + return nil + } + + logrus.Debugf("Forwarding attach output for container %s", ctr.ID()) + + stdoutChan := make(chan error) + stdinChan := make(chan error) + + // Handle STDOUT/STDERR + go func() { + var err error + if isTerminal { + // Hack: return immediately if attachStdout not set to + // emulate Docker. + // Basically, when terminal is set, STDERR goes nowhere. + // Everything does over STDOUT. + // Therefore, if not attaching STDOUT - we'll never copy + // anything from here. + logrus.Debugf("Performing terminal HTTP attach for container %s", ctr.ID()) + if attachStdout { + err = httpAttachTerminalCopy(conn, httpBuf, ctr.ID()) + } + } else { + logrus.Debugf("Performing non-terminal HTTP attach for container %s", ctr.ID()) + err = httpAttachNonTerminalCopy(conn, httpBuf, ctr.ID(), attachStdin, attachStdout, attachStderr) + } + stdoutChan <- err + logrus.Debugf("STDOUT/ERR copy completed") + }() + // Next, STDIN. Avoid entirely if attachStdin unset. + if attachStdin { + go func() { + _, err := cutil.CopyDetachable(conn, httpBuf, detach) + logrus.Debugf("STDIN copy completed") + stdinChan <- err + }() + } + + for { + select { + case err := <-stdoutChan: + if err != nil { + return err + } + + return nil + case err := <-stdinChan: + if err != nil { + return err + } + // copy stdin is done, close it + if connErr := conn.CloseWrite(); connErr != nil { + logrus.Errorf("Unable to close conn: %v", connErr) + } + case <-cancel: + return nil + } + } +} + +// isRetryable returns whether the error was caused by a blocked syscall or the +// specified operation on a non blocking file descriptor wasn't ready for completion. +func isRetryable(err error) bool { + var errno syscall.Errno + if errors.As(err, &errno) { + return errno == syscall.EINTR || errno == syscall.EAGAIN + } + return false +} + +// openControlFile opens the terminal control file. +func openControlFile(ctr *Container, parentDir string) (*os.File, error) { + controlPath := filepath.Join(parentDir, "ctl") + for i := 0; i < 600; i++ { + controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY|unix.O_NONBLOCK, 0) + if err == nil { + return controlFile, nil + } + if !isRetryable(err) { + return nil, fmt.Errorf("could not open ctl file for terminal resize for container %s: %w", ctr.ID(), err) + } + time.Sleep(time.Second / 10) + } + return nil, fmt.Errorf("timeout waiting for %q", controlPath) +} + +// AttachResize resizes the terminal used by the given container. +func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize resize.TerminalSize) error { + controlFile, err := openControlFile(ctr, ctr.bundlePath()) + if err != nil { + return err + } + defer controlFile.Close() + + logrus.Debugf("Received a resize event for container %s: %+v", ctr.ID(), newSize) + if _, err = fmt.Fprintf(controlFile, "%d %d %d\n", 1, newSize.Height, newSize.Width); err != nil { + return fmt.Errorf("failed to write to ctl file to resize terminal: %w", err) + } + + return nil +} + +// CheckpointContainer checkpoints the given container. +func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options ContainerCheckpointOptions) (int64, error) { + // imagePath is used by CRIU to store the actual checkpoint files + imagePath := ctr.CheckpointPath() + if options.PreCheckPoint { + imagePath = ctr.PreCheckPointPath() + } + // workPath will be used to store dump.log and stats-dump + workPath := ctr.bundlePath() + logrus.Debugf("Writing checkpoint to %s", imagePath) + logrus.Debugf("Writing checkpoint logs to %s", workPath) + logrus.Debugf("Pre-dump the container %t", options.PreCheckPoint) + args := []string{} + args = append(args, r.runtimeFlags...) + args = append(args, "checkpoint") + args = append(args, "--image-path") + args = append(args, imagePath) + args = append(args, "--work-path") + args = append(args, workPath) + if options.KeepRunning { + args = append(args, "--leave-running") + } + if options.TCPEstablished { + args = append(args, "--tcp-established") + } + if options.FileLocks { + args = append(args, "--file-locks") + } + if !options.PreCheckPoint && options.KeepRunning { + args = append(args, "--leave-running") + } + if options.PreCheckPoint { + args = append(args, "--pre-dump") + } + if !options.PreCheckPoint && options.WithPrevious { + args = append( + args, + "--parent-path", + filepath.Join("..", preCheckpointDir), + ) + } + + args = append(args, ctr.ID()) + logrus.Debugf("the args to checkpoint: %s %s", r.path, strings.Join(args, " ")) + + runtimeDir, err := util.GetRuntimeDir() + if err != nil { + return 0, err + } + env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} + if path, ok := os.LookupEnv("PATH"); ok { + env = append(env, fmt.Sprintf("PATH=%s", path)) + } + + var runtimeCheckpointStarted time.Time + err = r.withContainerSocketLabel(ctr, func() error { + runtimeCheckpointStarted = time.Now() + return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, args...) + }) + + runtimeCheckpointDuration := func() int64 { + if options.PrintStats { + return time.Since(runtimeCheckpointStarted).Microseconds() + } + return 0 + }() + + return runtimeCheckpointDuration, err +} + +func (r *ConmonOCIRuntime) CheckConmonRunning(ctr *Container) (bool, error) { + if ctr.state.ConmonPID == 0 { + // If the container is running or paused, assume Conmon is + // running. We didn't record Conmon PID on some old versions, so + // that is likely what's going on... + // Unusual enough that we should print a warning message though. + if ctr.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) { + logrus.Warnf("Conmon PID is not set, but container is running!") + return true, nil + } + // Container's not running, so conmon PID being unset is + // expected. Conmon is not running. + return false, nil + } + + // We have a conmon PID. Ping it with signal 0. + if err := unix.Kill(ctr.state.ConmonPID, 0); err != nil { + if err == unix.ESRCH { + return false, nil + } + return false, fmt.Errorf("error pinging container %s conmon with signal 0: %w", ctr.ID(), err) + } + return true, nil +} + +// SupportsCheckpoint checks if the OCI runtime supports checkpointing +// containers. +func (r *ConmonOCIRuntime) SupportsCheckpoint() bool { + return crutils.CRRuntimeSupportsCheckpointRestore(r.path) +} + +// SupportsJSONErrors checks if the OCI runtime supports JSON-formatted error +// messages. +func (r *ConmonOCIRuntime) SupportsJSONErrors() bool { + return r.supportsJSON +} + +// SupportsNoCgroups checks if the OCI runtime supports running containers +// without cgroups (the --cgroup-manager=disabled flag). +func (r *ConmonOCIRuntime) SupportsNoCgroups() bool { + return r.supportsNoCgroups +} + +// SupportsKVM checks if the OCI runtime supports running containers +// without KVM separation +func (r *ConmonOCIRuntime) SupportsKVM() bool { + return r.supportsKVM +} + +// AttachSocketPath is the path to a single container's attach socket. +func (r *ConmonOCIRuntime) AttachSocketPath(ctr *Container) (string, error) { + if ctr == nil { + return "", fmt.Errorf("must provide a valid container to get attach socket path: %w", define.ErrInvalidArg) + } + + return filepath.Join(ctr.bundlePath(), "attach"), nil +} + +// ExitFilePath is the path to a container's exit file. +func (r *ConmonOCIRuntime) ExitFilePath(ctr *Container) (string, error) { + if ctr == nil { + return "", fmt.Errorf("must provide a valid container to get exit file path: %w", define.ErrInvalidArg) + } + return filepath.Join(r.exitsDir, ctr.ID()), nil +} + +// RuntimeInfo provides information on the runtime. +func (r *ConmonOCIRuntime) RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error) { + runtimePackage := packageVersion(r.path) + conmonPackage := packageVersion(r.conmonPath) + runtimeVersion, err := r.getOCIRuntimeVersion() + if err != nil { + return nil, nil, fmt.Errorf("error getting version of OCI runtime %s: %w", r.name, err) + } + conmonVersion, err := r.getConmonVersion() + if err != nil { + return nil, nil, fmt.Errorf("error getting conmon version: %w", err) + } + + conmon := define.ConmonInfo{ + Package: conmonPackage, + Path: r.conmonPath, + Version: conmonVersion, + } + ocirt := define.OCIRuntimeInfo{ + Name: r.name, + Path: r.path, + Package: runtimePackage, + Version: runtimeVersion, + } + return &conmon, &ocirt, nil +} + +// makeAccessible changes the path permission and each parent directory to have --x--x--x +func makeAccessible(path string, uid, gid int) error { + for ; path != "/"; path = filepath.Dir(path) { + st, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + if int(st.Sys().(*syscall.Stat_t).Uid) == uid && int(st.Sys().(*syscall.Stat_t).Gid) == gid { + continue + } + if st.Mode()&0111 != 0111 { + if err := os.Chmod(path, st.Mode()|0111); err != nil { + return err + } + } + } + return nil +} + +// Wait for a container which has been sent a signal to stop +func waitContainerStop(ctr *Container, timeout time.Duration) error { + return waitPidStop(ctr.state.PID, timeout) +} + +// Wait for a given PID to stop +func waitPidStop(pid int, timeout time.Duration) error { + done := make(chan struct{}) + chControl := make(chan struct{}) + go func() { + for { + select { + case <-chControl: + return + default: + if err := unix.Kill(pid, 0); err != nil { + if err == unix.ESRCH { + close(done) + return + } + logrus.Errorf("Pinging PID %d with signal 0: %v", pid, err) + } + time.Sleep(100 * time.Millisecond) + } + } + }() + select { + case <-done: + return nil + case <-time.After(timeout): + close(chControl) + return fmt.Errorf("given PIDs did not die within timeout") + } +} + +func (r *ConmonOCIRuntime) getLogTag(ctr *Container) (string, error) { + logTag := ctr.LogTag() + if logTag == "" { + return "", nil + } + data, err := ctr.inspectLocked(false) + if err != nil { + // FIXME: this error should probably be returned + return "", nil //nolint: nilerr + } + tmpl, err := template.New("container").Parse(logTag) + if err != nil { + return "", fmt.Errorf("template parsing error %s: %w", logTag, err) + } + var b bytes.Buffer + err = tmpl.Execute(&b, data) + if err != nil { + return "", err + } + return b.String(), nil +} + +// createOCIContainer generates this container's main conmon instance and prepares it for starting +func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) (int64, error) { + var stderrBuf bytes.Buffer + + runtimeDir, err := util.GetRuntimeDir() + if err != nil { + return 0, err + } + + parentSyncPipe, childSyncPipe, err := newPipe() + if err != nil { + return 0, fmt.Errorf("error creating socket pair: %w", err) + } + defer errorhandling.CloseQuiet(parentSyncPipe) + + childStartPipe, parentStartPipe, err := newPipe() + if err != nil { + return 0, fmt.Errorf("error creating socket pair for start pipe: %w", err) + } + + defer errorhandling.CloseQuiet(parentStartPipe) + + var ociLog string + if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON { + ociLog = filepath.Join(ctr.state.RunDir, "oci-log") + } + + logTag, err := r.getLogTag(ctr) + if err != nil { + return 0, err + } + + if ctr.config.CgroupsMode == cgroupSplit { + if err := utils.MoveUnderCgroupSubtree("runtime"); err != nil { + return 0, err + } + } + + pidfile := ctr.config.PidFile + if pidfile == "" { + pidfile = filepath.Join(ctr.state.RunDir, "pidfile") + } + + args := r.sharedConmonArgs(ctr, ctr.ID(), ctr.bundlePath(), pidfile, ctr.LogPath(), r.exitsDir, ociLog, ctr.LogDriver(), logTag) + + if ctr.config.SdNotifyMode == define.SdNotifyModeContainer && ctr.config.SdNotifySocket != "" { + args = append(args, fmt.Sprintf("--sdnotify-socket=%s", ctr.config.SdNotifySocket)) + } + + if ctr.config.Spec.Process.Terminal { + args = append(args, "-t") + } else if ctr.config.Stdin { + args = append(args, "-i") + } + + if ctr.config.Timeout > 0 { + args = append(args, fmt.Sprintf("--timeout=%d", ctr.config.Timeout)) + } + + if !r.enableKeyring { + args = append(args, "--no-new-keyring") + } + if ctr.config.ConmonPidFile != "" { + args = append(args, "--conmon-pidfile", ctr.config.ConmonPidFile) + } + + if r.noPivot { + args = append(args, "--no-pivot") + } + + exitCommand, err := specgenutil.CreateExitCommandArgs(ctr.runtime.storageConfig, ctr.runtime.config, logrus.IsLevelEnabled(logrus.DebugLevel), ctr.AutoRemove(), false) + if err != nil { + return 0, err + } + exitCommand = append(exitCommand, ctr.config.ID) + + args = append(args, "--exit-command", exitCommand[0]) + for _, arg := range exitCommand[1:] { + args = append(args, []string{"--exit-command-arg", arg}...) + } + + // Pass down the LISTEN_* environment (see #10443). + preserveFDs := ctr.config.PreserveFDs + if val := os.Getenv("LISTEN_FDS"); val != "" { + if ctr.config.PreserveFDs > 0 { + logrus.Warnf("Ignoring LISTEN_FDS to preserve custom user-specified FDs") + } else { + fds, err := strconv.Atoi(val) + if err != nil { + return 0, fmt.Errorf("converting LISTEN_FDS=%s: %w", val, err) + } + preserveFDs = uint(fds) + } + } + + if preserveFDs > 0 { + args = append(args, formatRuntimeOpts("--preserve-fds", fmt.Sprintf("%d", preserveFDs))...) + } + + if restoreOptions != nil { + args = append(args, "--restore", ctr.CheckpointPath()) + if restoreOptions.TCPEstablished { + args = append(args, "--runtime-opt", "--tcp-established") + } + if restoreOptions.FileLocks { + args = append(args, "--runtime-opt", "--file-locks") + } + if restoreOptions.Pod != "" { + mountLabel := ctr.config.MountLabel + processLabel := ctr.config.ProcessLabel + if mountLabel != "" { + args = append( + args, + "--runtime-opt", + fmt.Sprintf( + "--lsm-mount-context=%s", + mountLabel, + ), + ) + } + if processLabel != "" { + args = append( + args, + "--runtime-opt", + fmt.Sprintf( + "--lsm-profile=selinux:%s", + processLabel, + ), + ) + } + } + } + + logrus.WithFields(logrus.Fields{ + "args": args, + }).Debugf("running conmon: %s", r.conmonPath) + + cmd := exec.Command(r.conmonPath, args...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: true, + } + // TODO this is probably a really bad idea for some uses + // Make this configurable + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if ctr.config.Spec.Process.Terminal { + cmd.Stderr = &stderrBuf + } + + // 0, 1 and 2 are stdin, stdout and stderr + conmonEnv := r.configureConmonEnv(runtimeDir) + + var filesToClose []*os.File + if preserveFDs > 0 { + for fd := 3; fd < int(3+preserveFDs); fd++ { + f := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)) + filesToClose = append(filesToClose, f) + cmd.ExtraFiles = append(cmd.ExtraFiles, f) + } + } + + cmd.Env = r.conmonEnv + // we don't want to step on users fds they asked to preserve + // Since 0-2 are used for stdio, start the fds we pass in at preserveFDs+3 + cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", preserveFDs+3), fmt.Sprintf("_OCI_STARTPIPE=%d", preserveFDs+4)) + cmd.Env = append(cmd.Env, conmonEnv...) + cmd.ExtraFiles = append(cmd.ExtraFiles, childSyncPipe, childStartPipe) + + if r.reservePorts && !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() { + ports, err := bindPorts(ctr.convertPortMappings()) + if err != nil { + return 0, err + } + filesToClose = append(filesToClose, ports...) + + // Leak the port we bound in the conmon process. These fd's won't be used + // by the container and conmon will keep the ports busy so that another + // process cannot use them. + cmd.ExtraFiles = append(cmd.ExtraFiles, ports...) + } + + if ctr.config.NetMode.IsSlirp4netns() || rootless.IsRootless() { + if ctr.config.PostConfigureNetNS { + havePortMapping := len(ctr.config.PortMappings) > 0 + if havePortMapping { + ctr.rootlessPortSyncR, ctr.rootlessPortSyncW, err = os.Pipe() + if err != nil { + return 0, fmt.Errorf("failed to create rootless port sync pipe: %w", err) + } + } + ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe() + if err != nil { + return 0, fmt.Errorf("failed to create rootless network sync pipe: %w", err) + } + } else { + if ctr.rootlessSlirpSyncR != nil { + defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR) + } + if ctr.rootlessSlirpSyncW != nil { + defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW) + } + } + // Leak one end in conmon, the other one will be leaked into slirp4netns + cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessSlirpSyncW) + + if ctr.rootlessPortSyncW != nil { + defer errorhandling.CloseQuiet(ctr.rootlessPortSyncW) + // Leak one end in conmon, the other one will be leaked into rootlessport + cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessPortSyncW) + } + } + var runtimeRestoreStarted time.Time + if restoreOptions != nil { + runtimeRestoreStarted = time.Now() + } + err = startCommand(cmd, ctr) + + // regardless of whether we errored or not, we no longer need the children pipes + childSyncPipe.Close() + childStartPipe.Close() + if err != nil { + return 0, err + } + if err := r.moveConmonToCgroupAndSignal(ctr, cmd, parentStartPipe); err != nil { + return 0, err + } + /* Wait for initial setup and fork, and reap child */ + err = cmd.Wait() + if err != nil { + return 0, err + } + + pid, err := readConmonPipeData(r.name, parentSyncPipe, ociLog) + if err != nil { + if err2 := r.DeleteContainer(ctr); err2 != nil { + logrus.Errorf("Removing container %s from runtime after creation failed", ctr.ID()) + } + return 0, err + } + ctr.state.PID = pid + + conmonPID, err := readConmonPidFile(ctr.config.ConmonPidFile) + if err != nil { + logrus.Warnf("Error reading conmon pid file for container %s: %v", ctr.ID(), err) + } else if conmonPID > 0 { + // conmon not having a pid file is a valid state, so don't set it if we don't have it + logrus.Infof("Got Conmon PID as %d", conmonPID) + ctr.state.ConmonPID = conmonPID + } + + runtimeRestoreDuration := func() int64 { + if restoreOptions != nil && restoreOptions.PrintStats { + return time.Since(runtimeRestoreStarted).Microseconds() + } + return 0 + }() + + // These fds were passed down to the runtime. Close them + // and not interfere + for _, f := range filesToClose { + errorhandling.CloseQuiet(f) + } + + return runtimeRestoreDuration, nil +} + +// configureConmonEnv gets the environment values to add to conmon's exec struct +// TODO this may want to be less hardcoded/more configurable in the future +func (r *ConmonOCIRuntime) configureConmonEnv(runtimeDir string) []string { + var env []string + for _, e := range os.Environ() { + if strings.HasPrefix(e, "LC_") { + env = append(env, e) + } + } + conf, ok := os.LookupEnv("CONTAINERS_CONF") + if ok { + env = append(env, fmt.Sprintf("CONTAINERS_CONF=%s", conf)) + } + env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)) + env = append(env, fmt.Sprintf("_CONTAINERS_USERNS_CONFIGURED=%s", os.Getenv("_CONTAINERS_USERNS_CONFIGURED"))) + env = append(env, fmt.Sprintf("_CONTAINERS_ROOTLESS_UID=%s", os.Getenv("_CONTAINERS_ROOTLESS_UID"))) + home := homedir.Get() + if home != "" { + env = append(env, fmt.Sprintf("HOME=%s", home)) + } + + return env +} + +// sharedConmonArgs takes common arguments for exec and create/restore and formats them for the conmon CLI +func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, pidPath, logPath, exitDir, ociLogPath, logDriver, logTag string) []string { + // set the conmon API version to be able to use the correct sync struct keys + args := []string{ + "--api-version", "1", + "-c", ctr.ID(), + "-u", cuuid, + "-r", r.path, + "-b", bundlePath, + "-p", pidPath, + "-n", ctr.Name(), + "--exit-dir", exitDir, + "--full-attach", + } + if len(r.runtimeFlags) > 0 { + rFlags := []string{} + for _, arg := range r.runtimeFlags { + rFlags = append(rFlags, "--runtime-arg", arg) + } + args = append(args, rFlags...) + } + + if ctr.CgroupManager() == config.SystemdCgroupsManager && !ctr.config.NoCgroups && ctr.config.CgroupsMode != cgroupSplit { + args = append(args, "-s") + } + + var logDriverArg string + switch logDriver { + case define.JournaldLogging: + logDriverArg = define.JournaldLogging + case define.NoLogging: + logDriverArg = define.NoLogging + case define.PassthroughLogging: + logDriverArg = define.PassthroughLogging + //lint:ignore ST1015 the default case has to be here + default: //nolint:stylecheck,gocritic + // No case here should happen except JSONLogging, but keep this here in case the options are extended + logrus.Errorf("%s logging specified but not supported. Choosing k8s-file logging instead", ctr.LogDriver()) + fallthrough + case "": + // to get here, either a user would specify `--log-driver ""`, or this came from another place in libpod + // since the former case is obscure, and the latter case isn't an error, let's silently fallthrough + fallthrough + case define.JSONLogging: + fallthrough + case define.KubernetesLogging: + logDriverArg = fmt.Sprintf("%s:%s", define.KubernetesLogging, logPath) + } + + args = append(args, "-l", logDriverArg) + logLevel := logrus.GetLevel() + args = append(args, "--log-level", logLevel.String()) + + if logLevel == logrus.DebugLevel { + logrus.Debugf("%s messages will be logged to syslog", r.conmonPath) + args = append(args, "--syslog") + } + + size := r.logSizeMax + if ctr.config.LogSize > 0 { + size = ctr.config.LogSize + } + if size > 0 { + args = append(args, "--log-size-max", fmt.Sprintf("%v", size)) + } + + if ociLogPath != "" { + args = append(args, "--runtime-arg", "--log-format=json", "--runtime-arg", "--log", fmt.Sprintf("--runtime-arg=%s", ociLogPath)) + } + if logTag != "" { + args = append(args, "--log-tag", logTag) + } + if ctr.config.NoCgroups { + logrus.Debugf("Running with no Cgroups") + args = append(args, "--runtime-arg", "--cgroup-manager", "--runtime-arg", "disabled") + } + return args +} + +func startCommand(cmd *exec.Cmd, ctr *Container) error { + // Make sure to unset the NOTIFY_SOCKET and reset it afterwards if needed. + switch ctr.config.SdNotifyMode { + case define.SdNotifyModeContainer, define.SdNotifyModeIgnore: + if prev := os.Getenv("NOTIFY_SOCKET"); prev != "" { + if err := os.Unsetenv("NOTIFY_SOCKET"); err != nil { + logrus.Warnf("Error unsetting NOTIFY_SOCKET %v", err) + } + defer func() { + if err := os.Setenv("NOTIFY_SOCKET", prev); err != nil { + logrus.Errorf("Resetting NOTIFY_SOCKET=%s", prev) + } + }() + } + } + + return cmd.Start() +} + +// newPipe creates a unix socket pair for communication. +// Returns two files - first is parent, second is child. +func newPipe() (*os.File, *os.File, error) { + fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_SEQPACKET|unix.SOCK_CLOEXEC, 0) + if err != nil { + return nil, nil, err + } + return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil +} + +// readConmonPidFile attempts to read conmon's pid from its pid file +func readConmonPidFile(pidFile string) (int, error) { + // Let's try reading the Conmon pid at the same time. + if pidFile != "" { + contents, err := ioutil.ReadFile(pidFile) + if err != nil { + return -1, err + } + // Convert it to an int + conmonPID, err := strconv.Atoi(string(contents)) + if err != nil { + return -1, err + } + return conmonPID, nil + } + return 0, nil +} + +// readConmonPipeData attempts to read a syncInfo struct from the pipe +func readConmonPipeData(runtimeName string, pipe *os.File, ociLog string) (int, error) { + // syncInfo is used to return data from monitor process to daemon + type syncInfo struct { + Data int `json:"data"` + Message string `json:"message,omitempty"` + } + + // Wait to get container pid from conmon + type syncStruct struct { + si *syncInfo + err error + } + ch := make(chan syncStruct) + go func() { + var si *syncInfo + rdr := bufio.NewReader(pipe) + b, err := rdr.ReadBytes('\n') + // ignore EOF here, error is returned even when data was read + // if it is no valid json unmarshal will fail below + if err != nil && !errors.Is(err, io.EOF) { + ch <- syncStruct{err: err} + } + if err := json.Unmarshal(b, &si); err != nil { + ch <- syncStruct{err: fmt.Errorf("conmon bytes %q: %w", string(b), err)} + return + } + ch <- syncStruct{si: si} + }() + + data := -1 //nolint: wastedassign + select { + case ss := <-ch: + if ss.err != nil { + if ociLog != "" { + ociLogData, err := ioutil.ReadFile(ociLog) + if err == nil { + var ociErr ociError + if err := json.Unmarshal(ociLogData, &ociErr); err == nil { + return -1, getOCIRuntimeError(runtimeName, ociErr.Msg) + } + } + } + return -1, fmt.Errorf("container create failed (no logs from conmon): %w", ss.err) + } + logrus.Debugf("Received: %d", ss.si.Data) + if ss.si.Data < 0 { + if ociLog != "" { + ociLogData, err := ioutil.ReadFile(ociLog) + if err == nil { + var ociErr ociError + if err := json.Unmarshal(ociLogData, &ociErr); err == nil { + return ss.si.Data, getOCIRuntimeError(runtimeName, ociErr.Msg) + } + } + } + // If we failed to parse the JSON errors, then print the output as it is + if ss.si.Message != "" { + return ss.si.Data, getOCIRuntimeError(runtimeName, ss.si.Message) + } + return ss.si.Data, fmt.Errorf("container create failed: %w", define.ErrInternal) + } + data = ss.si.Data + case <-time.After(define.ContainerCreateTimeout): + return -1, fmt.Errorf("container creation timeout: %w", define.ErrInternal) + } + return data, nil +} + +// writeConmonPipeData writes nonce data to a pipe +func writeConmonPipeData(pipe *os.File) error { + someData := []byte{0} + _, err := pipe.Write(someData) + return err +} + +// formatRuntimeOpts prepends opts passed to it with --runtime-opt for passing to conmon +func formatRuntimeOpts(opts ...string) []string { + args := make([]string, 0, len(opts)*2) + for _, o := range opts { + args = append(args, "--runtime-opt", o) + } + return args +} + +// getConmonVersion returns a string representation of the conmon version. +func (r *ConmonOCIRuntime) getConmonVersion() (string, error) { + output, err := utils.ExecCmd(r.conmonPath, "--version") + if err != nil { + return "", err + } + return strings.TrimSuffix(strings.Replace(output, "\n", ", ", 1), "\n"), nil +} + +// getOCIRuntimeVersion returns a string representation of the OCI runtime's +// version. +func (r *ConmonOCIRuntime) getOCIRuntimeVersion() (string, error) { + output, err := utils.ExecCmd(r.path, "--version") + if err != nil { + return "", err + } + return strings.TrimSuffix(output, "\n"), nil +} + +// Copy data from container to HTTP connection, for terminal attach. +// Container is the container's attach socket connection, http is a buffer for +// the HTTP connection. cid is the ID of the container the attach session is +// running for (used solely for error messages). +func httpAttachTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, cid string) error { + buf := make([]byte, bufferSize) + for { + numR, err := container.Read(buf) + logrus.Debugf("Read fd(%d) %d/%d bytes for container %s", int(buf[0]), numR, len(buf), cid) + + if numR > 0 { + switch buf[0] { + case AttachPipeStdout: + // Do nothing + default: + logrus.Errorf("Received unexpected attach type %+d, discarding %d bytes", buf[0], numR) + continue + } + + numW, err2 := http.Write(buf[1:numR]) + if err2 != nil { + if err != nil { + logrus.Errorf("Reading container %s STDOUT: %v", cid, err) + } + return err2 + } else if numW+1 != numR { + return io.ErrShortWrite + } + // We need to force the buffer to write immediately, so + // there isn't a delay on the terminal side. + if err2 := http.Flush(); err2 != nil { + if err != nil { + logrus.Errorf("Reading container %s STDOUT: %v", cid, err) + } + return err2 + } + } + if err != nil { + if err == io.EOF { + return nil + } + return err + } + } +} + +// Copy data from a container to an HTTP connection, for non-terminal attach. +// Appends a header to multiplex input. +func httpAttachNonTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, cid string, stdin, stdout, stderr bool) error { + buf := make([]byte, bufferSize) + for { + numR, err := container.Read(buf) + if numR > 0 { + var headerBuf []byte + + // Subtract 1 because we strip the first byte (used for + // multiplexing by Conmon). + headerLen := uint32(numR - 1) + // Practically speaking, we could make this buf[0] - 1, + // but we need to validate it anyway. + switch buf[0] { + case AttachPipeStdin: + headerBuf = makeHTTPAttachHeader(0, headerLen) + if !stdin { + continue + } + case AttachPipeStdout: + if !stdout { + continue + } + headerBuf = makeHTTPAttachHeader(1, headerLen) + case AttachPipeStderr: + if !stderr { + continue + } + headerBuf = makeHTTPAttachHeader(2, headerLen) + default: + logrus.Errorf("Received unexpected attach type %+d, discarding %d bytes", buf[0], numR) + continue + } + + numH, err2 := http.Write(headerBuf) + if err2 != nil { + if err != nil { + logrus.Errorf("Reading container %s standard streams: %v", cid, err) + } + + return err2 + } + // Hardcoding header length is pretty gross, but + // fast. Should be safe, as this is a fixed part + // of the protocol. + if numH != 8 { + if err != nil { + logrus.Errorf("Reading container %s standard streams: %v", cid, err) + } + + return io.ErrShortWrite + } + + numW, err2 := http.Write(buf[1:numR]) + if err2 != nil { + if err != nil { + logrus.Errorf("Reading container %s standard streams: %v", cid, err) + } + + return err2 + } else if numW+1 != numR { + if err != nil { + logrus.Errorf("Reading container %s standard streams: %v", cid, err) + } + + return io.ErrShortWrite + } + // We need to force the buffer to write immediately, so + // there isn't a delay on the terminal side. + if err2 := http.Flush(); err2 != nil { + if err != nil { + logrus.Errorf("Reading container %s STDOUT: %v", cid, err) + } + return err2 + } + } + if err != nil { + if err == io.EOF { + return nil + } + + return err + } + } +} diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_common.go index 16cd7ef9f..16cd7ef9f 100644 --- a/libpod/oci_conmon_exec_linux.go +++ b/libpod/oci_conmon_exec_common.go diff --git a/libpod/oci_conmon_freebsd.go b/libpod/oci_conmon_freebsd.go new file mode 100644 index 000000000..6f7ac7fc6 --- /dev/null +++ b/libpod/oci_conmon_freebsd.go @@ -0,0 +1,24 @@ +package libpod + +import ( + "errors" + "os" + "os/exec" +) + +func (r *ConmonOCIRuntime) createRootlessContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) (int64, error) { + return -1, errors.New("unsupported (*ConmonOCIRuntime) createRootlessContainer") +} + +// Run the closure with the container's socket label set +func (r *ConmonOCIRuntime) withContainerSocketLabel(ctr *Container, closure func() error) error { + // No label support yet + return closure() +} + +// moveConmonToCgroupAndSignal gets a container's cgroupParent and moves the conmon process to that cgroup +// it then signals for conmon to start by sending nonce data down the start fd +func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec.Cmd, startFd *os.File) error { + // No equivalent on FreeBSD + return nil +} diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index 1b654ed33..0964d4ea3 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -1,46 +1,21 @@ -//go:build linux -// +build linux - package libpod import ( - "bufio" - "bytes" - "context" - "errors" "fmt" - "io" - "io/ioutil" - "net" - "net/http" "os" "os/exec" "path/filepath" "runtime" - "strconv" "strings" - "sync" - "syscall" - "text/template" - "time" runcconfig "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" "github.com/containers/common/pkg/cgroups" "github.com/containers/common/pkg/config" - "github.com/containers/common/pkg/resize" - cutil "github.com/containers/common/pkg/util" - conmonConfig "github.com/containers/conmon/runner/config" - "github.com/containers/podman/v4/libpod/define" - "github.com/containers/podman/v4/libpod/logs" - "github.com/containers/podman/v4/pkg/checkpoint/crutils" "github.com/containers/podman/v4/pkg/errorhandling" "github.com/containers/podman/v4/pkg/rootless" - "github.com/containers/podman/v4/pkg/specgenutil" - "github.com/containers/podman/v4/pkg/util" "github.com/containers/podman/v4/utils" - "github.com/containers/storage/pkg/homedir" pmount "github.com/containers/storage/pkg/mount" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux/label" @@ -48,782 +23,70 @@ import ( "golang.org/x/sys/unix" ) -const ( - // This is Conmon's STDIO_BUF_SIZE. I don't believe we have access to it - // directly from the Go code, so const it here - // Important: The conmon attach socket uses an extra byte at the beginning of each - // message to specify the STREAM so we have to increase the buffer size by one - bufferSize = conmonConfig.BufSize + 1 -) - -// ConmonOCIRuntime is an OCI runtime managed by Conmon. -// TODO: Make all calls to OCI runtime have a timeout. -type ConmonOCIRuntime struct { - name string - path string - conmonPath string - conmonEnv []string - tmpDir string - exitsDir string - logSizeMax int64 - noPivot bool - reservePorts bool - runtimeFlags []string - supportsJSON bool - supportsKVM bool - supportsNoCgroups bool - enableKeyring bool -} - -// Make a new Conmon-based OCI runtime with the given options. -// Conmon will wrap the given OCI runtime, which can be `runc`, `crun`, or -// any runtime with a runc-compatible CLI. -// The first path that points to a valid executable will be used. -// Deliberately private. Someone should not be able to construct this outside of -// libpod. -func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeFlags []string, runtimeCfg *config.Config) (OCIRuntime, error) { - if name == "" { - return nil, fmt.Errorf("the OCI runtime must be provided a non-empty name: %w", define.ErrInvalidArg) - } - - // Make lookup tables for runtime support - supportsJSON := make(map[string]bool, len(runtimeCfg.Engine.RuntimeSupportsJSON)) - supportsNoCgroups := make(map[string]bool, len(runtimeCfg.Engine.RuntimeSupportsNoCgroups)) - supportsKVM := make(map[string]bool, len(runtimeCfg.Engine.RuntimeSupportsKVM)) - for _, r := range runtimeCfg.Engine.RuntimeSupportsJSON { - supportsJSON[r] = true - } - for _, r := range runtimeCfg.Engine.RuntimeSupportsNoCgroups { - supportsNoCgroups[r] = true - } - for _, r := range runtimeCfg.Engine.RuntimeSupportsKVM { - supportsKVM[r] = true - } - - runtime := new(ConmonOCIRuntime) - runtime.name = name - runtime.conmonPath = conmonPath - runtime.runtimeFlags = runtimeFlags - - runtime.conmonEnv = runtimeCfg.Engine.ConmonEnvVars - runtime.tmpDir = runtimeCfg.Engine.TmpDir - runtime.logSizeMax = runtimeCfg.Containers.LogSizeMax - runtime.noPivot = runtimeCfg.Engine.NoPivotRoot - runtime.reservePorts = runtimeCfg.Engine.EnablePortReservation - runtime.enableKeyring = runtimeCfg.Containers.EnableKeyring - - // TODO: probe OCI runtime for feature and enable automatically if - // available. - - base := filepath.Base(name) - runtime.supportsJSON = supportsJSON[base] - runtime.supportsNoCgroups = supportsNoCgroups[base] - runtime.supportsKVM = supportsKVM[base] - - foundPath := false - for _, path := range paths { - stat, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - continue - } - return nil, fmt.Errorf("cannot stat OCI runtime %s path: %w", name, err) - } - if !stat.Mode().IsRegular() { - continue - } - foundPath = true - logrus.Tracef("found runtime %q", path) - runtime.path = path - break - } - - // Search the $PATH as last fallback - if !foundPath { - if foundRuntime, err := exec.LookPath(name); err == nil { - foundPath = true - runtime.path = foundRuntime - logrus.Debugf("using runtime %q from $PATH: %q", name, foundRuntime) - } - } - - if !foundPath { - return nil, fmt.Errorf("no valid executable found for OCI runtime %s: %w", name, define.ErrInvalidArg) - } - - runtime.exitsDir = filepath.Join(runtime.tmpDir, "exits") - - // Create the exit files and attach sockets directories - if err := os.MkdirAll(runtime.exitsDir, 0750); err != nil { - // The directory is allowed to exist - if !os.IsExist(err) { - return nil, fmt.Errorf("error creating OCI runtime exit files directory: %w", err) - } +func (r *ConmonOCIRuntime) createRootlessContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) (int64, error) { + type result struct { + restoreDuration int64 + err error } - return runtime, nil -} - -// Name returns the name of the runtime being wrapped by Conmon. -func (r *ConmonOCIRuntime) Name() string { - return r.name -} - -// Path returns the path of the OCI runtime being wrapped by Conmon. -func (r *ConmonOCIRuntime) Path() string { - return r.path -} - -// hasCurrentUserMapped checks whether the current user is mapped inside the container user namespace -func hasCurrentUserMapped(ctr *Container) bool { - if len(ctr.config.IDMappings.UIDMap) == 0 && len(ctr.config.IDMappings.GIDMap) == 0 { - return true - } - uid := os.Geteuid() - for _, m := range ctr.config.IDMappings.UIDMap { - if uid >= m.HostID && uid < m.HostID+m.Size { - return true - } - } - return false -} - -// CreateContainer creates a container. -func (r *ConmonOCIRuntime) CreateContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) (int64, error) { - // always make the run dir accessible to the current user so that the PID files can be read without - // being in the rootless user namespace. - if err := makeAccessible(ctr.state.RunDir, 0, 0); err != nil { - return 0, err - } - if !hasCurrentUserMapped(ctr) { - for _, i := range []string{ctr.state.RunDir, ctr.runtime.config.Engine.TmpDir, ctr.config.StaticDir, ctr.state.Mountpoint, ctr.runtime.config.Engine.VolumePath} { - if err := makeAccessible(i, ctr.RootUID(), ctr.RootGID()); err != nil { + ch := make(chan result) + go func() { + runtime.LockOSThread() + restoreDuration, err := func() (int64, error) { + fd, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid())) + if err != nil { return 0, err } - } + defer errorhandling.CloseQuiet(fd) - // if we are running a non privileged container, be sure to umount some kernel paths so they are not - // bind mounted inside the container at all. - if !ctr.config.Privileged && !rootless.IsRootless() { - type result struct { - restoreDuration int64 - err error + // create a new mountns on the current thread + if err = unix.Unshare(unix.CLONE_NEWNS); err != nil { + return 0, err } - ch := make(chan result) - go func() { - runtime.LockOSThread() - restoreDuration, err := func() (int64, error) { - fd, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid())) - if err != nil { - return 0, err - } - defer errorhandling.CloseQuiet(fd) - - // create a new mountns on the current thread - if err = unix.Unshare(unix.CLONE_NEWNS); err != nil { - return 0, err - } - defer func() { - if err := unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS); err != nil { - logrus.Errorf("Unable to clone new namespace: %q", err) - } - }() - - // don't spread our mounts around. We are setting only /sys to be slave - // so that the cleanup process is still able to umount the storage and the - // changes are propagated to the host. - err = unix.Mount("/sys", "/sys", "none", unix.MS_REC|unix.MS_SLAVE, "") - if err != nil { - return 0, fmt.Errorf("cannot make /sys slave: %w", err) - } - - mounts, err := pmount.GetMounts() - if err != nil { - return 0, err - } - for _, m := range mounts { - if !strings.HasPrefix(m.Mountpoint, "/sys/kernel") { - continue - } - err = unix.Unmount(m.Mountpoint, 0) - if err != nil && !os.IsNotExist(err) { - return 0, fmt.Errorf("cannot unmount %s: %w", m.Mountpoint, err) - } - } - return r.createOCIContainer(ctr, restoreOptions) - }() - ch <- result{ - restoreDuration: restoreDuration, - err: err, + defer func() { + if err := unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS); err != nil { + logrus.Errorf("Unable to clone new namespace: %q", err) } }() - r := <-ch - return r.restoreDuration, r.err - } - } - return r.createOCIContainer(ctr, restoreOptions) -} - -// UpdateContainerStatus retrieves the current status of the container from the -// runtime. It updates the container's state but does not save it. -// If useRuntime is false, we will not directly hit runc to see the container's -// status, but will instead only check for the existence of the conmon exit file -// and update state to stopped if it exists. -func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error { - runtimeDir, err := util.GetRuntimeDir() - if err != nil { - return err - } - - // Store old state so we know if we were already stopped - oldState := ctr.state.State - state := new(spec.State) - - cmd := exec.Command(r.path, "state", ctr.ID()) - cmd.Env = append(cmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)) - - outPipe, err := cmd.StdoutPipe() - if err != nil { - return fmt.Errorf("getting stdout pipe: %w", err) - } - errPipe, err := cmd.StderrPipe() - if err != nil { - return fmt.Errorf("getting stderr pipe: %w", err) - } - - if err := cmd.Start(); err != nil { - out, err2 := ioutil.ReadAll(errPipe) - if err2 != nil { - return fmt.Errorf("error getting container %s state: %w", ctr.ID(), err) - } - if strings.Contains(string(out), "does not exist") || strings.Contains(string(out), "No such file") { - if err := ctr.removeConmonFiles(); err != nil { - logrus.Debugf("unable to remove conmon files for container %s", ctr.ID()) - } - ctr.state.ExitCode = -1 - ctr.state.FinishedTime = time.Now() - ctr.state.State = define.ContainerStateExited - return ctr.runtime.state.AddContainerExitCode(ctr.ID(), ctr.state.ExitCode) - } - return fmt.Errorf("error getting container %s state. stderr/out: %s: %w", ctr.ID(), out, err) - } - defer func() { - _ = cmd.Wait() - }() - - if err := errPipe.Close(); err != nil { - return err - } - out, err := ioutil.ReadAll(outPipe) - if err != nil { - return fmt.Errorf("error reading stdout: %s: %w", ctr.ID(), err) - } - if err := json.NewDecoder(bytes.NewBuffer(out)).Decode(state); err != nil { - return fmt.Errorf("error decoding container status for container %s: %w", ctr.ID(), err) - } - ctr.state.PID = state.Pid - - switch state.Status { - case "created": - ctr.state.State = define.ContainerStateCreated - case "paused": - ctr.state.State = define.ContainerStatePaused - case "running": - ctr.state.State = define.ContainerStateRunning - case "stopped": - ctr.state.State = define.ContainerStateStopped - default: - return fmt.Errorf("unrecognized status returned by runtime for container %s: %s: %w", - ctr.ID(), state.Status, define.ErrInternal) - } - - // Only grab exit status if we were not already stopped - // If we were, it should already be in the database - if ctr.state.State == define.ContainerStateStopped && oldState != define.ContainerStateStopped { - if _, err := ctr.Wait(context.Background()); err != nil { - logrus.Errorf("Waiting for container %s to exit: %v", ctr.ID(), err) - } - return nil - } - - // Handle ContainerStateStopping - keep it unless the container - // transitioned to no longer running. - if oldState == define.ContainerStateStopping && (ctr.state.State == define.ContainerStatePaused || ctr.state.State == define.ContainerStateRunning) { - ctr.state.State = define.ContainerStateStopping - } - - return nil -} - -// StartContainer starts the given container. -// Sets time the container was started, but does not save it. -func (r *ConmonOCIRuntime) StartContainer(ctr *Container) error { - // TODO: streams should probably *not* be our STDIN/OUT/ERR - redirect to buffers? - runtimeDir, err := util.GetRuntimeDir() - if err != nil { - return err - } - env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - if path, ok := os.LookupEnv("PATH"); ok { - env = append(env, fmt.Sprintf("PATH=%s", path)) - } - if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "start", ctr.ID())...); err != nil { - return err - } - - ctr.state.StartedTime = time.Now() - - return nil -} - -// KillContainer sends the given signal to the given container. -// If all is set, send to all PIDs in the container. -// All is only supported if the container created cgroups. -func (r *ConmonOCIRuntime) KillContainer(ctr *Container, signal uint, all bool) error { - logrus.Debugf("Sending signal %d to container %s", signal, ctr.ID()) - runtimeDir, err := util.GetRuntimeDir() - if err != nil { - return err - } - env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - var args []string - args = append(args, r.runtimeFlags...) - if all { - args = append(args, "kill", "--all", ctr.ID(), fmt.Sprintf("%d", signal)) - } else { - args = append(args, "kill", ctr.ID(), fmt.Sprintf("%d", signal)) - } - if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, args...); err != nil { - // Update container state - there's a chance we failed because - // the container exited in the meantime. - if err2 := r.UpdateContainerStatus(ctr); err2 != nil { - logrus.Infof("Error updating status for container %s: %v", ctr.ID(), err2) - } - if ctr.ensureState(define.ContainerStateStopped, define.ContainerStateExited) { - return define.ErrCtrStateInvalid - } - return fmt.Errorf("error sending signal to container %s: %w", ctr.ID(), err) - } - - return nil -} - -// StopContainer stops a container, first using its given stop signal (or -// SIGTERM if no signal was specified), then using SIGKILL. -// Timeout is given in seconds. If timeout is 0, the container will be -// immediately kill with SIGKILL. -// Does not set finished time for container, assumes you will run updateStatus -// after to pull the exit code. -func (r *ConmonOCIRuntime) StopContainer(ctr *Container, timeout uint, all bool) error { - logrus.Debugf("Stopping container %s (PID %d)", ctr.ID(), ctr.state.PID) - - // Ping the container to see if it's alive - // If it's not, it's already stopped, return - err := unix.Kill(ctr.state.PID, 0) - if err == unix.ESRCH { - return nil - } - - stopSignal := ctr.config.StopSignal - if stopSignal == 0 { - stopSignal = uint(syscall.SIGTERM) - } - - if timeout > 0 { - if err := r.KillContainer(ctr, stopSignal, all); err != nil { - // Is the container gone? - // If so, it probably died between the first check and - // our sending the signal - // The container is stopped, so exit cleanly - err := unix.Kill(ctr.state.PID, 0) - if err == unix.ESRCH { - return nil + // don't spread our mounts around. We are setting only /sys to be slave + // so that the cleanup process is still able to umount the storage and the + // changes are propagated to the host. + err = unix.Mount("/sys", "/sys", "none", unix.MS_REC|unix.MS_SLAVE, "") + if err != nil { + return 0, fmt.Errorf("cannot make /sys slave: %w", err) } - return err - } - - if err := waitContainerStop(ctr, time.Duration(timeout)*time.Second); err != nil { - logrus.Debugf("Timed out stopping container %s with %s, resorting to SIGKILL: %v", ctr.ID(), unix.SignalName(syscall.Signal(stopSignal)), err) - logrus.Warnf("StopSignal %s failed to stop container %s in %d seconds, resorting to SIGKILL", unix.SignalName(syscall.Signal(stopSignal)), ctr.Name(), timeout) - } else { - // No error, the container is dead - return nil - } - } - - if err := r.KillContainer(ctr, 9, all); err != nil { - // Again, check if the container is gone. If it is, exit cleanly. - err := unix.Kill(ctr.state.PID, 0) - if err == unix.ESRCH { - return nil - } - - return fmt.Errorf("error sending SIGKILL to container %s: %w", ctr.ID(), err) - } - - // Give runtime a few seconds to make it happen - if err := waitContainerStop(ctr, killContainerTimeout); err != nil { - return err - } - - return nil -} - -// DeleteContainer deletes a container from the OCI runtime. -func (r *ConmonOCIRuntime) DeleteContainer(ctr *Container) error { - runtimeDir, err := util.GetRuntimeDir() - if err != nil { - return err - } - env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "delete", "--force", ctr.ID())...) -} - -// PauseContainer pauses the given container. -func (r *ConmonOCIRuntime) PauseContainer(ctr *Container) error { - runtimeDir, err := util.GetRuntimeDir() - if err != nil { - return err - } - env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "pause", ctr.ID())...) -} - -// UnpauseContainer unpauses the given container. -func (r *ConmonOCIRuntime) UnpauseContainer(ctr *Container) error { - runtimeDir, err := util.GetRuntimeDir() - if err != nil { - return err - } - env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "resume", ctr.ID())...) -} - -// HTTPAttach performs an attach for the HTTP API. -// The caller must handle closing the HTTP connection after this returns. -// The cancel channel is not closed; it is up to the caller to do so after -// this function returns. -// If this is a container with a terminal, we will stream raw. If it is not, we -// will stream with an 8-byte header to multiplex STDOUT and STDERR. -// Returns any errors that occurred, and whether the connection was successfully -// hijacked before that error occurred. -func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.ResponseWriter, streams *HTTPAttachStreams, detachKeys *string, cancel <-chan bool, hijackDone chan<- bool, streamAttach, streamLogs bool) (deferredErr error) { - isTerminal := false - if ctr.config.Spec.Process != nil { - isTerminal = ctr.config.Spec.Process.Terminal - } - - if streams != nil { - if !streams.Stdin && !streams.Stdout && !streams.Stderr { - return fmt.Errorf("must specify at least one stream to attach to: %w", define.ErrInvalidArg) - } - } - - attachSock, err := r.AttachSocketPath(ctr) - if err != nil { - return err - } - - var conn *net.UnixConn - if streamAttach { - newConn, err := openUnixSocket(attachSock) - if err != nil { - return fmt.Errorf("failed to connect to container's attach socket: %v: %w", attachSock, err) - } - conn = newConn - defer func() { - if err := conn.Close(); err != nil { - logrus.Errorf("Unable to close container %s attach socket: %q", ctr.ID(), err) + mounts, err := pmount.GetMounts() + if err != nil { + return 0, err } - }() - - logrus.Debugf("Successfully connected to container %s attach socket %s", ctr.ID(), attachSock) - } - - detachString := ctr.runtime.config.Engine.DetachKeys - if detachKeys != nil { - detachString = *detachKeys - } - detach, err := processDetachKeys(detachString) - if err != nil { - return err - } - - attachStdout := true - attachStderr := true - attachStdin := true - if streams != nil { - attachStdout = streams.Stdout - attachStderr = streams.Stderr - attachStdin = streams.Stdin - } - - logrus.Debugf("Going to hijack container %s attach connection", ctr.ID()) - - // Alright, let's hijack. - hijacker, ok := w.(http.Hijacker) - if !ok { - return fmt.Errorf("unable to hijack connection") - } - - httpCon, httpBuf, err := hijacker.Hijack() - if err != nil { - return fmt.Errorf("error hijacking connection: %w", err) - } - - hijackDone <- true - - writeHijackHeader(req, httpBuf) - - // Force a flush after the header is written. - if err := httpBuf.Flush(); err != nil { - return fmt.Errorf("error flushing HTTP hijack header: %w", err) - } - - defer func() { - hijackWriteErrorAndClose(deferredErr, ctr.ID(), isTerminal, httpCon, httpBuf) - }() - - logrus.Debugf("Hijack for container %s attach session done, ready to stream", ctr.ID()) - - // TODO: This is gross. Really, really gross. - // I want to say we should read all the logs into an array before - // calling this, in container_api.go, but that could take a lot of - // memory... - // On the whole, we need to figure out a better way of doing this, - // though. - logSize := 0 - if streamLogs { - logrus.Debugf("Will stream logs for container %s attach session", ctr.ID()) - - // Get all logs for the container - logChan := make(chan *logs.LogLine) - logOpts := new(logs.LogOptions) - logOpts.Tail = -1 - logOpts.WaitGroup = new(sync.WaitGroup) - errChan := make(chan error) - go func() { - var err error - // In non-terminal mode we need to prepend with the - // stream header. - logrus.Debugf("Writing logs for container %s to HTTP attach", ctr.ID()) - for logLine := range logChan { - if !isTerminal { - device := logLine.Device - var header []byte - headerLen := uint32(len(logLine.Msg)) - logSize += len(logLine.Msg) - switch strings.ToLower(device) { - case "stdin": - header = makeHTTPAttachHeader(0, headerLen) - case "stdout": - header = makeHTTPAttachHeader(1, headerLen) - case "stderr": - header = makeHTTPAttachHeader(2, headerLen) - default: - logrus.Errorf("Unknown device for log line: %s", device) - header = makeHTTPAttachHeader(1, headerLen) - } - _, err = httpBuf.Write(header) - if err != nil { - break - } - } - _, err = httpBuf.Write([]byte(logLine.Msg)) - if err != nil { - break - } - if !logLine.Partial() { - _, err = httpBuf.Write([]byte("\n")) - if err != nil { - break - } + for _, m := range mounts { + if !strings.HasPrefix(m.Mountpoint, "/sys/kernel") { + continue } - err = httpBuf.Flush() - if err != nil { - break + err = unix.Unmount(m.Mountpoint, 0) + if err != nil && !os.IsNotExist(err) { + return 0, fmt.Errorf("cannot unmount %s: %w", m.Mountpoint, err) } } - errChan <- err - }() - if err := ctr.ReadLog(context.Background(), logOpts, logChan, 0); err != nil { - return err - } - go func() { - logOpts.WaitGroup.Wait() - close(logChan) + return r.createOCIContainer(ctr, restoreOptions) }() - logrus.Debugf("Done reading logs for container %s, %d bytes", ctr.ID(), logSize) - if err := <-errChan; err != nil { - return err + ch <- result{ + restoreDuration: restoreDuration, + err: err, } - } - if !streamAttach { - logrus.Debugf("Done streaming logs for container %s attach, exiting as attach streaming not requested", ctr.ID()) - return nil - } - - logrus.Debugf("Forwarding attach output for container %s", ctr.ID()) - - stdoutChan := make(chan error) - stdinChan := make(chan error) - - // Handle STDOUT/STDERR - go func() { - var err error - if isTerminal { - // Hack: return immediately if attachStdout not set to - // emulate Docker. - // Basically, when terminal is set, STDERR goes nowhere. - // Everything does over STDOUT. - // Therefore, if not attaching STDOUT - we'll never copy - // anything from here. - logrus.Debugf("Performing terminal HTTP attach for container %s", ctr.ID()) - if attachStdout { - err = httpAttachTerminalCopy(conn, httpBuf, ctr.ID()) - } - } else { - logrus.Debugf("Performing non-terminal HTTP attach for container %s", ctr.ID()) - err = httpAttachNonTerminalCopy(conn, httpBuf, ctr.ID(), attachStdin, attachStdout, attachStderr) - } - stdoutChan <- err - logrus.Debugf("STDOUT/ERR copy completed") }() - // Next, STDIN. Avoid entirely if attachStdin unset. - if attachStdin { - go func() { - _, err := cutil.CopyDetachable(conn, httpBuf, detach) - logrus.Debugf("STDIN copy completed") - stdinChan <- err - }() - } - - for { - select { - case err := <-stdoutChan: - if err != nil { - return err - } - - return nil - case err := <-stdinChan: - if err != nil { - return err - } - // copy stdin is done, close it - if connErr := conn.CloseWrite(); connErr != nil { - logrus.Errorf("Unable to close conn: %v", connErr) - } - case <-cancel: - return nil - } - } -} - -// isRetryable returns whether the error was caused by a blocked syscall or the -// specified operation on a non blocking file descriptor wasn't ready for completion. -func isRetryable(err error) bool { - var errno syscall.Errno - if errors.As(err, &errno) { - return errno == syscall.EINTR || errno == syscall.EAGAIN - } - return false + res := <-ch + return res.restoreDuration, res.err } -// openControlFile opens the terminal control file. -func openControlFile(ctr *Container, parentDir string) (*os.File, error) { - controlPath := filepath.Join(parentDir, "ctl") - for i := 0; i < 600; i++ { - controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY|unix.O_NONBLOCK, 0) - if err == nil { - return controlFile, nil - } - if !isRetryable(err) { - return nil, fmt.Errorf("could not open ctl file for terminal resize for container %s: %w", ctr.ID(), err) - } - time.Sleep(time.Second / 10) - } - return nil, fmt.Errorf("timeout waiting for %q", controlPath) -} - -// AttachResize resizes the terminal used by the given container. -func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize resize.TerminalSize) error { - controlFile, err := openControlFile(ctr, ctr.bundlePath()) - if err != nil { - return err - } - defer controlFile.Close() - - logrus.Debugf("Received a resize event for container %s: %+v", ctr.ID(), newSize) - if _, err = fmt.Fprintf(controlFile, "%d %d %d\n", 1, newSize.Height, newSize.Width); err != nil { - return fmt.Errorf("failed to write to ctl file to resize terminal: %w", err) - } - - return nil -} - -// CheckpointContainer checkpoints the given container. -func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options ContainerCheckpointOptions) (int64, error) { - // imagePath is used by CRIU to store the actual checkpoint files - imagePath := ctr.CheckpointPath() - if options.PreCheckPoint { - imagePath = ctr.PreCheckPointPath() - } - // workPath will be used to store dump.log and stats-dump - workPath := ctr.bundlePath() - logrus.Debugf("Writing checkpoint to %s", imagePath) - logrus.Debugf("Writing checkpoint logs to %s", workPath) - logrus.Debugf("Pre-dump the container %t", options.PreCheckPoint) - args := []string{} - args = append(args, r.runtimeFlags...) - args = append(args, "checkpoint") - args = append(args, "--image-path") - args = append(args, imagePath) - args = append(args, "--work-path") - args = append(args, workPath) - if options.KeepRunning { - args = append(args, "--leave-running") - } - if options.TCPEstablished { - args = append(args, "--tcp-established") - } - if options.FileLocks { - args = append(args, "--file-locks") - } - if !options.PreCheckPoint && options.KeepRunning { - args = append(args, "--leave-running") - } - if options.PreCheckPoint { - args = append(args, "--pre-dump") - } - if !options.PreCheckPoint && options.WithPrevious { - args = append( - args, - "--parent-path", - filepath.Join("..", preCheckpointDir), - ) - } - - args = append(args, ctr.ID()) - logrus.Debugf("the args to checkpoint: %s %s", r.path, strings.Join(args, " ")) - - runtimeDir, err := util.GetRuntimeDir() - if err != nil { - return 0, err - } - env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - if path, ok := os.LookupEnv("PATH"); ok { - env = append(env, fmt.Sprintf("PATH=%s", path)) - } - +// Run the closure with the container's socket label set +func (r *ConmonOCIRuntime) withContainerSocketLabel(ctr *Container, closure func() error) error { runtime.LockOSThread() if err := label.SetSocketLabel(ctr.ProcessLabel()); err != nil { - return 0, err + return err } - - runtimeCheckpointStarted := time.Now() - err = utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, args...) + err := closure() // Ignore error returned from SetSocketLabel("") call, // can't recover. if labelErr := label.SetSocketLabel(""); labelErr == nil { @@ -834,576 +97,7 @@ func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options Container } else { logrus.Errorf("Unable to reset socket label: %q", labelErr) } - - runtimeCheckpointDuration := func() int64 { - if options.PrintStats { - return time.Since(runtimeCheckpointStarted).Microseconds() - } - return 0 - }() - - return runtimeCheckpointDuration, err -} - -func (r *ConmonOCIRuntime) CheckConmonRunning(ctr *Container) (bool, error) { - if ctr.state.ConmonPID == 0 { - // If the container is running or paused, assume Conmon is - // running. We didn't record Conmon PID on some old versions, so - // that is likely what's going on... - // Unusual enough that we should print a warning message though. - if ctr.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) { - logrus.Warnf("Conmon PID is not set, but container is running!") - return true, nil - } - // Container's not running, so conmon PID being unset is - // expected. Conmon is not running. - return false, nil - } - - // We have a conmon PID. Ping it with signal 0. - if err := unix.Kill(ctr.state.ConmonPID, 0); err != nil { - if err == unix.ESRCH { - return false, nil - } - return false, fmt.Errorf("error pinging container %s conmon with signal 0: %w", ctr.ID(), err) - } - return true, nil -} - -// SupportsCheckpoint checks if the OCI runtime supports checkpointing -// containers. -func (r *ConmonOCIRuntime) SupportsCheckpoint() bool { - return crutils.CRRuntimeSupportsCheckpointRestore(r.path) -} - -// SupportsJSONErrors checks if the OCI runtime supports JSON-formatted error -// messages. -func (r *ConmonOCIRuntime) SupportsJSONErrors() bool { - return r.supportsJSON -} - -// SupportsNoCgroups checks if the OCI runtime supports running containers -// without cgroups (the --cgroup-manager=disabled flag). -func (r *ConmonOCIRuntime) SupportsNoCgroups() bool { - return r.supportsNoCgroups -} - -// SupportsKVM checks if the OCI runtime supports running containers -// without KVM separation -func (r *ConmonOCIRuntime) SupportsKVM() bool { - return r.supportsKVM -} - -// AttachSocketPath is the path to a single container's attach socket. -func (r *ConmonOCIRuntime) AttachSocketPath(ctr *Container) (string, error) { - if ctr == nil { - return "", fmt.Errorf("must provide a valid container to get attach socket path: %w", define.ErrInvalidArg) - } - - return filepath.Join(ctr.bundlePath(), "attach"), nil -} - -// ExitFilePath is the path to a container's exit file. -func (r *ConmonOCIRuntime) ExitFilePath(ctr *Container) (string, error) { - if ctr == nil { - return "", fmt.Errorf("must provide a valid container to get exit file path: %w", define.ErrInvalidArg) - } - return filepath.Join(r.exitsDir, ctr.ID()), nil -} - -// RuntimeInfo provides information on the runtime. -func (r *ConmonOCIRuntime) RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error) { - runtimePackage := packageVersion(r.path) - conmonPackage := packageVersion(r.conmonPath) - runtimeVersion, err := r.getOCIRuntimeVersion() - if err != nil { - return nil, nil, fmt.Errorf("error getting version of OCI runtime %s: %w", r.name, err) - } - conmonVersion, err := r.getConmonVersion() - if err != nil { - return nil, nil, fmt.Errorf("error getting conmon version: %w", err) - } - - conmon := define.ConmonInfo{ - Package: conmonPackage, - Path: r.conmonPath, - Version: conmonVersion, - } - ocirt := define.OCIRuntimeInfo{ - Name: r.name, - Path: r.path, - Package: runtimePackage, - Version: runtimeVersion, - } - return &conmon, &ocirt, nil -} - -// makeAccessible changes the path permission and each parent directory to have --x--x--x -func makeAccessible(path string, uid, gid int) error { - for ; path != "/"; path = filepath.Dir(path) { - st, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - return nil - } - return err - } - if int(st.Sys().(*syscall.Stat_t).Uid) == uid && int(st.Sys().(*syscall.Stat_t).Gid) == gid { - continue - } - if st.Mode()&0111 != 0111 { - if err := os.Chmod(path, st.Mode()|0111); err != nil { - return err - } - } - } - return nil -} - -// Wait for a container which has been sent a signal to stop -func waitContainerStop(ctr *Container, timeout time.Duration) error { - return waitPidStop(ctr.state.PID, timeout) -} - -// Wait for a given PID to stop -func waitPidStop(pid int, timeout time.Duration) error { - done := make(chan struct{}) - chControl := make(chan struct{}) - go func() { - for { - select { - case <-chControl: - return - default: - if err := unix.Kill(pid, 0); err != nil { - if err == unix.ESRCH { - close(done) - return - } - logrus.Errorf("Pinging PID %d with signal 0: %v", pid, err) - } - time.Sleep(100 * time.Millisecond) - } - } - }() - select { - case <-done: - return nil - case <-time.After(timeout): - close(chControl) - return fmt.Errorf("given PIDs did not die within timeout") - } -} - -func (r *ConmonOCIRuntime) getLogTag(ctr *Container) (string, error) { - logTag := ctr.LogTag() - if logTag == "" { - return "", nil - } - data, err := ctr.inspectLocked(false) - if err != nil { - // FIXME: this error should probably be returned - return "", nil //nolint: nilerr - } - tmpl, err := template.New("container").Parse(logTag) - if err != nil { - return "", fmt.Errorf("template parsing error %s: %w", logTag, err) - } - var b bytes.Buffer - err = tmpl.Execute(&b, data) - if err != nil { - return "", err - } - return b.String(), nil -} - -// createOCIContainer generates this container's main conmon instance and prepares it for starting -func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) (int64, error) { - var stderrBuf bytes.Buffer - - runtimeDir, err := util.GetRuntimeDir() - if err != nil { - return 0, err - } - - parentSyncPipe, childSyncPipe, err := newPipe() - if err != nil { - return 0, fmt.Errorf("error creating socket pair: %w", err) - } - defer errorhandling.CloseQuiet(parentSyncPipe) - - childStartPipe, parentStartPipe, err := newPipe() - if err != nil { - return 0, fmt.Errorf("error creating socket pair for start pipe: %w", err) - } - - defer errorhandling.CloseQuiet(parentStartPipe) - - var ociLog string - if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON { - ociLog = filepath.Join(ctr.state.RunDir, "oci-log") - } - - logTag, err := r.getLogTag(ctr) - if err != nil { - return 0, err - } - - if ctr.config.CgroupsMode == cgroupSplit { - if err := utils.MoveUnderCgroupSubtree("runtime"); err != nil { - return 0, err - } - } - - pidfile := ctr.config.PidFile - if pidfile == "" { - pidfile = filepath.Join(ctr.state.RunDir, "pidfile") - } - - args := r.sharedConmonArgs(ctr, ctr.ID(), ctr.bundlePath(), pidfile, ctr.LogPath(), r.exitsDir, ociLog, ctr.LogDriver(), logTag) - - if ctr.config.SdNotifyMode == define.SdNotifyModeContainer && ctr.config.SdNotifySocket != "" { - args = append(args, fmt.Sprintf("--sdnotify-socket=%s", ctr.config.SdNotifySocket)) - } - - if ctr.config.Spec.Process.Terminal { - args = append(args, "-t") - } else if ctr.config.Stdin { - args = append(args, "-i") - } - - if ctr.config.Timeout > 0 { - args = append(args, fmt.Sprintf("--timeout=%d", ctr.config.Timeout)) - } - - if !r.enableKeyring { - args = append(args, "--no-new-keyring") - } - if ctr.config.ConmonPidFile != "" { - args = append(args, "--conmon-pidfile", ctr.config.ConmonPidFile) - } - - if r.noPivot { - args = append(args, "--no-pivot") - } - - exitCommand, err := specgenutil.CreateExitCommandArgs(ctr.runtime.storageConfig, ctr.runtime.config, logrus.IsLevelEnabled(logrus.DebugLevel), ctr.AutoRemove(), false) - if err != nil { - return 0, err - } - exitCommand = append(exitCommand, ctr.config.ID) - - args = append(args, "--exit-command", exitCommand[0]) - for _, arg := range exitCommand[1:] { - args = append(args, []string{"--exit-command-arg", arg}...) - } - - // Pass down the LISTEN_* environment (see #10443). - preserveFDs := ctr.config.PreserveFDs - if val := os.Getenv("LISTEN_FDS"); val != "" { - if ctr.config.PreserveFDs > 0 { - logrus.Warnf("Ignoring LISTEN_FDS to preserve custom user-specified FDs") - } else { - fds, err := strconv.Atoi(val) - if err != nil { - return 0, fmt.Errorf("converting LISTEN_FDS=%s: %w", val, err) - } - preserveFDs = uint(fds) - } - } - - if preserveFDs > 0 { - args = append(args, formatRuntimeOpts("--preserve-fds", fmt.Sprintf("%d", preserveFDs))...) - } - - if restoreOptions != nil { - args = append(args, "--restore", ctr.CheckpointPath()) - if restoreOptions.TCPEstablished { - args = append(args, "--runtime-opt", "--tcp-established") - } - if restoreOptions.FileLocks { - args = append(args, "--runtime-opt", "--file-locks") - } - if restoreOptions.Pod != "" { - mountLabel := ctr.config.MountLabel - processLabel := ctr.config.ProcessLabel - if mountLabel != "" { - args = append( - args, - "--runtime-opt", - fmt.Sprintf( - "--lsm-mount-context=%s", - mountLabel, - ), - ) - } - if processLabel != "" { - args = append( - args, - "--runtime-opt", - fmt.Sprintf( - "--lsm-profile=selinux:%s", - processLabel, - ), - ) - } - } - } - - logrus.WithFields(logrus.Fields{ - "args": args, - }).Debugf("running conmon: %s", r.conmonPath) - - cmd := exec.Command(r.conmonPath, args...) - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setpgid: true, - } - // TODO this is probably a really bad idea for some uses - // Make this configurable - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if ctr.config.Spec.Process.Terminal { - cmd.Stderr = &stderrBuf - } - - // 0, 1 and 2 are stdin, stdout and stderr - conmonEnv := r.configureConmonEnv(runtimeDir) - - var filesToClose []*os.File - if preserveFDs > 0 { - for fd := 3; fd < int(3+preserveFDs); fd++ { - f := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)) - filesToClose = append(filesToClose, f) - cmd.ExtraFiles = append(cmd.ExtraFiles, f) - } - } - - cmd.Env = r.conmonEnv - // we don't want to step on users fds they asked to preserve - // Since 0-2 are used for stdio, start the fds we pass in at preserveFDs+3 - cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", preserveFDs+3), fmt.Sprintf("_OCI_STARTPIPE=%d", preserveFDs+4)) - cmd.Env = append(cmd.Env, conmonEnv...) - cmd.ExtraFiles = append(cmd.ExtraFiles, childSyncPipe, childStartPipe) - - if r.reservePorts && !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() { - ports, err := bindPorts(ctr.convertPortMappings()) - if err != nil { - return 0, err - } - filesToClose = append(filesToClose, ports...) - - // Leak the port we bound in the conmon process. These fd's won't be used - // by the container and conmon will keep the ports busy so that another - // process cannot use them. - cmd.ExtraFiles = append(cmd.ExtraFiles, ports...) - } - - if ctr.config.NetMode.IsSlirp4netns() || rootless.IsRootless() { - if ctr.config.PostConfigureNetNS { - havePortMapping := len(ctr.config.PortMappings) > 0 - if havePortMapping { - ctr.rootlessPortSyncR, ctr.rootlessPortSyncW, err = os.Pipe() - if err != nil { - return 0, fmt.Errorf("failed to create rootless port sync pipe: %w", err) - } - } - ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe() - if err != nil { - return 0, fmt.Errorf("failed to create rootless network sync pipe: %w", err) - } - } else { - if ctr.rootlessSlirpSyncR != nil { - defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR) - } - if ctr.rootlessSlirpSyncW != nil { - defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW) - } - } - // Leak one end in conmon, the other one will be leaked into slirp4netns - cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessSlirpSyncW) - - if ctr.rootlessPortSyncW != nil { - defer errorhandling.CloseQuiet(ctr.rootlessPortSyncW) - // Leak one end in conmon, the other one will be leaked into rootlessport - cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessPortSyncW) - } - } - var runtimeRestoreStarted time.Time - if restoreOptions != nil { - runtimeRestoreStarted = time.Now() - } - err = startCommand(cmd, ctr) - - // regardless of whether we errored or not, we no longer need the children pipes - childSyncPipe.Close() - childStartPipe.Close() - if err != nil { - return 0, err - } - if err := r.moveConmonToCgroupAndSignal(ctr, cmd, parentStartPipe); err != nil { - return 0, err - } - /* Wait for initial setup and fork, and reap child */ - err = cmd.Wait() - if err != nil { - return 0, err - } - - pid, err := readConmonPipeData(r.name, parentSyncPipe, ociLog) - if err != nil { - if err2 := r.DeleteContainer(ctr); err2 != nil { - logrus.Errorf("Removing container %s from runtime after creation failed", ctr.ID()) - } - return 0, err - } - ctr.state.PID = pid - - conmonPID, err := readConmonPidFile(ctr.config.ConmonPidFile) - if err != nil { - logrus.Warnf("Error reading conmon pid file for container %s: %v", ctr.ID(), err) - } else if conmonPID > 0 { - // conmon not having a pid file is a valid state, so don't set it if we don't have it - logrus.Infof("Got Conmon PID as %d", conmonPID) - ctr.state.ConmonPID = conmonPID - } - - runtimeRestoreDuration := func() int64 { - if restoreOptions != nil && restoreOptions.PrintStats { - return time.Since(runtimeRestoreStarted).Microseconds() - } - return 0 - }() - - // These fds were passed down to the runtime. Close them - // and not interfere - for _, f := range filesToClose { - errorhandling.CloseQuiet(f) - } - - return runtimeRestoreDuration, nil -} - -// configureConmonEnv gets the environment values to add to conmon's exec struct -// TODO this may want to be less hardcoded/more configurable in the future -func (r *ConmonOCIRuntime) configureConmonEnv(runtimeDir string) []string { - var env []string - for _, e := range os.Environ() { - if strings.HasPrefix(e, "LC_") { - env = append(env, e) - } - } - conf, ok := os.LookupEnv("CONTAINERS_CONF") - if ok { - env = append(env, fmt.Sprintf("CONTAINERS_CONF=%s", conf)) - } - env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)) - env = append(env, fmt.Sprintf("_CONTAINERS_USERNS_CONFIGURED=%s", os.Getenv("_CONTAINERS_USERNS_CONFIGURED"))) - env = append(env, fmt.Sprintf("_CONTAINERS_ROOTLESS_UID=%s", os.Getenv("_CONTAINERS_ROOTLESS_UID"))) - home := homedir.Get() - if home != "" { - env = append(env, fmt.Sprintf("HOME=%s", home)) - } - - return env -} - -// sharedConmonArgs takes common arguments for exec and create/restore and formats them for the conmon CLI -func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, pidPath, logPath, exitDir, ociLogPath, logDriver, logTag string) []string { - // set the conmon API version to be able to use the correct sync struct keys - args := []string{ - "--api-version", "1", - "-c", ctr.ID(), - "-u", cuuid, - "-r", r.path, - "-b", bundlePath, - "-p", pidPath, - "-n", ctr.Name(), - "--exit-dir", exitDir, - "--full-attach", - } - if len(r.runtimeFlags) > 0 { - rFlags := []string{} - for _, arg := range r.runtimeFlags { - rFlags = append(rFlags, "--runtime-arg", arg) - } - args = append(args, rFlags...) - } - - if ctr.CgroupManager() == config.SystemdCgroupsManager && !ctr.config.NoCgroups && ctr.config.CgroupsMode != cgroupSplit { - args = append(args, "-s") - } - - var logDriverArg string - switch logDriver { - case define.JournaldLogging: - logDriverArg = define.JournaldLogging - case define.NoLogging: - logDriverArg = define.NoLogging - case define.PassthroughLogging: - logDriverArg = define.PassthroughLogging - //lint:ignore ST1015 the default case has to be here - default: //nolint:stylecheck,gocritic - // No case here should happen except JSONLogging, but keep this here in case the options are extended - logrus.Errorf("%s logging specified but not supported. Choosing k8s-file logging instead", ctr.LogDriver()) - fallthrough - case "": - // to get here, either a user would specify `--log-driver ""`, or this came from another place in libpod - // since the former case is obscure, and the latter case isn't an error, let's silently fallthrough - fallthrough - case define.JSONLogging: - fallthrough - case define.KubernetesLogging: - logDriverArg = fmt.Sprintf("%s:%s", define.KubernetesLogging, logPath) - } - - args = append(args, "-l", logDriverArg) - logLevel := logrus.GetLevel() - args = append(args, "--log-level", logLevel.String()) - - if logLevel == logrus.DebugLevel { - logrus.Debugf("%s messages will be logged to syslog", r.conmonPath) - args = append(args, "--syslog") - } - - size := r.logSizeMax - if ctr.config.LogSize > 0 { - size = ctr.config.LogSize - } - if size > 0 { - args = append(args, "--log-size-max", fmt.Sprintf("%v", size)) - } - - if ociLogPath != "" { - args = append(args, "--runtime-arg", "--log-format=json", "--runtime-arg", "--log", fmt.Sprintf("--runtime-arg=%s", ociLogPath)) - } - if logTag != "" { - args = append(args, "--log-tag", logTag) - } - if ctr.config.NoCgroups { - logrus.Debugf("Running with no Cgroups") - args = append(args, "--runtime-arg", "--cgroup-manager", "--runtime-arg", "disabled") - } - return args -} - -func startCommand(cmd *exec.Cmd, ctr *Container) error { - // Make sure to unset the NOTIFY_SOCKET and reset it afterwards if needed. - switch ctr.config.SdNotifyMode { - case define.SdNotifyModeContainer, define.SdNotifyModeIgnore: - if prev := os.Getenv("NOTIFY_SOCKET"); prev != "" { - if err := os.Unsetenv("NOTIFY_SOCKET"); err != nil { - logrus.Warnf("Error unsetting NOTIFY_SOCKET %v", err) - } - defer func() { - if err := os.Setenv("NOTIFY_SOCKET", prev); err != nil { - logrus.Errorf("Resetting NOTIFY_SOCKET=%s", prev) - } - }() - } - } - - return cmd.Start() + return err } // moveConmonToCgroupAndSignal gets a container's cgroupParent and moves the conmon process to that cgroup @@ -1475,271 +169,6 @@ func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec return nil } -// newPipe creates a unix socket pair for communication. -// Returns two files - first is parent, second is child. -func newPipe() (*os.File, *os.File, error) { - fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_SEQPACKET|unix.SOCK_CLOEXEC, 0) - if err != nil { - return nil, nil, err - } - return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil -} - -// readConmonPidFile attempts to read conmon's pid from its pid file -func readConmonPidFile(pidFile string) (int, error) { - // Let's try reading the Conmon pid at the same time. - if pidFile != "" { - contents, err := ioutil.ReadFile(pidFile) - if err != nil { - return -1, err - } - // Convert it to an int - conmonPID, err := strconv.Atoi(string(contents)) - if err != nil { - return -1, err - } - return conmonPID, nil - } - return 0, nil -} - -// readConmonPipeData attempts to read a syncInfo struct from the pipe -func readConmonPipeData(runtimeName string, pipe *os.File, ociLog string) (int, error) { - // syncInfo is used to return data from monitor process to daemon - type syncInfo struct { - Data int `json:"data"` - Message string `json:"message,omitempty"` - } - - // Wait to get container pid from conmon - type syncStruct struct { - si *syncInfo - err error - } - ch := make(chan syncStruct) - go func() { - var si *syncInfo - rdr := bufio.NewReader(pipe) - b, err := rdr.ReadBytes('\n') - // ignore EOF here, error is returned even when data was read - // if it is no valid json unmarshal will fail below - if err != nil && !errors.Is(err, io.EOF) { - ch <- syncStruct{err: err} - } - if err := json.Unmarshal(b, &si); err != nil { - ch <- syncStruct{err: fmt.Errorf("conmon bytes %q: %w", string(b), err)} - return - } - ch <- syncStruct{si: si} - }() - - data := -1 //nolint: wastedassign - select { - case ss := <-ch: - if ss.err != nil { - if ociLog != "" { - ociLogData, err := ioutil.ReadFile(ociLog) - if err == nil { - var ociErr ociError - if err := json.Unmarshal(ociLogData, &ociErr); err == nil { - return -1, getOCIRuntimeError(runtimeName, ociErr.Msg) - } - } - } - return -1, fmt.Errorf("container create failed (no logs from conmon): %w", ss.err) - } - logrus.Debugf("Received: %d", ss.si.Data) - if ss.si.Data < 0 { - if ociLog != "" { - ociLogData, err := ioutil.ReadFile(ociLog) - if err == nil { - var ociErr ociError - if err := json.Unmarshal(ociLogData, &ociErr); err == nil { - return ss.si.Data, getOCIRuntimeError(runtimeName, ociErr.Msg) - } - } - } - // If we failed to parse the JSON errors, then print the output as it is - if ss.si.Message != "" { - return ss.si.Data, getOCIRuntimeError(runtimeName, ss.si.Message) - } - return ss.si.Data, fmt.Errorf("container create failed: %w", define.ErrInternal) - } - data = ss.si.Data - case <-time.After(define.ContainerCreateTimeout): - return -1, fmt.Errorf("container creation timeout: %w", define.ErrInternal) - } - return data, nil -} - -// writeConmonPipeData writes nonce data to a pipe -func writeConmonPipeData(pipe *os.File) error { - someData := []byte{0} - _, err := pipe.Write(someData) - return err -} - -// formatRuntimeOpts prepends opts passed to it with --runtime-opt for passing to conmon -func formatRuntimeOpts(opts ...string) []string { - args := make([]string, 0, len(opts)*2) - for _, o := range opts { - args = append(args, "--runtime-opt", o) - } - return args -} - -// getConmonVersion returns a string representation of the conmon version. -func (r *ConmonOCIRuntime) getConmonVersion() (string, error) { - output, err := utils.ExecCmd(r.conmonPath, "--version") - if err != nil { - return "", err - } - return strings.TrimSuffix(strings.Replace(output, "\n", ", ", 1), "\n"), nil -} - -// getOCIRuntimeVersion returns a string representation of the OCI runtime's -// version. -func (r *ConmonOCIRuntime) getOCIRuntimeVersion() (string, error) { - output, err := utils.ExecCmd(r.path, "--version") - if err != nil { - return "", err - } - return strings.TrimSuffix(output, "\n"), nil -} - -// Copy data from container to HTTP connection, for terminal attach. -// Container is the container's attach socket connection, http is a buffer for -// the HTTP connection. cid is the ID of the container the attach session is -// running for (used solely for error messages). -func httpAttachTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, cid string) error { - buf := make([]byte, bufferSize) - for { - numR, err := container.Read(buf) - logrus.Debugf("Read fd(%d) %d/%d bytes for container %s", int(buf[0]), numR, len(buf), cid) - - if numR > 0 { - switch buf[0] { - case AttachPipeStdout: - // Do nothing - default: - logrus.Errorf("Received unexpected attach type %+d, discarding %d bytes", buf[0], numR) - continue - } - - numW, err2 := http.Write(buf[1:numR]) - if err2 != nil { - if err != nil { - logrus.Errorf("Reading container %s STDOUT: %v", cid, err) - } - return err2 - } else if numW+1 != numR { - return io.ErrShortWrite - } - // We need to force the buffer to write immediately, so - // there isn't a delay on the terminal side. - if err2 := http.Flush(); err2 != nil { - if err != nil { - logrus.Errorf("Reading container %s STDOUT: %v", cid, err) - } - return err2 - } - } - if err != nil { - if err == io.EOF { - return nil - } - return err - } - } -} - -// Copy data from a container to an HTTP connection, for non-terminal attach. -// Appends a header to multiplex input. -func httpAttachNonTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, cid string, stdin, stdout, stderr bool) error { - buf := make([]byte, bufferSize) - for { - numR, err := container.Read(buf) - if numR > 0 { - var headerBuf []byte - - // Subtract 1 because we strip the first byte (used for - // multiplexing by Conmon). - headerLen := uint32(numR - 1) - // Practically speaking, we could make this buf[0] - 1, - // but we need to validate it anyway. - switch buf[0] { - case AttachPipeStdin: - headerBuf = makeHTTPAttachHeader(0, headerLen) - if !stdin { - continue - } - case AttachPipeStdout: - if !stdout { - continue - } - headerBuf = makeHTTPAttachHeader(1, headerLen) - case AttachPipeStderr: - if !stderr { - continue - } - headerBuf = makeHTTPAttachHeader(2, headerLen) - default: - logrus.Errorf("Received unexpected attach type %+d, discarding %d bytes", buf[0], numR) - continue - } - - numH, err2 := http.Write(headerBuf) - if err2 != nil { - if err != nil { - logrus.Errorf("Reading container %s standard streams: %v", cid, err) - } - - return err2 - } - // Hardcoding header length is pretty gross, but - // fast. Should be safe, as this is a fixed part - // of the protocol. - if numH != 8 { - if err != nil { - logrus.Errorf("Reading container %s standard streams: %v", cid, err) - } - - return io.ErrShortWrite - } - - numW, err2 := http.Write(buf[1:numR]) - if err2 != nil { - if err != nil { - logrus.Errorf("Reading container %s standard streams: %v", cid, err) - } - - return err2 - } else if numW+1 != numR { - if err != nil { - logrus.Errorf("Reading container %s standard streams: %v", cid, err) - } - - return io.ErrShortWrite - } - // We need to force the buffer to write immediately, so - // there isn't a delay on the terminal side. - if err2 := http.Flush(); err2 != nil { - if err != nil { - logrus.Errorf("Reading container %s STDOUT: %v", cid, err) - } - return err2 - } - } - if err != nil { - if err == io.EOF { - return nil - } - - return err - } - } -} - // GetLimits converts spec resource limits to cgroup consumable limits func GetLimits(resource *spec.LinuxResources) (runcconfig.Resources, error) { if resource == nil { diff --git a/libpod/oci_conmon_unsupported.go b/libpod/oci_conmon_unsupported.go new file mode 100644 index 000000000..cc6d68e89 --- /dev/null +++ b/libpod/oci_conmon_unsupported.go @@ -0,0 +1,24 @@ +//go:build !linux && !freebsd +// +build !linux,!freebsd + +package libpod + +import ( + "errors" + + "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/resize" +) + +// Make a new Conmon-based OCI runtime with the given options. +// Conmon will wrap the given OCI runtime, which can be `runc`, `crun`, or +// any runtime with a runc-compatible CLI. +// The first path that points to a valid executable will be used. +// Deliberately private. Someone should not be able to construct this outside of +// libpod. +func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeFlags []string, runtimeCfg *config.Config) (OCIRuntime, error) { + return nil, errors.New("newConmonOCIRuntime not supported on this platform") +} + +func registerResizeFunc(r <-chan resize.TerminalSize, bundlePath string) { +} diff --git a/libpod/options.go b/libpod/options.go index 43ed1ff78..d31741094 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1695,14 +1695,22 @@ func withSetAnon() VolumeCreateOption { } } -// WithVolumeDriverTimeout sets the volume creation timeout period -func WithVolumeDriverTimeout(timeout int) VolumeCreateOption { +// WithVolumeDriverTimeout sets the volume creation timeout period. +// Only usable if a non-local volume driver is in use. +func WithVolumeDriverTimeout(timeout uint) VolumeCreateOption { return func(volume *Volume) error { if volume.valid { return define.ErrVolumeFinalized } - volume.config.Timeout = timeout + if volume.config.Driver == "" || volume.config.Driver == define.VolumeDriverLocal { + return fmt.Errorf("Volume driver timeout can only be used with non-local volume drivers: %w", define.ErrInvalidArg) + } + + tm := timeout + + volume.config.Timeout = &tm + return nil } } diff --git a/libpod/plugin/volume_api.go b/libpod/plugin/volume_api.go index 0a5eaae53..b13578388 100644 --- a/libpod/plugin/volume_api.go +++ b/libpod/plugin/volume_api.go @@ -3,6 +3,7 @@ package plugin import ( "bytes" "context" + "errors" "fmt" "io/ioutil" "net" @@ -13,8 +14,7 @@ import ( "sync" "time" - "errors" - + "github.com/containers/common/pkg/config" "github.com/containers/podman/v4/libpod/define" "github.com/docker/go-plugins-helpers/sdk" "github.com/docker/go-plugins-helpers/volume" @@ -40,7 +40,6 @@ var ( ) const ( - defaultTimeout = 5 * time.Second volumePluginType = "VolumeDriver" ) @@ -129,7 +128,7 @@ func validatePlugin(newPlugin *VolumePlugin) error { // GetVolumePlugin gets a single volume plugin, with the given name, at the // given path. -func GetVolumePlugin(name string, path string, timeout int) (*VolumePlugin, error) { +func GetVolumePlugin(name string, path string, timeout *uint, cfg *config.Config) (*VolumePlugin, error) { pluginsLock.Lock() defer pluginsLock.Unlock() @@ -152,13 +151,11 @@ func GetVolumePlugin(name string, path string, timeout int) (*VolumePlugin, erro // Need an HTTP client to force a Unix connection. // And since we can reuse it, might as well cache it. client := new(http.Client) - client.Timeout = defaultTimeout - // if the user specified a non-zero timeout, use their value. Else, keep the default. - if timeout != 0 { - if time.Duration(timeout)*time.Second < defaultTimeout { - logrus.Warnf("the default timeout for volume creation is %d seconds, setting a time less than that may break this feature.", defaultTimeout) - } - client.Timeout = time.Duration(timeout) * time.Second + client.Timeout = 5 * time.Second + if timeout != nil { + client.Timeout = time.Duration(*timeout) * time.Second + } else if cfg != nil { + client.Timeout = time.Duration(cfg.Engine.VolumePluginTimeout) * time.Second } // This bit borrowed from pkg/bindings/connection.go client.Transport = &http.Transport{ diff --git a/libpod/pod_top_unsupported.go b/libpod/pod_top_unsupported.go new file mode 100644 index 000000000..92323043a --- /dev/null +++ b/libpod/pod_top_unsupported.go @@ -0,0 +1,20 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "errors" +) + +// GetPodPidInformation returns process-related data of all processes in +// the pod. The output data can be controlled via the `descriptors` +// argument which expects format descriptors and supports all AIXformat +// descriptors of ps (1) plus some additional ones to for instance inspect the +// set of effective capabilities. Each element in the returned string slice +// is a tab-separated string. +// +// For more details, please refer to github.com/containers/psgo. +func (p *Pod) GetPodPidInformation(descriptors []string) ([]string, error) { + return nil, errors.New("not implemented (*Pod) GetPodPidInformation") +} diff --git a/libpod/runtime.go b/libpod/runtime.go index ea4b34954..9b97fd724 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -2,15 +2,11 @@ package libpod import ( "bufio" - "bytes" "context" "errors" "fmt" "os" - "os/exec" "path/filepath" - "regexp" - "strconv" "strings" "sync" "syscall" @@ -44,17 +40,6 @@ import ( "github.com/sirupsen/logrus" ) -const ( - // conmonMinMajorVersion is the major version required for conmon. - conmonMinMajorVersion = 2 - - // conmonMinMinorVersion is the minor version required for conmon. - conmonMinMinorVersion = 0 - - // conmonMinPatchVersion is the sub-minor version required for conmon. - conmonMinPatchVersion = 24 -) - // A RuntimeOption is a functional option which alters the Runtime created by // NewRuntime type RuntimeOption func(*Runtime) error @@ -308,7 +293,7 @@ func getLockManager(runtime *Runtime) (lock.Manager, error) { // Sets up containers/storage, state store, OCI runtime func makeRuntime(runtime *Runtime) (retErr error) { // Find a working conmon binary - cPath, err := findConmon(runtime.config.Engine.ConmonPath) + cPath, err := runtime.config.FindConmon() if err != nil { return err } @@ -670,102 +655,6 @@ func makeRuntime(runtime *Runtime) (retErr error) { return nil } -// findConmon iterates over conmonPaths and returns the path -// to the first conmon binary with a new enough version. If none is found, -// we try to do a path lookup of "conmon". -func findConmon(conmonPaths []string) (string, error) { - foundOutdatedConmon := false - for _, path := range conmonPaths { - stat, err := os.Stat(path) - if err != nil { - continue - } - if stat.IsDir() { - continue - } - if err := probeConmon(path); err != nil { - logrus.Warnf("Conmon at %s invalid: %v", path, err) - foundOutdatedConmon = true - continue - } - logrus.Debugf("Using conmon: %q", path) - return path, nil - } - - // Search the $PATH as last fallback - if path, err := exec.LookPath("conmon"); err == nil { - if err := probeConmon(path); err != nil { - logrus.Warnf("Conmon at %s is invalid: %v", path, err) - foundOutdatedConmon = true - } else { - logrus.Debugf("Using conmon from $PATH: %q", path) - return path, nil - } - } - - if foundOutdatedConmon { - return "", fmt.Errorf( - "please update to v%d.%d.%d or later: %w", - conmonMinMajorVersion, conmonMinMinorVersion, conmonMinPatchVersion, define.ErrConmonOutdated) - } - - return "", fmt.Errorf( - "could not find a working conmon binary (configured options: %v): %w", - conmonPaths, define.ErrInvalidArg) -} - -// probeConmon calls conmon --version and verifies it is a new enough version for -// the runtime expectations the container engine currently has. -func probeConmon(conmonBinary string) error { - cmd := exec.Command(conmonBinary, "--version") - var out bytes.Buffer - cmd.Stdout = &out - err := cmd.Run() - if err != nil { - return err - } - r := regexp.MustCompile(`^conmon version (?P<Major>\d+).(?P<Minor>\d+).(?P<Patch>\d+)`) - - matches := r.FindStringSubmatch(out.String()) - if len(matches) != 4 { - return fmt.Errorf("%v: %w", define.ErrConmonVersionFormat, err) - } - major, err := strconv.Atoi(matches[1]) - if err != nil { - return fmt.Errorf("%v: %w", define.ErrConmonVersionFormat, err) - } - if major < conmonMinMajorVersion { - return define.ErrConmonOutdated - } - if major > conmonMinMajorVersion { - return nil - } - - minor, err := strconv.Atoi(matches[2]) - if err != nil { - return fmt.Errorf("%v: %w", define.ErrConmonVersionFormat, err) - } - if minor < conmonMinMinorVersion { - return define.ErrConmonOutdated - } - if minor > conmonMinMinorVersion { - return nil - } - - patch, err := strconv.Atoi(matches[3]) - if err != nil { - return fmt.Errorf("%v: %w", define.ErrConmonVersionFormat, err) - } - if patch < conmonMinPatchVersion { - return define.ErrConmonOutdated - } - if patch > conmonMinPatchVersion { - return nil - } - - return nil -} - // TmpDir gets the current Libpod temporary files directory. func (r *Runtime) TmpDir() (string, error) { if !r.valid { @@ -1208,7 +1097,7 @@ func (r *Runtime) getVolumePlugin(volConfig *VolumeConfig) (*plugin.VolumePlugin return nil, fmt.Errorf("no volume plugin with name %s available: %w", name, define.ErrMissingPlugin) } - return plugin.GetVolumePlugin(name, pluginPath, timeout) + return plugin.GetVolumePlugin(name, pluginPath, timeout, r.config) } // GetSecretsStorageDir returns the directory that the secrets manager should take diff --git a/libpod/runtime_migrate_unsupported.go b/libpod/runtime_migrate_unsupported.go new file mode 100644 index 000000000..77c2737a9 --- /dev/null +++ b/libpod/runtime_migrate_unsupported.go @@ -0,0 +1,16 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "errors" +) + +func (r *Runtime) stopPauseProcess() error { + return errors.New("not implemented (*Runtime) stopPauseProcess") +} + +func (r *Runtime) migrate() error { + return errors.New("not implemented (*Runtime) migrate") +} diff --git a/libpod/runtime_pod_unsupported.go b/libpod/runtime_pod_unsupported.go new file mode 100644 index 000000000..0c7ff8655 --- /dev/null +++ b/libpod/runtime_pod_unsupported.go @@ -0,0 +1,30 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "context" + "errors" + + "github.com/containers/podman/v4/pkg/specgen" +) + +// NewPod makes a new, empty pod +func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, options ...PodCreateOption) (_ *Pod, deferredErr error) { + return nil, errors.New("not implemented (*Runtime) NewPod") +} + +// AddInfra adds the created infra container to the pod state +func (r *Runtime) AddInfra(ctx context.Context, pod *Pod, infraCtr *Container) (*Pod, error) { + return nil, errors.New("not implemented (*Runtime) AddInfra") +} + +// SavePod is a helper function to save the pod state from outside of libpod +func (r *Runtime) SavePod(pod *Pod) error { + return errors.New("not implemented (*Runtime) SavePod") +} + +func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool, timeout *uint) error { + return errors.New("not implemented (*Runtime) removePod") +} diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go index 1f354e41b..65f2a1005 100644 --- a/libpod/runtime_volume_linux.go +++ b/libpod/runtime_volume_linux.go @@ -184,7 +184,7 @@ func (r *Runtime) UpdateVolumePlugins(ctx context.Context) *define.VolumeReload ) for driverName, socket := range r.config.Engine.VolumePlugins { - driver, err := volplugin.GetVolumePlugin(driverName, socket, 0) + driver, err := volplugin.GetVolumePlugin(driverName, socket, nil, r.config) if err != nil { errs = append(errs, err) continue diff --git a/libpod/runtime_volume_unsupported.go b/libpod/runtime_volume_unsupported.go new file mode 100644 index 000000000..c2816b817 --- /dev/null +++ b/libpod/runtime_volume_unsupported.go @@ -0,0 +1,42 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "context" + "errors" + + "github.com/containers/podman/v4/libpod/define" +) + +// NewVolume creates a new empty volume +func (r *Runtime) NewVolume(ctx context.Context, options ...VolumeCreateOption) (*Volume, error) { + if !r.valid { + return nil, define.ErrRuntimeStopped + } + return r.newVolume(false, options...) +} + +// NewVolume creates a new empty volume +func (r *Runtime) newVolume(noCreatePluginVolume bool, options ...VolumeCreateOption) (*Volume, error) { + return nil, errors.New("not implemented (*Runtime) newVolume") +} + +// UpdateVolumePlugins reads all volumes from all configured volume plugins and +// imports them into the libpod db. It also checks if existing libpod volumes +// are removed in the plugin, in this case we try to remove it from libpod. +// On errors we continue and try to do as much as possible. all errors are +// returned as array in the returned struct. +// This function has many race conditions, it is best effort but cannot guarantee +// a perfect state since plugins can be modified from the outside at any time. +func (r *Runtime) UpdateVolumePlugins(ctx context.Context) *define.VolumeReload { + return nil +} + +// removeVolume removes the specified volume from state as well tears down its mountpoint and storage. +// ignoreVolumePlugin is used to only remove the volume from the db and not the plugin, +// this is required when the volume was already removed from the plugin, i.e. in UpdateVolumePlugins(). +func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool, timeout *uint, ignoreVolumePlugin bool) error { + return errors.New("not implemented (*Runtime) removeVolume") +} diff --git a/libpod/stats_unsupported.go b/libpod/stats_unsupported.go new file mode 100644 index 000000000..b23333c2e --- /dev/null +++ b/libpod/stats_unsupported.go @@ -0,0 +1,17 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "errors" + + "github.com/containers/podman/v4/libpod/define" +) + +// GetContainerStats gets the running stats for a given container. +// The previousStats is used to correctly calculate cpu percentages. You +// should pass nil if there is no previous stat for this container. +func (c *Container) GetContainerStats(previousStats *define.ContainerStats) (*define.ContainerStats, error) { + return nil, errors.New("not implemented (*Container) GetContainerStats") +} diff --git a/libpod/util_unsupported.go b/libpod/util_unsupported.go new file mode 100644 index 000000000..d2ec3ae7b --- /dev/null +++ b/libpod/util_unsupported.go @@ -0,0 +1,27 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "errors" + + spec "github.com/opencontainers/runtime-spec/specs-go" +) + +// systemdSliceFromPath makes a new systemd slice under the given parent with +// the given name. +// The parent must be a slice. The name must NOT include ".slice" +func systemdSliceFromPath(parent, name string, resources *spec.LinuxResources) (string, error) { + return "", errors.New("not implemented systemdSliceFromPath") +} + +// Unmount umounts a target directory +func Unmount(mount string) { +} + +// LabelVolumePath takes a mount path for a volume and gives it an +// selinux label of either shared or not +func LabelVolumePath(path string) error { + return errors.New("not implemented LabelVolumePath") +} diff --git a/libpod/volume.go b/libpod/volume.go index 2e8cd77a5..a054e4032 100644 --- a/libpod/volume.go +++ b/libpod/volume.go @@ -56,7 +56,7 @@ type VolumeConfig struct { // quota tracking. DisableQuota bool `json:"disableQuota,omitempty"` // Timeout allows users to override the default driver timeout of 5 seconds - Timeout int + Timeout *uint `json:"timeout,omitempty"` } // VolumeState holds the volume's mutable state. diff --git a/libpod/volume_inspect.go b/libpod/volume_inspect.go index dd2f3fd01..c3872bca7 100644 --- a/libpod/volume_inspect.go +++ b/libpod/volume_inspect.go @@ -64,7 +64,12 @@ func (v *Volume) Inspect() (*define.InspectVolumeData, error) { data.MountCount = v.state.MountCount data.NeedsCopyUp = v.state.NeedsCopyUp data.NeedsChown = v.state.NeedsChown - data.Timeout = v.config.Timeout + + if v.config.Timeout != nil { + data.Timeout = *v.config.Timeout + } else if v.UsesVolumeDriver() { + data.Timeout = v.runtime.config.Engine.VolumePluginTimeout + } return data, nil } diff --git a/libpod/volume_internal_unsupported.go b/libpod/volume_internal_unsupported.go new file mode 100644 index 000000000..50515e692 --- /dev/null +++ b/libpod/volume_internal_unsupported.go @@ -0,0 +1,32 @@ +//go:build !linux +// +build !linux + +package libpod + +import ( + "errors" +) + +// mount mounts the volume if necessary. +// A mount is necessary if a volume has any options set. +// If a mount is necessary, v.state.MountCount will be incremented. +// If it was 0 when the increment occurred, the volume will be mounted on the +// host. Otherwise, we assume it is already mounted. +// Must be done while the volume is locked. +// Is a no-op on volumes that do not require a mount (as defined by +// volumeNeedsMount()). +func (v *Volume) mount() error { + return errors.New("not implemented (*Volume) mount") +} + +// unmount unmounts the volume if necessary. +// Unmounting a volume that is not mounted is a no-op. +// Unmounting a volume that does not require a mount is a no-op. +// The volume must be locked for this to occur. +// The mount counter will be decremented if non-zero. If the counter reaches 0, +// the volume will really be unmounted, as no further containers are using the +// volume. +// If force is set, the volume will be unmounted regardless of mount counter. +func (v *Volume) unmount(force bool) error { + return errors.New("not implemented (*Volume) unmount") +} diff --git a/pkg/api/handlers/compat/auth.go b/pkg/api/handlers/compat/auth.go index 37d2b784d..ee478b9e3 100644 --- a/pkg/api/handlers/compat/auth.go +++ b/pkg/api/handlers/compat/auth.go @@ -1,7 +1,6 @@ package compat import ( - "context" "encoding/json" "errors" "fmt" @@ -44,7 +43,7 @@ func Auth(w http.ResponseWriter, r *http.Request) { fmt.Println("Authenticating with existing credentials...") registry := stripAddressOfScheme(authConfig.ServerAddress) - if err := DockerClient.CheckAuth(context.Background(), sysCtx, authConfig.Username, authConfig.Password, registry); err == nil { + if err := DockerClient.CheckAuth(r.Context(), sysCtx, authConfig.Username, authConfig.Password, registry); err == nil { utils.WriteResponse(w, http.StatusOK, entities.AuthReport{ IdentityToken: "", Status: "Login Succeeded", diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 35681cb36..61d6fc86d 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -467,6 +467,7 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON, if err := json.Unmarshal(h, &hc); err != nil { return nil, err } + sort.Strings(hc.Binds) // k8s-file == json-file if hc.LogConfig.Type == define.KubernetesLogging { diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go index 9fff8b4c8..d4f5d5f36 100644 --- a/pkg/api/handlers/compat/containers_create.go +++ b/pkg/api/handlers/compat/containers_create.go @@ -408,6 +408,7 @@ func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.C Systemd: "true", // podman default TmpFS: parsedTmp, TTY: cc.Config.Tty, + EnvMerge: cc.EnvMerge, UnsetEnv: cc.UnsetEnv, UnsetEnvAll: cc.UnsetEnvAll, User: cc.Config.User, diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go index 18fb35966..105404a0d 100644 --- a/pkg/api/handlers/compat/events.go +++ b/pkg/api/handlers/compat/events.go @@ -89,6 +89,12 @@ func GetEvents(w http.ResponseWriter, r *http.Request) { } e := entities.ConvertToEntitiesEvent(*evt) + // Some events differ between Libpod and Docker endpoints. + // Handle these differences for Docker-compat. + if !utils.IsLibpodRequest(r) && e.Type == "image" && e.Status == "remove" { + e.Status = "delete" + e.Action = "delete" + } if !utils.IsLibpodRequest(r) && e.Status == "died" { e.Status = "die" e.Action = "die" diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index a00f0b089..7ba1029a7 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -101,6 +101,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { ForceRm bool `schema:"forcerm"` From string `schema:"from"` HTTPProxy bool `schema:"httpproxy"` + IDMappingOptions string `schema:"idmappingoptions"` IdentityLabel bool `schema:"identitylabel"` Ignore bool `schema:"ignore"` Isolation string `schema:"isolation"` @@ -389,6 +390,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } } + var idMappingOptions buildahDefine.IDMappingOptions + if _, found := r.URL.Query()["idmappingoptions"]; found { + if err := json.Unmarshal([]byte(query.IDMappingOptions), &idMappingOptions); err != nil { + utils.BadRequest(w, "idmappingoptions", query.IDMappingOptions, err) + return + } + } + var cacheFrom reference.Named if _, found := r.URL.Query()["cachefrom"]; found { cacheFrom, err = parse.RepoNameToNamedReference(query.CacheFrom) @@ -644,6 +653,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Excludes: excludes, ForceRmIntermediateCtrs: query.ForceRm, From: fromImage, + IDMappingOptions: &idMappingOptions, IgnoreUnrecognizedInstructions: query.Ignore, Isolation: isolation, Jobs: &jobs, @@ -694,7 +704,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { success bool ) - runCtx, cancel := context.WithCancel(context.Background()) + runCtx, cancel := context.WithCancel(r.Context()) go func() { defer cancel() imageID, _, err = runtime.Build(r.Context(), buildOptions, containerFiles...) diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go index 1307c267a..429f45f91 100644 --- a/pkg/api/handlers/libpod/containers_create.go +++ b/pkg/api/handlers/libpod/containers_create.go @@ -1,7 +1,6 @@ package libpod import ( - "context" "encoding/json" "fmt" "net/http" @@ -63,12 +62,12 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), runtime, &sg, false, nil) + rtSpec, spec, opts, err := generate.MakeContainer(r.Context(), runtime, &sg, false, nil) if err != nil { utils.InternalServerError(w, err) return } - ctr, err := generate.ExecuteCreate(context.Background(), runtime, rtSpec, spec, false, opts...) + ctr, err := generate.ExecuteCreate(r.Context(), runtime, rtSpec, spec, false, opts...) if err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go index 7e24ae5ac..57b2e3a78 100644 --- a/pkg/api/handlers/libpod/images_pull.go +++ b/pkg/api/handlers/libpod/images_pull.go @@ -82,17 +82,32 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { pullOptions.IdentityToken = authConf.IdentityToken } - writer := channel.NewWriter(make(chan []byte)) - defer writer.Close() - - pullOptions.Writer = writer - pullPolicy, err := config.ParsePullPolicy(query.PullPolicy) if err != nil { utils.Error(w, http.StatusBadRequest, err) return } + // Let's keep thing simple when running in quiet mode and pull directly. + if query.Quiet { + images, err := runtime.LibimageRuntime().Pull(r.Context(), query.Reference, pullPolicy, pullOptions) + var report entities.ImagePullReport + if err != nil { + report.Error = err.Error() + } + for _, image := range images { + report.Images = append(report.Images, image.ID()) + // Pull last ID from list and publish in 'id' stanza. This maintains previous API contract + report.ID = image.ID() + } + utils.WriteResponse(w, http.StatusOK, report) + return + } + + writer := channel.NewWriter(make(chan []byte)) + defer writer.Close() + pullOptions.Writer = writer + var pulledImages []*libimage.Image var pullError error runCtx, cancel := context.WithCancel(r.Context()) @@ -118,10 +133,8 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { select { case s := <-writer.Chan(): report.Stream = string(s) - if !query.Quiet { - if err := enc.Encode(report); err != nil { - logrus.Warnf("Failed to encode json: %v", err) - } + if err := enc.Encode(report); err != nil { + logrus.Warnf("Failed to encode json: %v", err) } flush() case <-runCtx.Done(): diff --git a/pkg/api/handlers/libpod/images_push.go b/pkg/api/handlers/libpod/images_push.go index e931fd2f9..be6f5b131 100644 --- a/pkg/api/handlers/libpod/images_push.go +++ b/pkg/api/handlers/libpod/images_push.go @@ -90,7 +90,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) { // Let's keep thing simple when running in quiet mode and push directly. if query.Quiet { - if err := imageEngine.Push(context.Background(), source, destination, options); err != nil { + if err := imageEngine.Push(r.Context(), source, destination, options); err != nil { utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err)) return } diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go index b0c93f3b9..8391def5c 100644 --- a/pkg/api/handlers/libpod/manifests.go +++ b/pkg/api/handlers/libpod/manifests.go @@ -36,6 +36,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) { Name string `schema:"name"` Images []string `schema:"images"` All bool `schema:"all"` + Amend bool `schema:"amend"` }{ // Add defaults here once needed. } @@ -70,7 +71,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) { imageEngine := abi.ImageEngine{Libpod: runtime} - createOptions := entities.ManifestCreateOptions{All: query.All} + createOptions := entities.ManifestCreateOptions{All: query.All, Amend: query.Amend} manID, err := imageEngine.ManifestCreate(r.Context(), query.Name, query.Images, createOptions) if err != nil { utils.InternalServerError(w, err) @@ -292,7 +293,7 @@ func ManifestPushV3(w http.ResponseWriter, r *http.Request) { options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) } imageEngine := abi.ImageEngine{Libpod: runtime} - digest, err := imageEngine.ManifestPush(context.Background(), source, query.Destination, options) + digest, err := imageEngine.ManifestPush(r.Context(), source, query.Destination, options) if err != nil { utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", query.Destination, err)) return @@ -366,7 +367,7 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) { // Let's keep thing simple when running in quiet mode and push directly. if query.Quiet { - digest, err := imageEngine.ManifestPush(context.Background(), source, destination, options) + digest, err := imageEngine.ManifestPush(r.Context(), source, destination, options) if err != nil { utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err)) return diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go index b533e131c..aab905878 100644 --- a/pkg/api/handlers/types.go +++ b/pkg/api/handlers/types.go @@ -127,6 +127,7 @@ type CreateContainerConfig struct { dockerContainer.Config // desired container configuration HostConfig dockerContainer.HostConfig // host dependent configuration for container NetworkingConfig dockerNetwork.NetworkingConfig // network configuration for container + EnvMerge []string // preprocess env variables from image before injecting into containers UnsetEnv []string // unset specified default environment variables UnsetEnvAll bool // unset all default environment variables } @@ -162,7 +163,7 @@ type ExecStartConfig struct { func ImageDataToImageInspect(ctx context.Context, l *libimage.Image) (*ImageInspect, error) { options := &libimage.InspectOptions{WithParent: true, WithSize: true} - info, err := l.Inspect(context.Background(), options) + info, err := l.Inspect(ctx, options) if err != nil { return nil, err } diff --git a/pkg/api/server/register_manifest.go b/pkg/api/server/register_manifest.go index c22479cf9..7a55eaefe 100644 --- a/pkg/api/server/register_manifest.go +++ b/pkg/api/server/register_manifest.go @@ -117,6 +117,10 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // name: all // type: boolean // description: add all contents if given list + // - in: query + // name: amend + // type: boolean + // description: modify an existing list if one with the desired name already exists // - in: body // name: options // description: options for new manifest diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 2615bc516..8348ac54b 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -88,6 +88,13 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } params.Set("additionalbuildcontexts", string(additionalBuildContextMap)) } + if options.IDMappingOptions != nil { + idmappingsOptions, err := jsoniter.Marshal(options.IDMappingOptions) + if err != nil { + return nil, err + } + params.Set("idmappingoptions", string(idmappingsOptions)) + } if buildArgs := options.Args; len(buildArgs) > 0 { bArgs, err := jsoniter.MarshalToString(buildArgs) if err != nil { diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go index 1a4aa3038..109981c63 100644 --- a/pkg/bindings/images/pull.go +++ b/pkg/bindings/images/pull.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net/http" "os" "strconv" @@ -57,10 +56,14 @@ func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string, return nil, response.Process(err) } - // Historically pull writes status to stderr - stderr := io.Writer(os.Stderr) + var writer io.Writer if options.GetQuiet() { - stderr = ioutil.Discard + writer = io.Discard + } else if progressWriter := options.GetProgressWriter(); progressWriter != nil { + writer = progressWriter + } else { + // Historically push writes status to stderr + writer = os.Stderr } dec := json.NewDecoder(response.Body) @@ -84,7 +87,7 @@ func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string, switch { case report.Stream != "": - fmt.Fprint(stderr, report.Stream) + fmt.Fprint(writer, report.Stream) case report.Error != "": pullErrors = append(pullErrors, errors.New(report.Error)) case len(report.Images) > 0: diff --git a/pkg/bindings/images/push.go b/pkg/bindings/images/push.go index 5069dd780..f1e059f8c 100644 --- a/pkg/bindings/images/push.go +++ b/pkg/bindings/images/push.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net/http" "os" "strconv" @@ -58,12 +57,14 @@ func Push(ctx context.Context, source string, destination string, options *PushO return response.Process(err) } - // Historically push writes status to stderr - writer := io.Writer(os.Stderr) + var writer io.Writer if options.GetQuiet() { - writer = ioutil.Discard + writer = io.Discard } else if progressWriter := options.GetProgressWriter(); progressWriter != nil { writer = progressWriter + } else { + // Historically push writes status to stderr + writer = os.Stderr } dec := json.NewDecoder(response.Body) diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go index 7b28c499e..3ecfb9e09 100644 --- a/pkg/bindings/images/types.go +++ b/pkg/bindings/images/types.go @@ -182,6 +182,8 @@ type PullOptions struct { Policy *string // Password for authenticating against the registry. Password *string + // ProgressWriter is a writer where pull progress are sent. + ProgressWriter *io.Writer // Quiet can be specified to suppress pull progress when pulling. Ignored // for remote calls. Quiet *bool diff --git a/pkg/bindings/images/types_pull_options.go b/pkg/bindings/images/types_pull_options.go index 4cd525185..c1a88fd9e 100644 --- a/pkg/bindings/images/types_pull_options.go +++ b/pkg/bindings/images/types_pull_options.go @@ -2,6 +2,7 @@ package images import ( + "io" "net/url" "github.com/containers/podman/v4/pkg/bindings/internal/util" @@ -107,6 +108,21 @@ func (o *PullOptions) GetPassword() string { return *o.Password } +// WithProgressWriter set field ProgressWriter to given value +func (o *PullOptions) WithProgressWriter(value io.Writer) *PullOptions { + o.ProgressWriter = &value + return o +} + +// GetProgressWriter returns value of field ProgressWriter +func (o *PullOptions) GetProgressWriter() io.Writer { + if o.ProgressWriter == nil { + var z io.Writer + return z + } + return *o.ProgressWriter +} + // WithQuiet set field Quiet to given value func (o *PullOptions) WithQuiet(value bool) *PullOptions { o.Quiet = &value diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go index 49e4089f5..0163d21a0 100644 --- a/pkg/bindings/manifests/manifests.go +++ b/pkg/bindings/manifests/manifests.go @@ -182,12 +182,14 @@ func Push(ctx context.Context, name, destination string, options *images.PushOpt return "", response.Process(err) } - // Historically push writes status to stderr - writer := io.Writer(os.Stderr) + var writer io.Writer if options.GetQuiet() { writer = io.Discard } else if progressWriter := options.GetProgressWriter(); progressWriter != nil { writer = progressWriter + } else { + // Historically push writes status to stderr + writer = os.Stderr } dec := json.NewDecoder(response.Body) diff --git a/pkg/bindings/manifests/types.go b/pkg/bindings/manifests/types.go index e23ef798d..5f2557fe1 100644 --- a/pkg/bindings/manifests/types.go +++ b/pkg/bindings/manifests/types.go @@ -8,7 +8,8 @@ type InspectOptions struct { //go:generate go run ../generator/generator.go CreateOptions // CreateOptions are optional options for creating manifests type CreateOptions struct { - All *bool + All *bool + Amend *bool } //go:generate go run ../generator/generator.go ExistsOptions diff --git a/pkg/bindings/manifests/types_create_options.go b/pkg/bindings/manifests/types_create_options.go index 960332a82..09942c00a 100644 --- a/pkg/bindings/manifests/types_create_options.go +++ b/pkg/bindings/manifests/types_create_options.go @@ -31,3 +31,18 @@ func (o *CreateOptions) GetAll() bool { } return *o.All } + +// WithAmend set field Amend to given value +func (o *CreateOptions) WithAmend(value bool) *CreateOptions { + o.Amend = &value + return o +} + +// GetAmend returns value of field Amend +func (o *CreateOptions) GetAmend() bool { + if o.Amend == nil { + var z bool + return z + } + return *o.Amend +} diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go index 9c9796661..53c5a1e83 100644 --- a/pkg/bindings/test/images_test.go +++ b/pkg/bindings/test/images_test.go @@ -1,11 +1,14 @@ package bindings_test import ( + "bytes" + "fmt" "net/http" "os" "path/filepath" "time" + podmanRegistry "github.com/containers/podman/v4/hack/podman-registry-go" "github.com/containers/podman/v4/pkg/bindings" "github.com/containers/podman/v4/pkg/bindings/containers" "github.com/containers/podman/v4/pkg/bindings/images" @@ -362,9 +365,14 @@ var _ = Describe("Podman images", func() { It("Image Pull", func() { rawImage := "docker.io/library/busybox:latest" - pulledImages, err := images.Pull(bt.conn, rawImage, nil) + var writer bytes.Buffer + pullOpts := new(images.PullOptions).WithProgressWriter(&writer) + pulledImages, err := images.Pull(bt.conn, rawImage, pullOpts) Expect(err).NotTo(HaveOccurred()) Expect(len(pulledImages)).To(Equal(1)) + output := writer.String() + Expect(output).To(ContainSubstring("Trying to pull ")) + Expect(output).To(ContainSubstring("Getting image source signatures")) exists, err := images.Exists(bt.conn, rawImage, nil) Expect(err).NotTo(HaveOccurred()) @@ -380,7 +388,19 @@ var _ = Describe("Podman images", func() { }) It("Image Push", func() { - Skip("TODO: implement test for image push to registry") + registry, err := podmanRegistry.Start() + Expect(err).To(BeNil()) + + var writer bytes.Buffer + pushOpts := new(images.PushOptions).WithUsername(registry.User).WithPassword(registry.Password).WithSkipTLSVerify(true).WithProgressWriter(&writer).WithQuiet(false) + err = images.Push(bt.conn, alpine.name, fmt.Sprintf("localhost:%s/test:latest", registry.Port), pushOpts) + Expect(err).ToNot(HaveOccurred()) + + output := writer.String() + Expect(output).To(ContainSubstring("Copying blob ")) + Expect(output).To(ContainSubstring("Copying config ")) + Expect(output).To(ContainSubstring("Writing manifest to image destination")) + Expect(output).To(ContainSubstring("Storing signatures")) }) It("Build no options", func() { diff --git a/pkg/bindings/test/manifests_test.go b/pkg/bindings/test/manifests_test.go index 6a34ef5a6..d6749f920 100644 --- a/pkg/bindings/test/manifests_test.go +++ b/pkg/bindings/test/manifests_test.go @@ -1,9 +1,12 @@ package bindings_test import ( + "bytes" + "fmt" "net/http" "time" + podmanRegistry "github.com/containers/podman/v4/hack/podman-registry-go" "github.com/containers/podman/v4/pkg/bindings" "github.com/containers/podman/v4/pkg/bindings/images" "github.com/containers/podman/v4/pkg/bindings/manifests" @@ -12,7 +15,7 @@ import ( "github.com/onsi/gomega/gexec" ) -var _ = Describe("podman manifest", func() { +var _ = Describe("Podman manifests", func() { var ( bt *bindingTest s *gexec.Session @@ -172,7 +175,21 @@ var _ = Describe("podman manifest", func() { Expect(list.Manifests[0].Platform.OS).To(Equal("foo")) }) - It("push manifest", func() { - Skip("TODO: implement test for manifest push to registry") + It("Manifest Push", func() { + registry, err := podmanRegistry.Start() + Expect(err).To(BeNil()) + + name := "quay.io/libpod/foobar:latest" + _, err = manifests.Create(bt.conn, name, []string{alpine.name}, nil) + Expect(err).ToNot(HaveOccurred()) + + var writer bytes.Buffer + pushOpts := new(images.PushOptions).WithUsername(registry.User).WithPassword(registry.Password).WithAll(true).WithSkipTLSVerify(true).WithProgressWriter(&writer).WithQuiet(false) + _, err = manifests.Push(bt.conn, name, fmt.Sprintf("localhost:%s/test:latest", registry.Port), pushOpts) + Expect(err).ToNot(HaveOccurred()) + + output := writer.String() + Expect(output).To(ContainSubstring("Writing manifest list to image destination")) + Expect(output).To(ContainSubstring("Storing list signatures")) }) }) diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 3ba507750..91ccdc2b2 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -119,6 +119,7 @@ type KillReport struct { } type RestartOptions struct { + Filters map[string][]string All bool Latest bool Running bool @@ -126,8 +127,9 @@ type RestartOptions struct { } type RestartReport struct { - Err error - Id string //nolint:revive,stylecheck + Err error + Id string //nolint:revive,stylecheck + RawInput string } type RmOptions struct { diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 21c1372b9..cad11b0ab 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -156,6 +156,8 @@ type ImagePullOptions struct { SkipTLSVerify types.OptionalBool // PullPolicy whether to pull new image PullPolicy config.PullPolicy + // Writer is used to display copy information including progress bars. + Writer io.Writer } // ImagePullReport is the response from pulling one or more images. diff --git a/pkg/domain/entities/manifest.go b/pkg/domain/entities/manifest.go index 126b76c62..f17079271 100644 --- a/pkg/domain/entities/manifest.go +++ b/pkg/domain/entities/manifest.go @@ -4,7 +4,12 @@ import "github.com/containers/image/v5/types" // ManifestCreateOptions provides model for creating manifest type ManifestCreateOptions struct { + // True when adding lists to include all images All bool `schema:"all"` + // Amend an extant list if there's already one with the desired name + Amend bool `schema:"amend"` + // Should TLS registry certificate be verified? + SkipTLSVerify types.OptionalBool `json:"-" schema:"-"` } // ManifestAddOptions provides model for adding digests to manifest list diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index 14ce370c1..33ca2c807 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -263,6 +263,7 @@ type ContainerCreateOptions struct { TTY bool Timezone string Umask string + EnvMerge []string UnsetEnv []string UnsetEnvAll bool UIDMap []string diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 5b5bc665e..0a8e5bc2f 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -309,31 +309,42 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) { var ( - ctrs []*libpod.Container - err error + ctrs []*libpod.Container + err error + rawInputs = []string{} ) if options.Running { ctrs, err = ic.Libpod.GetRunningContainers() + for _, candidate := range ctrs { + rawInputs = append(rawInputs, candidate.ID()) + } + if err != nil { return nil, err } } else { - ctrs, err = getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) + ctrs, rawInputs, err = getContainersAndInputByContext(options.All, options.Latest, namesOrIds, options.Filters, ic.Libpod) if err != nil { return nil, err } } - + idToRawInput := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID()] = rawInputs[i] + } + } reports := make([]*entities.RestartReport, 0, len(ctrs)) - for _, con := range ctrs { - timeout := con.StopTimeout() + for _, c := range ctrs { + timeout := c.StopTimeout() if options.Timeout != nil { timeout = *options.Timeout } reports = append(reports, &entities.RestartReport{ - Id: con.ID(), - Err: con.RestartWithTimeout(ctx, timeout), + Id: c.ID(), + Err: c.RestartWithTimeout(ctx, timeout), + RawInput: idToRawInput[c.ID()], }) } return reports, nil @@ -370,7 +381,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, // this will fail and code will fall through to removing the container from libpod.` tmpNames := []string{} for _, ctr := range names { - report := reports.RmReport{Id: ctr, RawInput: ctr} + report := reports.RmReport{Id: ctr} report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force) //nolint:gocritic if report.Err == nil { @@ -927,13 +938,15 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri if err != nil { return nil, err } + idToRawInput := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID()] = rawInputs[i] + } + } // There can only be one container if attach was used for i := range ctrs { ctr := ctrs[i] - rawInput := ctr.ID() - if !options.All { - rawInput = rawInputs[i] - } ctrState, err := ctr.State() if err != nil { return nil, err @@ -947,7 +960,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri // Exit cleanly immediately reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: nil, ExitCode: 0, }) @@ -958,7 +971,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri logrus.Debugf("Deadlock error: %v", err) reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: err, ExitCode: define.ExitCode(err), }) @@ -968,7 +981,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri if ctrRunning { reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: nil, ExitCode: 0, }) @@ -978,7 +991,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri if err != nil { reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: err, ExitCode: exitCode, }) @@ -993,7 +1006,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri exitCode = ic.GetContainerExitCode(ctx, ctr) reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: err, ExitCode: exitCode, }) @@ -1006,7 +1019,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri // If the container is in a pod, also set to recursively start dependencies report := &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], ExitCode: 125, } if err := ctr.Start(ctx, true); err != nil { diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 77d1bf0db..f9839f62f 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -237,8 +237,9 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti pullOptions.Variant = options.Variant pullOptions.SignaturePolicyPath = options.SignaturePolicy pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify + pullOptions.Writer = options.Writer - if !options.Quiet { + if !options.Quiet && pullOptions.Writer == nil { pullOptions.Writer = os.Stderr } diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go index e0c11267e..7e8c86526 100644 --- a/pkg/domain/infra/abi/manifest.go +++ b/pkg/domain/infra/abi/manifest.go @@ -32,7 +32,15 @@ func (ir *ImageEngine) ManifestCreate(ctx context.Context, name string, images [ manifestList, err := ir.Libpod.LibimageRuntime().CreateManifestList(name) if err != nil { - return "", err + if errors.Is(err, storage.ErrDuplicateName) && opts.Amend { + amendList, amendErr := ir.Libpod.LibimageRuntime().LookupManifestList(name) + if amendErr != nil { + return "", err + } + manifestList = amendList + } else { + return "", err + } } addOptions := &libimage.ManifestListAddOptions{All: opts.All} diff --git a/pkg/domain/infra/abi/parse/parse.go b/pkg/domain/infra/abi/parse/parse.go index 19699589b..fb2876bb2 100644 --- a/pkg/domain/infra/abi/parse/parse.go +++ b/pkg/domain/infra/abi/parse/parse.go @@ -86,8 +86,11 @@ func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error) if err != nil { return nil, fmt.Errorf("cannot convert Timeout %s to an integer: %w", splitO[1], err) } + if intTimeout < 0 { + return nil, fmt.Errorf("volume timeout cannot be negative (got %d)", intTimeout) + } logrus.Debugf("Removing timeout from options and adding WithTimeout for Timeout %d", intTimeout) - libpodOptions = append(libpodOptions, libpod.WithVolumeDriverTimeout(intTimeout)) + libpodOptions = append(libpodOptions, libpod.WithVolumeDriverTimeout(uint(intTimeout))) default: finalVal = append(finalVal, o) } diff --git a/pkg/domain/infra/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_commn.go index 16d345f06..3a0132ef3 100644 --- a/pkg/domain/infra/abi/terminal/sigproxy_linux.go +++ b/pkg/domain/infra/abi/terminal/sigproxy_commn.go @@ -1,3 +1,6 @@ +//go:build linux || freebsd +// +build linux freebsd + package terminal import ( diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_common.go index 222590871..afae2c085 100644 --- a/pkg/domain/infra/abi/terminal/terminal_linux.go +++ b/pkg/domain/infra/abi/terminal/terminal_common.go @@ -1,3 +1,6 @@ +//go:build linux || freebsd +// +build linux freebsd + package terminal import ( diff --git a/pkg/domain/infra/abi/terminal/terminal_unsupported.go b/pkg/domain/infra/abi/terminal/terminal_unsupported.go index 8fe325736..21ed6c8d4 100644 --- a/pkg/domain/infra/abi/terminal/terminal_unsupported.go +++ b/pkg/domain/infra/abi/terminal/terminal_unsupported.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build !linux && !freebsd +// +build !linux,!freebsd package terminal diff --git a/pkg/domain/infra/abi/trust.go b/pkg/domain/infra/abi/trust.go index 0e3d8fad9..c58ddff06 100644 --- a/pkg/domain/infra/abi/trust.go +++ b/pkg/domain/infra/abi/trust.go @@ -2,16 +2,11 @@ package abi import ( "context" - "encoding/json" - "errors" "fmt" "io/ioutil" - "os" - "strings" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/trust" - "github.com/sirupsen/logrus" ) func (ir *ImageEngine) ShowTrust(ctx context.Context, args []string, options entities.ShowTrustOptions) (*entities.ShowTrustReport, error) { @@ -34,11 +29,7 @@ func (ir *ImageEngine) ShowTrust(ctx context.Context, args []string, options ent if len(options.RegistryPath) > 0 { report.SystemRegistriesDirPath = options.RegistryPath } - policyContentStruct, err := trust.GetPolicy(policyPath) - if err != nil { - return nil, fmt.Errorf("could not read trust policies: %w", err) - } - report.Policies, err = getPolicyShowOutput(policyContentStruct, report.SystemRegistriesDirPath) + report.Policies, err = trust.PolicyDescription(policyPath, report.SystemRegistriesDirPath) if err != nil { return nil, fmt.Errorf("could not show trust policies: %w", err) } @@ -46,133 +37,19 @@ func (ir *ImageEngine) ShowTrust(ctx context.Context, args []string, options ent } func (ir *ImageEngine) SetTrust(ctx context.Context, args []string, options entities.SetTrustOptions) error { - var ( - policyContentStruct trust.PolicyContent - newReposContent []trust.RepoContent - ) - trustType := options.Type - if trustType == "accept" { - trustType = "insecureAcceptAnything" - } - - pubkeysfile := options.PubKeysFile - if len(pubkeysfile) == 0 && trustType == "signedBy" { - return errors.New("at least one public key must be defined for type 'signedBy'") + if len(args) != 1 { + return fmt.Errorf("SetTrust called with unexpected %d args", len(args)) } + scope := args[0] policyPath := trust.DefaultPolicyPath(ir.Libpod.SystemContext()) if len(options.PolicyPath) > 0 { policyPath = options.PolicyPath } - _, err := os.Stat(policyPath) - if !os.IsNotExist(err) { - policyContent, err := ioutil.ReadFile(policyPath) - if err != nil { - return err - } - if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { - return errors.New("could not read trust policies") - } - } - if len(pubkeysfile) != 0 { - for _, filepath := range pubkeysfile { - newReposContent = append(newReposContent, trust.RepoContent{Type: trustType, KeyType: "GPGKeys", KeyPath: filepath}) - } - } else { - newReposContent = append(newReposContent, trust.RepoContent{Type: trustType}) - } - if args[0] == "default" { - policyContentStruct.Default = newReposContent - } else { - if len(policyContentStruct.Default) == 0 { - return errors.New("default trust policy must be set") - } - registryExists := false - for transport, transportval := range policyContentStruct.Transports { - _, registryExists = transportval[args[0]] - if registryExists { - policyContentStruct.Transports[transport][args[0]] = newReposContent - break - } - } - if !registryExists { - if policyContentStruct.Transports == nil { - policyContentStruct.Transports = make(map[string]trust.RepoMap) - } - if policyContentStruct.Transports["docker"] == nil { - policyContentStruct.Transports["docker"] = make(map[string][]trust.RepoContent) - } - policyContentStruct.Transports["docker"][args[0]] = append(policyContentStruct.Transports["docker"][args[0]], newReposContent...) - } - } - - data, err := json.MarshalIndent(policyContentStruct, "", " ") - if err != nil { - return fmt.Errorf("error setting trust policy: %w", err) - } - return ioutil.WriteFile(policyPath, data, 0644) -} - -func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) ([]*trust.Policy, error) { - var output []*trust.Policy - - registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath) - if err != nil { - return nil, err - } - - if len(policyContentStruct.Default) > 0 { - defaultPolicyStruct := trust.Policy{ - Transport: "all", - Name: "* (default)", - RepoName: "default", - Type: trustTypeDescription(policyContentStruct.Default[0].Type), - } - output = append(output, &defaultPolicyStruct) - } - for transport, transval := range policyContentStruct.Transports { - if transport == "docker" { - transport = "repository" - } - for repo, repoval := range transval { - tempTrustShowOutput := trust.Policy{ - Name: repo, - RepoName: repo, - Transport: transport, - Type: trustTypeDescription(repoval[0].Type), - } - // TODO - keyarr is not used and I don't know its intent; commenting out for now for someone to fix later - // keyarr := []string{} - uids := []string{} - for _, repoele := range repoval { - if len(repoele.KeyPath) > 0 { - // keyarr = append(keyarr, repoele.KeyPath) - uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...) - } - if len(repoele.KeyData) > 0 { - // keyarr = append(keyarr, string(repoele.KeyData)) - uids = append(uids, trust.GetGPGIdFromKeyData(repoele.KeyData)...) - } - } - tempTrustShowOutput.GPGId = strings.Join(uids, ", ") - - registryNamespace := trust.HaveMatchRegistry(repo, registryConfigs) - if registryNamespace != nil { - tempTrustShowOutput.SignatureStore = registryNamespace.SigStore - } - output = append(output, &tempTrustShowOutput) - } - } - return output, nil -} - -var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "reject": "reject"} - -func trustTypeDescription(trustType string) string { - trustDescription, exist := typeDescription[trustType] - if !exist { - logrus.Warnf("Invalid trust type %s", trustType) - } - return trustDescription + return trust.AddPolicyEntries(policyPath, trust.AddPolicyEntriesInput{ + Scope: scope, + Type: options.Type, + PubKeyFiles: options.PubKeysFile, + }) } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index d49f029d5..023bee430 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -183,17 +183,22 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st if to := opts.Timeout; to != nil { options.WithTimeout(int(*to)) } - ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, false, namesOrIds) + ctrs, rawInputs, err := getContainersAndInputByContext(ic.ClientCtx, opts.All, false, namesOrIds, opts.Filters) if err != nil { return nil, err } + idToRawInput := map[string]string{} + for i := range ctrs { + idToRawInput[ctrs[i].ID] = rawInputs[i] + } for _, c := range ctrs { if opts.Running && c.State != define.ContainerStateRunning.String() { continue } reports = append(reports, &entities.RestartReport{ - Id: c.ID, - Err: containers.Restart(ic.ClientCtx, c.ID, options), + Id: c.ID, + Err: containers.Restart(ic.ClientCtx, c.ID, options), + RawInput: idToRawInput[c.ID], }) } return reports, nil @@ -667,10 +672,16 @@ func logIfRmError(id string, err error, reports []*reports.RmReport) { func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) { reports := []*entities.ContainerStartReport{} var exitCode = define.ExecErrorCodeGeneric - ctrs, namesOrIds, err := getContainersAndInputByContext(ic.ClientCtx, options.All, false, namesOrIds, options.Filters) + ctrs, rawInputs, err := getContainersAndInputByContext(ic.ClientCtx, options.All, false, namesOrIds, options.Filters) if err != nil { return nil, err } + idToRawInput := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID] = rawInputs[i] + } + } removeOptions := new(containers.RemoveOptions).WithVolumes(true).WithForce(false) removeContainer := func(id string) { reports, err := containers.Remove(ic.ClientCtx, id, removeOptions) @@ -678,15 +689,11 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri } // There can only be one container if attach was used - for i, ctr := range ctrs { + for _, ctr := range ctrs { name := ctr.ID - rawInput := ctr.ID - if !options.All { - rawInput = namesOrIds[i] - } report := entities.ContainerStartReport{ Id: name, - RawInput: rawInput, + RawInput: idToRawInput[name], ExitCode: exitCode, } ctrRunning := ctr.State == define.ContainerStateRunning.String() diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index bb3014099..2716aaf2a 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -110,6 +110,7 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities. options.WithAllTags(opts.AllTags).WithAuthfile(opts.Authfile).WithArch(opts.Arch).WithOS(opts.OS) options.WithVariant(opts.Variant).WithPassword(opts.Password) options.WithQuiet(opts.Quiet).WithUsername(opts.Username).WithPolicy(opts.PullPolicy.String()) + options.WithProgressWriter(opts.Writer) if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { if s == types.OptionalBoolTrue { options.WithSkipTLSVerify(true) diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go index 2a514861d..2e6134051 100644 --- a/pkg/domain/infra/tunnel/manifest.go +++ b/pkg/domain/infra/tunnel/manifest.go @@ -15,7 +15,7 @@ import ( // ManifestCreate implements manifest create via ImageEngine func (ir *ImageEngine) ManifestCreate(ctx context.Context, name string, images []string, opts entities.ManifestCreateOptions) (string, error) { - options := new(manifests.CreateOptions).WithAll(opts.All) + options := new(manifests.CreateOptions).WithAll(opts.All).WithAmend(opts.Amend) imageID, err := manifests.Create(ir.ClientCtx, name, images, options) if err != nil { return imageID, fmt.Errorf("error creating manifest: %w", err) diff --git a/pkg/env/env.go b/pkg/env/env.go index 8af9fd77c..fb7949ad8 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -37,6 +37,22 @@ func Slice(m map[string]string) []string { return env } +// Map transforms the specified slice of environment variables into a +// map. +func Map(slice []string) map[string]string { + envmap := make(map[string]string, len(slice)) + for _, val := range slice { + data := strings.SplitN(val, "=", 2) + + if len(data) > 1 { + envmap[data[0]] = data[1] + } else { + envmap[data[0]] = "" + } + } + return envmap +} + // Join joins the two environment maps with override overriding base. func Join(base map[string]string, override map[string]string) map[string]string { if len(base) == 0 { @@ -87,10 +103,6 @@ func parseEnv(env map[string]string, line string) error { } // trim the front of a variable, but nothing else name := strings.TrimLeft(data[0], whiteSpaces) - if strings.ContainsAny(name, whiteSpaces) { - return fmt.Errorf("name %q has white spaces, poorly formatted name", name) - } - if len(data) > 1 { env[name] = data[1] } else { diff --git a/pkg/machine/config.go b/pkg/machine/config.go index 5162006db..54aa9e1b7 100644 --- a/pkg/machine/config.go +++ b/pkg/machine/config.go @@ -175,7 +175,7 @@ func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url return uri } -// GetCacheDir returns the dir where VM images are downladed into when pulled +// GetCacheDir returns the dir where VM images are downloaded into when pulled func GetCacheDir(vmType string) (string, error) { dataDir, err := GetDataDir(vmType) if err != nil { diff --git a/pkg/machine/e2e/basic_test.go b/pkg/machine/e2e/basic_test.go index da0310485..fa1728770 100644 --- a/pkg/machine/e2e/basic_test.go +++ b/pkg/machine/e2e/basic_test.go @@ -1,6 +1,8 @@ package e2e_test import ( + "os" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" @@ -20,6 +22,12 @@ var _ = Describe("run basic podman commands", func() { }) It("Basic ops", func() { + // golangci-lint has trouble with actually skipping tests marked Skip + // so skip it on cirrus envs and where CIRRUS_CI isn't set. + if os.Getenv("CIRRUS_CI") != "false" { + Skip("FIXME: #15347 - ssh know hosts broken - fails on PR runs and on x86_64") + } + name := randomString() i := new(initMachine) session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath).withNow()).run() diff --git a/pkg/machine/pull.go b/pkg/machine/pull.go index 26b6adc67..22a1b4c0a 100644 --- a/pkg/machine/pull.go +++ b/pkg/machine/pull.go @@ -213,8 +213,8 @@ func decompressXZ(src string, output io.WriteCloser) error { var read io.Reader var cmd *exec.Cmd // Prefer xz utils for fastest performance, fallback to go xi2 impl - if _, err := exec.LookPath("xzcat"); err == nil { - cmd = exec.Command("xzcat", "-k", src) + if _, err := exec.LookPath("xz"); err == nil { + cmd = exec.Command("xz", "-d", "-c", "-k", src) read, err = cmd.StdoutPipe() if err != nil { return err diff --git a/pkg/machine/qemu/claim_unsupported.go b/pkg/machine/qemu/claim_unsupported.go index e0b3dd3d3..187ef9d69 100644 --- a/pkg/machine/qemu/claim_unsupported.go +++ b/pkg/machine/qemu/claim_unsupported.go @@ -1,5 +1,5 @@ -//go:build !darwin && !windows -// +build !darwin,!windows +//go:build !darwin +// +build !darwin package qemu diff --git a/pkg/machine/qemu/config.go b/pkg/machine/qemu/config.go index bada1af9b..8081727f6 100644 --- a/pkg/machine/qemu/config.go +++ b/pkg/machine/qemu/config.go @@ -1,6 +1,3 @@ -//go:build (amd64 && !windows) || (arm64 && !windows) -// +build amd64,!windows arm64,!windows - package qemu import ( diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index 213f7ce5d..e97b68e31 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -545,12 +545,12 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error { return err } defer fd.Close() - dnr, err := os.OpenFile("/dev/null", os.O_RDONLY, 0755) + dnr, err := os.OpenFile(os.DevNull, os.O_RDONLY, 0755) if err != nil { return err } defer dnr.Close() - dnw, err := os.OpenFile("/dev/null", os.O_WRONLY, 0755) + dnw, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0755) if err != nil { return err } @@ -870,7 +870,7 @@ func NewQMPMonitor(network, name string, timeout time.Duration) (Monitor, error) if err != nil { return Monitor{}, err } - if !rootless.IsRootless() { + if isRootful() { rtDir = "/run" } rtDir = filepath.Join(rtDir, "podman") @@ -1216,11 +1216,11 @@ func (v *MachineVM) startHostNetworking() (string, apiForwardingState, error) { } attr := new(os.ProcAttr) - dnr, err := os.OpenFile("/dev/null", os.O_RDONLY, 0755) + dnr, err := os.OpenFile(os.DevNull, os.O_RDONLY, 0755) if err != nil { return "", noForwarding, err } - dnw, err := os.OpenFile("/dev/null", os.O_WRONLY, 0755) + dnw, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0755) if err != nil { return "", noForwarding, err } @@ -1371,7 +1371,7 @@ func (v *MachineVM) setPIDSocket() error { if err != nil { return err } - if !rootless.IsRootless() { + if isRootful() { rtPath = "/run" } socketDir := filepath.Join(rtPath, "podman") @@ -1397,7 +1397,7 @@ func (v *MachineVM) getSocketandPid() (string, string, error) { if err != nil { return "", "", err } - if !rootless.IsRootless() { + if isRootful() { rtPath = "/run" } socketDir := filepath.Join(rtPath, "podman") @@ -1735,3 +1735,11 @@ func isProcessAlive(pid int) bool { func (p *Provider) VMType() string { return vmtype } + +func isRootful() bool { + // Rootless is not relevant on Windows. In the future rootless.IsRootless + // could be switched to return true on Windows, and other codepaths migrated + // for now will check additionally for valid os.Getuid + + return !rootless.IsRootless() && os.Getuid() != -1 +} diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index ec85f0f79..d57efa0d1 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -19,6 +19,7 @@ import ( "github.com/containers/podman/v4/pkg/signal" "github.com/containers/podman/v4/pkg/specgen" spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/openshift/imagebuilder" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) @@ -131,6 +132,17 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat defaultEnvs = envLib.Join(envLib.DefaultEnvVariables(), envLib.Join(defaultEnvs, envs)) } + for _, e := range s.EnvMerge { + processedWord, err := imagebuilder.ProcessWord(e, envLib.Slice(defaultEnvs)) + if err != nil { + return nil, fmt.Errorf("unable to process variables for --env-merge %s: %w", e, err) + } + splitWord := strings.Split(processedWord, "=") + if _, ok := defaultEnvs[splitWord[0]]; ok { + defaultEnvs[splitWord[0]] = splitWord[1] + } + } + for _, e := range s.UnsetEnv { delete(defaultEnvs, e) } @@ -140,10 +152,8 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat } // First transform the os env into a map. We need it for the labels later in // any case. - osEnv, err := envLib.ParseSlice(os.Environ()) - if err != nil { - return nil, fmt.Errorf("error parsing host environment variables: %w", err) - } + osEnv := envLib.Map(os.Environ()) + // Caller Specified defaults if s.EnvHost { defaultEnvs = envLib.Join(defaultEnvs, osEnv) @@ -347,9 +357,21 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID s conf.Systemd = tmpSystemd conf.Mounts = tmpMounts - if conf.Spec != nil && conf.Spec.Linux != nil && conf.Spec.Linux.Resources != nil { - if specg.ResourceLimits == nil { - specg.ResourceLimits = conf.Spec.Linux.Resources + if conf.Spec != nil { + if conf.Spec.Linux != nil && conf.Spec.Linux.Resources != nil { + if specg.ResourceLimits == nil { + specg.ResourceLimits = conf.Spec.Linux.Resources + } + } + if conf.Spec.Process != nil && conf.Spec.Process.Env != nil { + env := make(map[string]string) + for _, entry := range conf.Spec.Process.Env { + split := strings.Split(entry, "=") + if len(split) == 2 { + env[split[0]] = split[1] + } + } + specg.Env = env } } diff --git a/pkg/specgen/generate/validate.go b/pkg/specgen/generate/validate.go index 9c933d747..3c5d5fb96 100644 --- a/pkg/specgen/generate/validate.go +++ b/pkg/specgen/generate/validate.go @@ -9,6 +9,7 @@ import ( "github.com/containers/common/pkg/cgroups" "github.com/containers/common/pkg/sysinfo" + "github.com/containers/podman/v4/pkg/rootless" "github.com/containers/podman/v4/pkg/specgen" "github.com/containers/podman/v4/utils" ) @@ -19,6 +20,11 @@ func verifyContainerResourcesCgroupV1(s *specgen.SpecGenerator) ([]string, error sysInfo := sysinfo.New(true) + if s.ResourceLimits != nil && rootless.IsRootless() { + s.ResourceLimits = nil + warnings = append(warnings, "Resource limits are not supported and ignored on cgroups V1 rootless systems") + } + if s.ResourceLimits == nil { return warnings, nil } diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index b90f07ef8..51b6736a9 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -204,6 +204,9 @@ type ContainerBasicConfig struct { // The execution domain system allows Linux to provide limited support // for binaries compiled under other UNIX-like operating systems. Personality *spec.LinuxPersonality `json:"personality,omitempty"` + // EnvMerge takes the specified environment variables from image and preprocess them before injecting them into the + // container. + EnvMerge []string `json:"envmerge,omitempty"` // UnsetEnv unsets the specified default environment variables from the image or from buildin or containers.conf // Optional. UnsetEnv []string `json:"unsetenv,omitempty"` diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 7392e7b44..8c2c59fed 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -362,10 +362,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions // First transform the os env into a map. We need it for the labels later in // any case. - osEnv, err := envLib.ParseSlice(os.Environ()) - if err != nil { - return fmt.Errorf("error parsing host environment variables: %w", err) - } + osEnv := envLib.Map(os.Environ()) if !s.EnvHost { s.EnvHost = c.EnvHost @@ -839,6 +836,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions if !s.Volatile { s.Volatile = c.Rm } + if len(s.EnvMerge) == 0 || len(c.EnvMerge) != 0 { + s.EnvMerge = c.EnvMerge + } if len(s.UnsetEnv) == 0 || len(c.UnsetEnv) != 0 { s.UnsetEnv = c.UnsetEnv } diff --git a/pkg/systemd/notifyproxy/notifyproxy_test.go b/pkg/systemd/notifyproxy/notifyproxy_test.go index edad95659..ce63fc9cd 100644 --- a/pkg/systemd/notifyproxy/notifyproxy_test.go +++ b/pkg/systemd/notifyproxy/notifyproxy_test.go @@ -37,7 +37,7 @@ func TestWaitAndClose(t *testing.T) { time.Sleep(250 * time.Millisecond) select { case err := <-ch: - t.Fatalf("Should stil be waiting but received %v", err) + t.Fatalf("Should still be waiting but received %v", err) default: } diff --git a/pkg/trust/config.go b/pkg/trust/config.go deleted file mode 100644 index 6186d4cbd..000000000 --- a/pkg/trust/config.go +++ /dev/null @@ -1,12 +0,0 @@ -package trust - -// Policy describes a basic trust policy configuration -type Policy struct { - Transport string `json:"transport"` - Name string `json:"name,omitempty"` - RepoName string `json:"repo_name,omitempty"` - Keys []string `json:"keys,omitempty"` - SignatureStore string `json:"sigstore,omitempty"` - Type string `json:"type"` - GPGId string `json:"gpg_id,omitempty"` -} diff --git a/pkg/trust/policy.go b/pkg/trust/policy.go new file mode 100644 index 000000000..326fe17af --- /dev/null +++ b/pkg/trust/policy.go @@ -0,0 +1,248 @@ +package trust + +import ( + "bufio" + "bytes" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/containers/image/v5/types" + "github.com/sirupsen/logrus" +) + +// policyContent is the overall structure of a policy.json file (= c/image/v5/signature.Policy) +type policyContent struct { + Default []repoContent `json:"default"` + Transports transportsContent `json:"transports,omitempty"` +} + +// transportsContent contains policies for individual transports (= c/image/v5/signature.Policy.Transports) +type transportsContent map[string]repoMap + +// repoMap maps a scope name to requirements that apply to that scope (= c/image/v5/signature.PolicyTransportScopes) +type repoMap map[string][]repoContent + +// repoContent is a single policy requirement (one of possibly several for a scope), representing all of the individual alternatives in a single merged struct +// (= c/image/v5/signature.{PolicyRequirement,pr*}) +type repoContent struct { + Type string `json:"type"` + KeyType string `json:"keyType,omitempty"` + KeyPath string `json:"keyPath,omitempty"` + KeyPaths []string `json:"keyPaths,omitempty"` + KeyData string `json:"keyData,omitempty"` + SignedIdentity json.RawMessage `json:"signedIdentity,omitempty"` +} + +// genericPolicyContent is the overall structure of a policy.json file (= c/image/v5/signature.Policy), using generic data for individual requirements. +type genericPolicyContent struct { + Default json.RawMessage `json:"default"` + Transports genericTransportsContent `json:"transports,omitempty"` +} + +// genericTransportsContent contains policies for individual transports (= c/image/v5/signature.Policy.Transports), using generic data for individual requirements. +type genericTransportsContent map[string]genericRepoMap + +// genericRepoMap maps a scope name to requirements that apply to that scope (= c/image/v5/signature.PolicyTransportScopes) +type genericRepoMap map[string]json.RawMessage + +// DefaultPolicyPath returns a path to the default policy of the system. +func DefaultPolicyPath(sys *types.SystemContext) string { + systemDefaultPolicyPath := "/etc/containers/policy.json" + if sys != nil { + if sys.SignaturePolicyPath != "" { + return sys.SignaturePolicyPath + } + if sys.RootForImplicitAbsolutePaths != "" { + return filepath.Join(sys.RootForImplicitAbsolutePaths, systemDefaultPolicyPath) + } + } + return systemDefaultPolicyPath +} + +// gpgIDReader returns GPG key IDs of keys stored at the provided path. +// It exists only for tests, production code should always use getGPGIdFromKeyPath. +type gpgIDReader func(string) []string + +// createTmpFile creates a temp file under dir and writes the content into it +func createTmpFile(dir, pattern string, content []byte) (string, error) { + tmpfile, err := ioutil.TempFile(dir, pattern) + if err != nil { + return "", err + } + defer tmpfile.Close() + + if _, err := tmpfile.Write(content); err != nil { + return "", err + } + return tmpfile.Name(), nil +} + +// getGPGIdFromKeyPath returns GPG key IDs of keys stored at the provided path. +func getGPGIdFromKeyPath(path string) []string { + cmd := exec.Command("gpg2", "--with-colons", path) + results, err := cmd.Output() + if err != nil { + logrus.Errorf("Getting key identity: %s", err) + return nil + } + return parseUids(results) +} + +// getGPGIdFromKeyData returns GPG key IDs of keys in the provided keyring. +func getGPGIdFromKeyData(idReader gpgIDReader, key string) []string { + decodeKey, err := base64.StdEncoding.DecodeString(key) + if err != nil { + logrus.Errorf("%s, error decoding key data", err) + return nil + } + tmpfileName, err := createTmpFile("", "", decodeKey) + if err != nil { + logrus.Errorf("Creating key date temp file %s", err) + } + defer os.Remove(tmpfileName) + return idReader(tmpfileName) +} + +func parseUids(colonDelimitKeys []byte) []string { + var parseduids []string + scanner := bufio.NewScanner(bytes.NewReader(colonDelimitKeys)) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "uid:") || strings.HasPrefix(line, "pub:") { + uid := strings.Split(line, ":")[9] + if uid == "" { + continue + } + parseduid := uid + if strings.Contains(uid, "<") && strings.Contains(uid, ">") { + parseduid = strings.SplitN(strings.SplitAfterN(uid, "<", 2)[1], ">", 2)[0] + } + parseduids = append(parseduids, parseduid) + } + } + return parseduids +} + +// getPolicy parses policy.json into policyContent. +func getPolicy(policyPath string) (policyContent, error) { + var policyContentStruct policyContent + policyContent, err := ioutil.ReadFile(policyPath) + if err != nil { + return policyContentStruct, fmt.Errorf("unable to read policy file: %w", err) + } + if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { + return policyContentStruct, fmt.Errorf("could not parse trust policies from %s: %w", policyPath, err) + } + return policyContentStruct, nil +} + +var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "sigstoreSigned": "sigstoreSigned", "reject": "reject"} + +func trustTypeDescription(trustType string) string { + trustDescription, exist := typeDescription[trustType] + if !exist { + logrus.Warnf("Invalid trust type %s", trustType) + } + return trustDescription +} + +// AddPolicyEntriesInput collects some parameters to AddPolicyEntries, +// primarily so that the callers use named values instead of just strings in a sequence. +type AddPolicyEntriesInput struct { + Scope string // "default" or a docker/atomic scope name + Type string + PubKeyFiles []string // For signature enforcement types, paths to public keys files (where the image needs to be signed by at least one key from _each_ of the files). File format depends on Type. +} + +// AddPolicyEntries adds one or more policy entries necessary to implement AddPolicyEntriesInput. +func AddPolicyEntries(policyPath string, input AddPolicyEntriesInput) error { + var ( + policyContentStruct genericPolicyContent + newReposContent []repoContent + ) + trustType := input.Type + if trustType == "accept" { + trustType = "insecureAcceptAnything" + } + pubkeysfile := input.PubKeyFiles + + // The error messages in validation failures use input.Type instead of trustType to match the user’s input. + switch trustType { + case "insecureAcceptAnything", "reject": + if len(pubkeysfile) != 0 { + return fmt.Errorf("%d public keys unexpectedly provided for trust type %v", len(pubkeysfile), input.Type) + } + newReposContent = append(newReposContent, repoContent{Type: trustType}) + + case "signedBy": + if len(pubkeysfile) == 0 { + return errors.New("at least one public key must be defined for type 'signedBy'") + } + for _, filepath := range pubkeysfile { + newReposContent = append(newReposContent, repoContent{Type: trustType, KeyType: "GPGKeys", KeyPath: filepath}) + } + + case "sigstoreSigned": + if len(pubkeysfile) == 0 { + return errors.New("at least one public key must be defined for type 'sigstoreSigned'") + } + for _, filepath := range pubkeysfile { + newReposContent = append(newReposContent, repoContent{Type: trustType, KeyPath: filepath}) + } + + default: + return fmt.Errorf("unknown trust type %q", input.Type) + } + newReposJSON, err := json.Marshal(newReposContent) + if err != nil { + return err + } + + _, err = os.Stat(policyPath) + if !os.IsNotExist(err) { + policyContent, err := ioutil.ReadFile(policyPath) + if err != nil { + return err + } + if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { + return errors.New("could not read trust policies") + } + } + if input.Scope == "default" { + policyContentStruct.Default = json.RawMessage(newReposJSON) + } else { + if len(policyContentStruct.Default) == 0 { + return errors.New("default trust policy must be set") + } + registryExists := false + for transport, transportval := range policyContentStruct.Transports { + _, registryExists = transportval[input.Scope] + if registryExists { + policyContentStruct.Transports[transport][input.Scope] = json.RawMessage(newReposJSON) + break + } + } + if !registryExists { + if policyContentStruct.Transports == nil { + policyContentStruct.Transports = make(map[string]genericRepoMap) + } + if policyContentStruct.Transports["docker"] == nil { + policyContentStruct.Transports["docker"] = make(map[string]json.RawMessage) + } + policyContentStruct.Transports["docker"][input.Scope] = json.RawMessage(newReposJSON) + } + } + + data, err := json.MarshalIndent(policyContentStruct, "", " ") + if err != nil { + return fmt.Errorf("error setting trust policy: %w", err) + } + return ioutil.WriteFile(policyPath, data, 0644) +} diff --git a/pkg/trust/policy_test.go b/pkg/trust/policy_test.go new file mode 100644 index 000000000..3952b72c3 --- /dev/null +++ b/pkg/trust/policy_test.go @@ -0,0 +1,196 @@ +package trust + +import ( + "encoding/json" + "os" + "path/filepath" + "testing" + + "github.com/containers/image/v5/signature" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestAddPolicyEntries(t *testing.T) { + tempDir := t.TempDir() + policyPath := filepath.Join(tempDir, "policy.json") + + minimalPolicy := &signature.Policy{ + Default: []signature.PolicyRequirement{ + signature.NewPRInsecureAcceptAnything(), + }, + } + minimalPolicyJSON, err := json.Marshal(minimalPolicy) + require.NoError(t, err) + err = os.WriteFile(policyPath, minimalPolicyJSON, 0600) + require.NoError(t, err) + + // Invalid input: + for _, invalid := range []AddPolicyEntriesInput{ + { + Scope: "default", + Type: "accept", + PubKeyFiles: []string{"/does-not-make-sense"}, + }, + { + Scope: "default", + Type: "insecureAcceptAnything", + PubKeyFiles: []string{"/does-not-make-sense"}, + }, + { + Scope: "default", + Type: "reject", + PubKeyFiles: []string{"/does-not-make-sense"}, + }, + { + Scope: "default", + Type: "signedBy", + PubKeyFiles: []string{}, // A key is missing + }, + { + Scope: "default", + Type: "sigstoreSigned", + PubKeyFiles: []string{}, // A key is missing + }, + { + Scope: "default", + Type: "this-is-unknown", + PubKeyFiles: []string{}, + }, + } { + err := AddPolicyEntries(policyPath, invalid) + assert.Error(t, err, "%#v", invalid) + } + + err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{ + Scope: "default", + Type: "reject", + }) + assert.NoError(t, err) + err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{ + Scope: "quay.io/accepted", + Type: "accept", + }) + assert.NoError(t, err) + err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{ + Scope: "quay.io/multi-signed", + Type: "signedBy", + PubKeyFiles: []string{"/1.pub", "/2.pub"}, + }) + assert.NoError(t, err) + err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{ + Scope: "quay.io/sigstore-signed", + Type: "sigstoreSigned", + PubKeyFiles: []string{"/1.pub", "/2.pub"}, + }) + assert.NoError(t, err) + + // Test that the outcome is consumable, and compare it with the expected values. + parsedPolicy, err := signature.NewPolicyFromFile(policyPath) + require.NoError(t, err) + assert.Equal(t, &signature.Policy{ + Default: signature.PolicyRequirements{ + signature.NewPRReject(), + }, + Transports: map[string]signature.PolicyTransportScopes{ + "docker": { + "quay.io/accepted": { + signature.NewPRInsecureAcceptAnything(), + }, + "quay.io/multi-signed": { + xNewPRSignedByKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSignedByKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + "quay.io/sigstore-signed": { + xNewPRSigstoreSignedKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSigstoreSignedKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + }, + }, + }, parsedPolicy) + + // Test that completely unknown JSON is preserved + jsonWithUnknownData := `{ + "default": [ + { + "type": "this is unknown", + "unknown field": "should be preserved" + } + ], + "transports": + { + "docker-daemon": + { + "": [{ + "type":"this is unknown 2", + "unknown field 2": "should be preserved 2" + }] + } + } +}` + err = os.WriteFile(policyPath, []byte(jsonWithUnknownData), 0600) + require.NoError(t, err) + err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{ + Scope: "quay.io/innocuous", + Type: "signedBy", + PubKeyFiles: []string{"/1.pub"}, + }) + require.NoError(t, err) + updatedJSONWithUnknownData, err := os.ReadFile(policyPath) + require.NoError(t, err) + // Decode updatedJSONWithUnknownData so that this test does not depend on details of the encoding. + // To reduce noise in the constants below: + type a = []interface{} + type m = map[string]interface{} + var parsedUpdatedJSON m + err = json.Unmarshal(updatedJSONWithUnknownData, &parsedUpdatedJSON) + require.NoError(t, err) + assert.Equal(t, m{ + "default": a{ + m{ + "type": "this is unknown", + "unknown field": "should be preserved", + }, + }, + "transports": m{ + "docker-daemon": m{ + "": a{ + m{ + "type": "this is unknown 2", + "unknown field 2": "should be preserved 2", + }, + }, + }, + "docker": m{ + "quay.io/innocuous": a{ + m{ + "type": "signedBy", + "keyType": "GPGKeys", + "keyPath": "/1.pub", + }, + }, + }, + }, + }, parsedUpdatedJSON) +} + +// xNewPRSignedByKeyPath is a wrapper for NewPRSignedByKeyPath which must not fail. +func xNewPRSignedByKeyPath(t *testing.T, keyPath string, signedIdentity signature.PolicyReferenceMatch) signature.PolicyRequirement { + pr, err := signature.NewPRSignedByKeyPath(signature.SBKeyTypeGPGKeys, keyPath, signedIdentity) + require.NoError(t, err) + return pr +} + +// xNewPRSignedByKeyPaths is a wrapper for NewPRSignedByKeyPaths which must not fail. +func xNewPRSignedByKeyPaths(t *testing.T, keyPaths []string, signedIdentity signature.PolicyReferenceMatch) signature.PolicyRequirement { + pr, err := signature.NewPRSignedByKeyPaths(signature.SBKeyTypeGPGKeys, keyPaths, signedIdentity) + require.NoError(t, err) + return pr +} + +// xNewPRSigstoreSignedKeyPath is a wrapper for NewPRSigstoreSignedKeyPath which must not fail. +func xNewPRSigstoreSignedKeyPath(t *testing.T, keyPath string, signedIdentity signature.PolicyReferenceMatch) signature.PolicyRequirement { + pr, err := signature.NewPRSigstoreSignedKeyPath(keyPath, signedIdentity) + require.NoError(t, err) + return pr +} diff --git a/pkg/trust/registries.go b/pkg/trust/registries.go new file mode 100644 index 000000000..0adc38232 --- /dev/null +++ b/pkg/trust/registries.go @@ -0,0 +1,126 @@ +package trust + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/containers/image/v5/types" + "github.com/docker/docker/pkg/homedir" + "github.com/ghodss/yaml" +) + +// registryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all. +// NOTE: Keep this in sync with docs/registries.d.md! +type registryConfiguration struct { + DefaultDocker *registryNamespace `json:"default-docker"` + // The key is a namespace, using fully-expanded Docker reference format or parent namespaces (per dockerReference.PolicyConfiguration*), + Docker map[string]registryNamespace `json:"docker"` +} + +// registryNamespace defines lookaside locations for a single namespace. +type registryNamespace struct { + Lookaside string `json:"lookaside"` // For reading, and if LookasideStaging is not present, for writing. + LookasideStaging string `json:"lookaside-staging"` // For writing only. + SigStore string `json:"sigstore"` // For reading, and if SigStoreStaging is not present, for writing. + SigStoreStaging string `json:"sigstore-staging"` // For writing only. +} + +// systemRegistriesDirPath is the path to registries.d. +const systemRegistriesDirPath = "/etc/containers/registries.d" + +// userRegistriesDir is the path to the per user registries.d. +var userRegistriesDir = filepath.FromSlash(".config/containers/registries.d") + +// RegistriesDirPath returns a path to registries.d +func RegistriesDirPath(sys *types.SystemContext) string { + if sys != nil && sys.RegistriesDirPath != "" { + return sys.RegistriesDirPath + } + userRegistriesDirPath := filepath.Join(homedir.Get(), userRegistriesDir) + if _, err := os.Stat(userRegistriesDirPath); err == nil { + return userRegistriesDirPath + } + if sys != nil && sys.RootForImplicitAbsolutePaths != "" { + return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath) + } + + return systemRegistriesDirPath +} + +// loadAndMergeConfig loads registries.d configuration files in dirPath +func loadAndMergeConfig(dirPath string) (*registryConfiguration, error) { + mergedConfig := registryConfiguration{Docker: map[string]registryNamespace{}} + dockerDefaultMergedFrom := "" + nsMergedFrom := map[string]string{} + + dir, err := os.Open(dirPath) + if err != nil { + if os.IsNotExist(err) { + return &mergedConfig, nil + } + return nil, err + } + configNames, err := dir.Readdirnames(0) + if err != nil { + return nil, err + } + for _, configName := range configNames { + if !strings.HasSuffix(configName, ".yaml") { + continue + } + configPath := filepath.Join(dirPath, configName) + configBytes, err := ioutil.ReadFile(configPath) + if err != nil { + return nil, err + } + var config registryConfiguration + err = yaml.Unmarshal(configBytes, &config) + if err != nil { + return nil, fmt.Errorf("error parsing %s: %w", configPath, err) + } + if config.DefaultDocker != nil { + if mergedConfig.DefaultDocker != nil { + return nil, fmt.Errorf(`error parsing signature storage configuration: "default-docker" defined both in "%s" and "%s"`, + dockerDefaultMergedFrom, configPath) + } + mergedConfig.DefaultDocker = config.DefaultDocker + dockerDefaultMergedFrom = configPath + } + for nsName, nsConfig := range config.Docker { // includes config.Docker == nil + if _, ok := mergedConfig.Docker[nsName]; ok { + return nil, fmt.Errorf(`error parsing signature storage configuration: "docker" namespace "%s" defined both in "%s" and "%s"`, + nsName, nsMergedFrom[nsName], configPath) + } + mergedConfig.Docker[nsName] = nsConfig + nsMergedFrom[nsName] = configPath + } + } + return &mergedConfig, nil +} + +// registriesDConfigurationForScope returns registries.d configuration for the provided scope. +// scope can be "" to return only the global default configuration entry. +func registriesDConfigurationForScope(registryConfigs *registryConfiguration, scope string) *registryNamespace { + searchScope := scope + if searchScope != "" { + if !strings.Contains(searchScope, "/") { + val, exists := registryConfigs.Docker[searchScope] + if exists { + return &val + } + } + for range strings.Split(scope, "/") { + val, exists := registryConfigs.Docker[searchScope] + if exists { + return &val + } + if strings.Contains(searchScope, "/") { + searchScope = searchScope[:strings.LastIndex(searchScope, "/")] + } + } + } + return registryConfigs.DefaultDocker +} diff --git a/pkg/trust/testdata/default.yaml b/pkg/trust/testdata/default.yaml new file mode 100644 index 000000000..31bcd35ef --- /dev/null +++ b/pkg/trust/testdata/default.yaml @@ -0,0 +1,25 @@ +# This is a default registries.d configuration file. You may +# add to this file or create additional files in registries.d/. +# +# lookaside: indicates a location that is read and write +# lookaside-staging: indicates a location that is only for write +# +# lookaside and lookaside-staging take a value of the following: +# lookaside: {schema}://location +# +# For reading signatures, schema may be http, https, or file. +# For writing signatures, schema may only be file. + +# This is the default signature write location for docker registries. +default-docker: +# lookaside: file:///var/lib/containers/sigstore + lookaside-staging: file:///var/lib/containers/sigstore + +# The 'docker' indicator here is the start of the configuration +# for docker registries. +# +# docker: +# +# privateregistry.com: +# lookaside: http://privateregistry.com/sigstore/ +# lookaside-staging: /mnt/nfs/privateregistry/sigstore diff --git a/pkg/trust/testdata/quay.io.yaml b/pkg/trust/testdata/quay.io.yaml new file mode 100644 index 000000000..80071596d --- /dev/null +++ b/pkg/trust/testdata/quay.io.yaml @@ -0,0 +1,3 @@ +docker: + quay.io/multi-signed: + lookaside: https://quay.example.com/sigstore diff --git a/pkg/trust/testdata/redhat.yaml b/pkg/trust/testdata/redhat.yaml new file mode 100644 index 000000000..8e40a4174 --- /dev/null +++ b/pkg/trust/testdata/redhat.yaml @@ -0,0 +1,5 @@ +docker: + registry.redhat.io: + sigstore: https://registry.redhat.io/containers/sigstore + registry.access.redhat.com: + sigstore: https://registry.redhat.io/containers/sigstore diff --git a/pkg/trust/trust.go b/pkg/trust/trust.go index 663a1b5e2..07d144bc1 100644 --- a/pkg/trust/trust.go +++ b/pkg/trust/trust.go @@ -1,243 +1,127 @@ package trust import ( - "bufio" - "bytes" - "encoding/base64" - "encoding/json" "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" + "sort" "strings" - - "github.com/containers/image/v5/types" - "github.com/docker/docker/pkg/homedir" - "github.com/ghodss/yaml" - "github.com/sirupsen/logrus" ) -// PolicyContent struct for policy.json file -type PolicyContent struct { - Default []RepoContent `json:"default"` - Transports TransportsContent `json:"transports,omitempty"` -} - -// RepoContent struct used under each repo -type RepoContent struct { - Type string `json:"type"` - KeyType string `json:"keyType,omitempty"` - KeyPath string `json:"keyPath,omitempty"` - KeyData string `json:"keyData,omitempty"` - SignedIdentity json.RawMessage `json:"signedIdentity,omitempty"` -} - -// RepoMap map repo name to policycontent for each repo -type RepoMap map[string][]RepoContent - -// TransportsContent struct for content under "transports" -type TransportsContent map[string]RepoMap - -// RegistryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all. -// NOTE: Keep this in sync with docs/registries.d.md! -type RegistryConfiguration struct { - DefaultDocker *RegistryNamespace `json:"default-docker"` - // The key is a namespace, using fully-expanded Docker reference format or parent namespaces (per dockerReference.PolicyConfiguration*), - Docker map[string]RegistryNamespace `json:"docker"` +// Policy describes a basic trust policy configuration +type Policy struct { + Transport string `json:"transport"` + Name string `json:"name,omitempty"` + RepoName string `json:"repo_name,omitempty"` + Keys []string `json:"keys,omitempty"` + SignatureStore string `json:"sigstore,omitempty"` + Type string `json:"type"` + GPGId string `json:"gpg_id,omitempty"` } -// RegistryNamespace defines lookaside locations for a single namespace. -type RegistryNamespace struct { - SigStore string `json:"sigstore"` // For reading, and if SigStoreStaging is not present, for writing. - SigStoreStaging string `json:"sigstore-staging"` // For writing only. +// PolicyDescription returns an user-focused description of the policy in policyPath and registries.d data from registriesDirPath. +func PolicyDescription(policyPath, registriesDirPath string) ([]*Policy, error) { + return policyDescriptionWithGPGIDReader(policyPath, registriesDirPath, getGPGIdFromKeyPath) } -// ShowOutput keep the fields for image trust show command -type ShowOutput struct { - Repo string - Trusttype string - GPGid string - Sigstore string -} - -// systemRegistriesDirPath is the path to registries.d. -const systemRegistriesDirPath = "/etc/containers/registries.d" - -// userRegistriesDir is the path to the per user registries.d. -var userRegistriesDir = filepath.FromSlash(".config/containers/registries.d") - -// DefaultPolicyPath returns a path to the default policy of the system. -func DefaultPolicyPath(sys *types.SystemContext) string { - systemDefaultPolicyPath := "/etc/containers/policy.json" - if sys != nil { - if sys.SignaturePolicyPath != "" { - return sys.SignaturePolicyPath - } - if sys.RootForImplicitAbsolutePaths != "" { - return filepath.Join(sys.RootForImplicitAbsolutePaths, systemDefaultPolicyPath) - } - } - return systemDefaultPolicyPath -} - -// RegistriesDirPath returns a path to registries.d -func RegistriesDirPath(sys *types.SystemContext) string { - if sys != nil && sys.RegistriesDirPath != "" { - return sys.RegistriesDirPath - } - userRegistriesDirPath := filepath.Join(homedir.Get(), userRegistriesDir) - if _, err := os.Stat(userRegistriesDirPath); err == nil { - return userRegistriesDirPath +// policyDescriptionWithGPGIDReader is PolicyDescription with a gpgIDReader parameter. It exists only to make testing easier. +func policyDescriptionWithGPGIDReader(policyPath, registriesDirPath string, idReader gpgIDReader) ([]*Policy, error) { + policyContentStruct, err := getPolicy(policyPath) + if err != nil { + return nil, fmt.Errorf("could not read trust policies: %w", err) } - if sys != nil && sys.RootForImplicitAbsolutePaths != "" { - return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath) + res, err := getPolicyShowOutput(policyContentStruct, registriesDirPath, idReader) + if err != nil { + return nil, fmt.Errorf("could not show trust policies: %w", err) } - - return systemRegistriesDirPath + return res, nil } -// LoadAndMergeConfig loads configuration files in dirPath -func LoadAndMergeConfig(dirPath string) (*RegistryConfiguration, error) { - mergedConfig := RegistryConfiguration{Docker: map[string]RegistryNamespace{}} - dockerDefaultMergedFrom := "" - nsMergedFrom := map[string]string{} +func getPolicyShowOutput(policyContentStruct policyContent, systemRegistriesDirPath string, idReader gpgIDReader) ([]*Policy, error) { + var output []*Policy - dir, err := os.Open(dirPath) + registryConfigs, err := loadAndMergeConfig(systemRegistriesDirPath) if err != nil { - if os.IsNotExist(err) { - return &mergedConfig, nil - } return nil, err } - configNames, err := dir.Readdirnames(0) - if err != nil { - return nil, err - } - for _, configName := range configNames { - if !strings.HasSuffix(configName, ".yaml") { - continue - } - configPath := filepath.Join(dirPath, configName) - configBytes, err := ioutil.ReadFile(configPath) - if err != nil { - return nil, err + + if len(policyContentStruct.Default) > 0 { + template := Policy{ + Transport: "all", + Name: "* (default)", + RepoName: "default", } - var config RegistryConfiguration - err = yaml.Unmarshal(configBytes, &config) - if err != nil { - return nil, fmt.Errorf("error parsing %s: %w", configPath, err) + output = append(output, descriptionsOfPolicyRequirements(policyContentStruct.Default, template, registryConfigs, "", idReader)...) + } + // FIXME: This should use x/exp/maps.Keys after we update to Go 1.18. + transports := []string{} + for t := range policyContentStruct.Transports { + transports = append(transports, t) + } + sort.Strings(transports) + for _, transport := range transports { + transval := policyContentStruct.Transports[transport] + if transport == "docker" { + transport = "repository" } - if config.DefaultDocker != nil { - if mergedConfig.DefaultDocker != nil { - return nil, fmt.Errorf(`error parsing signature storage configuration: "default-docker" defined both in "%s" and "%s"`, - dockerDefaultMergedFrom, configPath) - } - mergedConfig.DefaultDocker = config.DefaultDocker - dockerDefaultMergedFrom = configPath + + // FIXME: This should use x/exp/maps.Keys after we update to Go 1.18. + scopes := []string{} + for s := range transval { + scopes = append(scopes, s) } - for nsName, nsConfig := range config.Docker { // includes config.Docker == nil - if _, ok := mergedConfig.Docker[nsName]; ok { - return nil, fmt.Errorf(`error parsing signature storage configuration: "docker" namespace "%s" defined both in "%s" and "%s"`, - nsName, nsMergedFrom[nsName], configPath) + sort.Strings(scopes) + for _, repo := range scopes { + repoval := transval[repo] + template := Policy{ + Transport: transport, + Name: repo, + RepoName: repo, } - mergedConfig.Docker[nsName] = nsConfig - nsMergedFrom[nsName] = configPath + output = append(output, descriptionsOfPolicyRequirements(repoval, template, registryConfigs, repo, idReader)...) } } - return &mergedConfig, nil + return output, nil } -// HaveMatchRegistry checks if trust settings for the registry have been configured in yaml file -func HaveMatchRegistry(key string, registryConfigs *RegistryConfiguration) *RegistryNamespace { - searchKey := key - if !strings.Contains(searchKey, "/") { - val, exists := registryConfigs.Docker[searchKey] - if exists { - return &val - } - } - for range strings.Split(key, "/") { - val, exists := registryConfigs.Docker[searchKey] - if exists { - return &val - } - if strings.Contains(searchKey, "/") { - searchKey = searchKey[:strings.LastIndex(searchKey, "/")] +// descriptionsOfPolicyRequirements turns reqs into user-readable policy entries, with Transport/Name/Reponame coming from template, potentially looking up scope (which may be "") in registryConfigs. +func descriptionsOfPolicyRequirements(reqs []repoContent, template Policy, registryConfigs *registryConfiguration, scope string, idReader gpgIDReader) []*Policy { + res := []*Policy{} + + var lookasidePath string + registryNamespace := registriesDConfigurationForScope(registryConfigs, scope) + if registryNamespace != nil { + if registryNamespace.Lookaside != "" { + lookasidePath = registryNamespace.Lookaside + } else { // incl. registryNamespace.SigStore == "" + lookasidePath = registryNamespace.SigStore } } - return registryConfigs.DefaultDocker -} - -// CreateTmpFile creates a temp file under dir and writes the content into it -func CreateTmpFile(dir, pattern string, content []byte) (string, error) { - tmpfile, err := ioutil.TempFile(dir, pattern) - if err != nil { - return "", err - } - defer tmpfile.Close() - - if _, err := tmpfile.Write(content); err != nil { - return "", err - } - return tmpfile.Name(), nil -} - -// GetGPGIdFromKeyPath return user keyring from key path -func GetGPGIdFromKeyPath(path string) []string { - cmd := exec.Command("gpg2", "--with-colons", path) - results, err := cmd.Output() - if err != nil { - logrus.Errorf("Getting key identity: %s", err) - return nil - } - return parseUids(results) -} -// GetGPGIdFromKeyData return user keyring from keydata -func GetGPGIdFromKeyData(key string) []string { - decodeKey, err := base64.StdEncoding.DecodeString(key) - if err != nil { - logrus.Errorf("%s, error decoding key data", err) - return nil - } - tmpfileName, err := CreateTmpFile("", "", decodeKey) - if err != nil { - logrus.Errorf("Creating key date temp file %s", err) - } - defer os.Remove(tmpfileName) - return GetGPGIdFromKeyPath(tmpfileName) -} + for _, repoele := range reqs { + entry := template + entry.Type = trustTypeDescription(repoele.Type) -func parseUids(colonDelimitKeys []byte) []string { - var parseduids []string - scanner := bufio.NewScanner(bytes.NewReader(colonDelimitKeys)) - for scanner.Scan() { - line := scanner.Text() - if strings.HasPrefix(line, "uid:") || strings.HasPrefix(line, "pub:") { - uid := strings.Split(line, ":")[9] - if uid == "" { - continue + var gpgIDString string + switch repoele.Type { + case "signedBy": + uids := []string{} + if len(repoele.KeyPath) > 0 { + uids = append(uids, idReader(repoele.KeyPath)...) } - parseduid := uid - if strings.Contains(uid, "<") && strings.Contains(uid, ">") { - parseduid = strings.SplitN(strings.SplitAfterN(uid, "<", 2)[1], ">", 2)[0] + for _, path := range repoele.KeyPaths { + uids = append(uids, idReader(path)...) } - parseduids = append(parseduids, parseduid) + if len(repoele.KeyData) > 0 { + uids = append(uids, getGPGIdFromKeyData(idReader, repoele.KeyData)...) + } + gpgIDString = strings.Join(uids, ", ") + + case "sigstoreSigned": + gpgIDString = "N/A" // We could potentially return key fingerprints here, but they would not be _GPG_ fingerprints. } + entry.GPGId = gpgIDString + entry.SignatureStore = lookasidePath // We do this even for sigstoreSigned and things like type: reject, to show that the sigstore is being read. + res = append(res, &entry) } - return parseduids -} -// GetPolicy parse policy.json into PolicyContent struct -func GetPolicy(policyPath string) (PolicyContent, error) { - var policyContentStruct PolicyContent - policyContent, err := ioutil.ReadFile(policyPath) - if err != nil { - return policyContentStruct, fmt.Errorf("unable to read policy file: %w", err) - } - if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { - return policyContentStruct, fmt.Errorf("could not parse trust policies from %s: %w", policyPath, err) - } - return policyContentStruct, nil + return res } diff --git a/pkg/trust/trust_test.go b/pkg/trust/trust_test.go new file mode 100644 index 000000000..22b780fc9 --- /dev/null +++ b/pkg/trust/trust_test.go @@ -0,0 +1,376 @@ +package trust + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/containers/image/v5/signature" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPolicyDescription(t *testing.T) { + tempDir := t.TempDir() + policyPath := filepath.Join(tempDir, "policy.json") + + // Override getGPGIdFromKeyPath because we don't want to bother with (and spend the unit-test time on) generating valid GPG keys, and running the real GPG binary. + // Instead of reading the files at all, just expect file names like /id1,id2,...,idN.pub + idReader := func(keyPath string) []string { + require.True(t, strings.HasPrefix(keyPath, "/")) + require.True(t, strings.HasSuffix(keyPath, ".pub")) + return strings.Split(keyPath[1:len(keyPath)-4], ",") + } + + for _, c := range []struct { + policy *signature.Policy + expected []*Policy + }{ + { + &signature.Policy{ + Default: signature.PolicyRequirements{ + signature.NewPRReject(), + }, + Transports: map[string]signature.PolicyTransportScopes{ + "docker": { + "quay.io/accepted": { + signature.NewPRInsecureAcceptAnything(), + }, + "registry.redhat.io": { + xNewPRSignedByKeyPath(t, "/redhat.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + "registry.access.redhat.com": { + xNewPRSignedByKeyPaths(t, []string{"/redhat.pub", "/redhat-beta.pub"}, signature.NewPRMMatchRepoDigestOrExact()), + }, + "quay.io/multi-signed": { + xNewPRSignedByKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSignedByKeyPath(t, "/2,3.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + "quay.io/sigstore-signed": { + xNewPRSigstoreSignedKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSigstoreSignedKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + }, + }, + }, + []*Policy{ + { + Transport: "all", + Name: "* (default)", + RepoName: "default", + Type: "reject", + }, + { + Transport: "repository", + Name: "quay.io/accepted", + RepoName: "quay.io/accepted", + Type: "accept", + }, + { + Transport: "repository", + Name: "quay.io/multi-signed", + RepoName: "quay.io/multi-signed", + Type: "signed", + SignatureStore: "https://quay.example.com/sigstore", + GPGId: "1", + }, + { + Transport: "repository", + Name: "quay.io/multi-signed", + RepoName: "quay.io/multi-signed", + Type: "signed", + SignatureStore: "https://quay.example.com/sigstore", + GPGId: "2, 3", + }, + { + Transport: "repository", + Name: "quay.io/sigstore-signed", + RepoName: "quay.io/sigstore-signed", + Type: "sigstoreSigned", + SignatureStore: "", + GPGId: "N/A", + }, + { + Transport: "repository", + Name: "quay.io/sigstore-signed", + RepoName: "quay.io/sigstore-signed", + Type: "sigstoreSigned", + SignatureStore: "", + GPGId: "N/A", + }, + { + Transport: "repository", + Name: "registry.access.redhat.com", + RepoName: "registry.access.redhat.com", + Type: "signed", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "redhat, redhat-beta", + }, { + Transport: "repository", + Name: "registry.redhat.io", + RepoName: "registry.redhat.io", + Type: "signed", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "redhat", + }, + }, + }, + { + &signature.Policy{ + Default: signature.PolicyRequirements{ + xNewPRSignedByKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSignedByKeyPath(t, "/2,3.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + }, + []*Policy{ + { + Transport: "all", + Name: "* (default)", + RepoName: "default", + Type: "signed", + SignatureStore: "", + GPGId: "1", + }, + { + Transport: "all", + Name: "* (default)", + RepoName: "default", + Type: "signed", + SignatureStore: "", + GPGId: "2, 3", + }, + }, + }, + } { + policyJSON, err := json.Marshal(c.policy) + require.NoError(t, err) + err = os.WriteFile(policyPath, policyJSON, 0600) + require.NoError(t, err) + + res, err := policyDescriptionWithGPGIDReader(policyPath, "./testdata", idReader) + require.NoError(t, err) + assert.Equal(t, c.expected, res) + } +} + +func TestDescriptionsOfPolicyRequirements(t *testing.T) { + // Override getGPGIdFromKeyPath because we don't want to bother with (and spend the unit-test time on) generating valid GPG keys, and running the real GPG binary. + // Instead of reading the files at all, just expect file names like /id1,id2,...,idN.pub + idReader := func(keyPath string) []string { + require.True(t, strings.HasPrefix(keyPath, "/")) + require.True(t, strings.HasSuffix(keyPath, ".pub")) + return strings.Split(keyPath[1:len(keyPath)-4], ",") + } + + template := Policy{ + Transport: "transport", + Name: "name", + RepoName: "repoName", + } + registryConfigs, err := loadAndMergeConfig("./testdata") + require.NoError(t, err) + + for _, c := range []struct { + scope string + reqs signature.PolicyRequirements + expected []*Policy + }{ + { + "", + signature.PolicyRequirements{ + signature.NewPRReject(), + }, + []*Policy{ + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "reject", + }, + }, + }, + { + "quay.io/accepted", + signature.PolicyRequirements{ + signature.NewPRInsecureAcceptAnything(), + }, + []*Policy{ + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "accept", + }, + }, + }, + { + "registry.redhat.io", + signature.PolicyRequirements{ + xNewPRSignedByKeyPath(t, "/redhat.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + []*Policy{ + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "signed", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "redhat", + }, + }, + }, + { + "registry.access.redhat.com", + signature.PolicyRequirements{ + xNewPRSignedByKeyPaths(t, []string{"/redhat.pub", "/redhat-beta.pub"}, signature.NewPRMMatchRepoDigestOrExact()), + }, + []*Policy{ + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "signed", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "redhat, redhat-beta", + }, + }, + }, + { + "quay.io/multi-signed", + signature.PolicyRequirements{ + xNewPRSignedByKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSignedByKeyPath(t, "/2,3.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + []*Policy{ + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "signed", + SignatureStore: "https://quay.example.com/sigstore", + GPGId: "1", + }, + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "signed", + SignatureStore: "https://quay.example.com/sigstore", + GPGId: "2, 3", + }, + }, + }, { + "quay.io/sigstore-signed", + signature.PolicyRequirements{ + xNewPRSigstoreSignedKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSigstoreSignedKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + []*Policy{ + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "sigstoreSigned", + SignatureStore: "", + GPGId: "N/A", + }, + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "sigstoreSigned", + SignatureStore: "", + GPGId: "N/A", + }, + }, + }, + { // Multiple kinds of requirements are represented individually. + "registry.redhat.io", + signature.PolicyRequirements{ + signature.NewPRReject(), + signature.NewPRInsecureAcceptAnything(), + xNewPRSignedByKeyPath(t, "/redhat.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSignedByKeyPaths(t, []string{"/redhat.pub", "/redhat-beta.pub"}, signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSignedByKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSignedByKeyPath(t, "/2,3.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSigstoreSignedKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), + xNewPRSigstoreSignedKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()), + }, + []*Policy{ + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + Type: "reject", + }, + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + Type: "accept", + }, + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "signed", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "redhat", + }, + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "signed", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "redhat, redhat-beta", + }, + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "signed", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "1", + }, + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "signed", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "2, 3", + }, + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "sigstoreSigned", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "N/A", + }, + { + Transport: "transport", + Name: "name", + RepoName: "repoName", + Type: "sigstoreSigned", + SignatureStore: "https://registry.redhat.io/containers/sigstore", + GPGId: "N/A", + }, + }, + }, + } { + reqsJSON, err := json.Marshal(c.reqs) + require.NoError(t, err) + var parsedRegs []repoContent + err = json.Unmarshal(reqsJSON, &parsedRegs) + require.NoError(t, err) + + res := descriptionsOfPolicyRequirements(parsedRegs, template, registryConfigs, c.scope, idReader) + assert.Equal(t, c.expected, res) + } +} diff --git a/podman.spec.rpkg b/podman.spec.rpkg index f27b31108..2962fe91e 100644 --- a/podman.spec.rpkg +++ b/podman.spec.rpkg @@ -233,6 +233,7 @@ done %{_userunitdir}/%{name}-restart.service %{_userunitdir}/%{name}-kube@.service %{_tmpfilesdir}/%{name}.conf +%{_user_tmpfilesdir}/%{name}-docker.conf %if 0%{?fedora} >= 36 %{_modulesloaddir}/%{name}-iptables.conf %endif diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at index f03b95786..86ee2a1f5 100644 --- a/test/apiv2/10-images.at +++ b/test/apiv2/10-images.at @@ -203,7 +203,7 @@ t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 200 # Libpod: allow building from url: https://github.com/alpinelinux/docker-alpine.git and must ignore any provided tar t POST "libpod/build?remote=https%3A%2F%2Fgithub.com%2Falpinelinux%2Fdocker-alpine.git" $CONTAINERFILE_TAR 200 \ - .stream~"STEP 1/5: FROM alpine:3.14" + .stream~"STEP 1/5: FROM alpine:" # Build api response header must contain Content-type: application/json t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 200 @@ -239,4 +239,23 @@ fi cleanBuildTest +# compat API vs libpod API event differences: +# on image removal, libpod produces 'remove' events. +# compat produces 'delete' events. +podman image build -t test:test -<<EOF +from $IMAGE +EOF + +START=$(date +%s) + +t DELETE libpod/images/test:test 200 +# HACK HACK HACK There is a race around events being added to the journal +# This sleep seems to avoid the race. +# If it fails and begins to flake, investigate a retry loop. +sleep 1 +t GET "libpod/events?stream=false&since=$START" 200 \ + 'select(.status | contains("remove")).Action=remove' +t GET "events?stream=false&since=$START" 200 \ + 'select(.status | contains("delete")).Action=delete' + # vim: filetype=sh diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at index 498d67569..eb58b8377 100644 --- a/test/apiv2/12-imagesMore.at +++ b/test/apiv2/12-imagesMore.at @@ -3,9 +3,6 @@ # Tests for more image-related endpoints # -red='\e[31m' -nc='\e[0m' - start_registry podman pull -q $IMAGE @@ -63,7 +60,9 @@ podman pull -q $IMAGE # test podman image SCP # ssh needs to work so we can validate that the failure is past argument parsing -podman system connection add --default test ssh://$USER@localhost/run/user/$UID/podman/podman.sock +conn=apiv2test-temp-connection +podman system connection add --default $conn \ + ssh://$USER@localhost/run/user/$UID/podman/podman.sock # should fail but need to check the output... # status 125 here means that the save/load fails due to # cirrus weirdness with exec.Command. All of the args have been parsed successfully. @@ -72,4 +71,7 @@ t POST "libpod/images/scp/$IMAGE?destination=QA::" 500 \ t DELETE libpod/images/$IMAGE 200 \ .ExitCode=0 +# Clean up +podman system connection rm $conn + stop_registry diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at index 29b641853..253bb2e45 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -531,21 +531,21 @@ sleep 3 t GET containers/status-test/json 200 .State.Status="exited" # test podman generate spec as input for the api -podman create --name=specgen alpine_labels +cname=specgen$(random_string 10) +podman create --name=$cname $IMAGE TMPD=$(mktemp -d podman-apiv2-test.build.XXXXXXXX) -podman generate spec -f ${TMPD}/input.txt -c specgen +podman generate spec -f ${TMPD}/myspec.json -c $cname -curl -XPOST -o ${TMPD}/response.txt --dump-header ${TMPD}/headers.txt -H content-type:application/json http://$HOST:$PORT/v4.0.0/libpod/containers/create -d "@${TMPD}/input.txt" +# Create a container based on that spec +t POST libpod/containers/create ${TMPD}/myspec.json 201 \ + .Id~[0-9a-f]\\{64\\} -if ! grep -q '201 Created' "${TMPD}/headers.txt"; then - cat "${TMPD}/headers.txt" - cat "${TMPD}/response.txt" - echo -e "${red}NOK: container create failed" - rm -rf $TMPD - exit 1 -fi +# Verify +t GET libpod/containers/$cname/json 200 \ + .ImageName=$IMAGE \ + .Name=$cname rm -rf $TMPD diff --git a/test/apiv2/23-containersArchive.at b/test/apiv2/23-containersArchive.at index c55164780..c1b936e3a 100644 --- a/test/apiv2/23-containersArchive.at +++ b/test/apiv2/23-containersArchive.at @@ -3,22 +3,31 @@ # test more container-related endpoints # -red='\e[31m' -nc='\e[0m' - podman pull $IMAGE &>/dev/null # Ensure clean slate podman rm -a -f &>/dev/null -CTR="ArchiveTestingCtr" +CTR="ArchiveTestingCtr$(random_string 5)" TMPD=$(mktemp -d podman-apiv2-test.archive.XXXXXXXX) HELLO_TAR="${TMPD}/hello.tar" -echo "Hello" > $TMPD/hello.txt +HELLO_S="Hello_$(random_string 8)" +echo "$HELLO_S" > $TMPD/hello.txt tar --owner=1042 --group=1043 --format=posix -C $TMPD -cvf ${HELLO_TAR} hello.txt &> /dev/null +# Start a container, and wait for it. (I know we don't actually do anything +# if we time out. If we do, subsequent tests will fail. I just want to avoid +# a race between container-start and tests-start) podman run -d --name "${CTR}" "${IMAGE}" top +timeout=10 +while [[ $timeout -gt 0 ]]; do + if podman container exists "${CTR}"; then + break + fi + timeout=$((timeout - 1)) + sleep 1 +done function cleanUpArchiveTest() { podman container stop "${CTR}" &> /dev/null @@ -30,63 +39,47 @@ t HEAD "containers/nonExistentCtr/archive?path=%2F" 404 t HEAD "containers/${CTR}/archive?path=%2Fnon%2Fexistent%2Fpath" 404 t HEAD "containers/${CTR}/archive?path=%2Fetc%2Fpasswd" 200 -curl "http://$HOST:$PORT/containers/${CTR}/archive?path=%2Ftmp%2F" \ - -X PUT \ - -H "Content-Type: application/x-tar" \ - --upload-file "${HELLO_TAR}" &> /dev/null +# Send tarfile to container... +t PUT "/containers/${CTR}/archive?path=%2Ftmp%2F" ${HELLO_TAR} 200 '' -if ! podman exec -it "${CTR}" "grep" "Hello" "/tmp/hello.txt" &> /dev/null ; then - echo -e "${red}NOK: The hello.txt file has not been uploaded.${nc}" 1>&2; - cleanUpArchiveTest - exit 1 -fi +# ...and 'exec cat file' to confirm that it got extracted into place. +cat >$TMPD/exec.json <<EOF +{ "AttachStdout":true,"Cmd":["cat","/tmp/hello.txt"]} +EOF +t POST containers/${CTR}/exec $TMPD/exec.json 201 .Id~[0-9a-f]\\{64\\} +eid=$(jq -r '.Id' <<<"$output") +# The 017 is the byte length +t POST exec/$eid/start 200 $'\001\017'$HELLO_S +# Now fetch hello.txt back as a tarfile t HEAD "containers/${CTR}/archive?path=%2Ftmp%2Fhello.txt" 200 +t GET "containers/${CTR}/archive?path=%2Ftmp%2Fhello.txt" 200 -curl "http://$HOST:$PORT/containers/${CTR}/archive?path=%2Ftmp%2Fhello.txt" \ - --dump-header "${TMPD}/headers.txt" \ - -o "${TMPD}/body.tar" \ - -X GET &> /dev/null - -PATH_STAT="$(grep X-Docker-Container-Path-Stat "${TMPD}/headers.txt" | cut -d " " -f 2 | base64 -d --ignore-garbage)" - -ARCHIVE_TEST_ERROR="" +# Check important-looking header +PATH_STAT="$(grep X-Docker-Container-Path-Stat "$WORKDIR/curl.headers.out" | cut -d " " -f 2 | base64 -d --ignore-garbage)" -if [ "$(echo "${PATH_STAT}" | jq ".name")" != '"hello.txt"' ]; then - echo -e "${red}NOK: Wrong name in X-Docker-Container-Path-Stat header.${nc}" 1>&2; - ARCHIVE_TEST_ERROR="1" -fi +is "$(jq -r .name <<<$PATH_STAT)" "hello.txt" "Docker-Path-Stat .name" +is "$(jq -r .size <<<$PATH_STAT)" "15" "Docker-Path-Stat .size" -if [ "$(echo "${PATH_STAT}" | jq ".size")" != "6" ]; then - echo -e "${red}NOK: Wrong size in X-Docker-Container-Path-Stat header.${nc}" 1>&2; - ARCHIVE_TEST_ERROR="1" -fi +# Check filename and its contents +tar_tf=$(tar tf $WORKDIR/curl.result.out) +is "$tar_tf" "hello.txt" "fetched tarball: file name" -if ! tar -tf "${TMPD}/body.tar" | grep "hello.txt" &> /dev/null; then - echo -e "${red}NOK: Body doesn't contain expected file.${nc}" 1>&2; - ARCHIVE_TEST_ERROR="1" -fi +tar_contents=$(tar xf $WORKDIR/curl.result.out --to-stdout) +is "$tar_contents" "$HELLO_S" "fetched tarball: file contents" -if [ "$(tar -xf "${TMPD}/body.tar" hello.txt --to-stdout)" != "Hello" ]; then - echo -e "${red}NOK: Content of file doesn't match.${nc}" 1>&2; - ARCHIVE_TEST_ERROR="1" -fi +# TODO: uid/gid should be also preserved on way back (GET request) +# right now it ends up as 0/0 instead of 1042/1043 +tar_uidgid=$(tar tvf $WORKDIR/curl.result.out | awk '{print $2}') +is "$tar_uidgid" "0/0" "fetched tarball: file uid/gid" -# test if uid/gid was set correctly in the server -uidngid=$($PODMAN_BIN --root $WORKDIR/server_root exec "${CTR}" stat -c "%u:%g" "/tmp/hello.txt") -if [[ "${uidngid}" != "1042:1043" ]]; then - echo -e "${red}NOK: UID/GID of the file doesn't match.${nc}" 1>&2; - ARCHIVE_TEST_ERROR="1" -fi +# test if uid/gid was set correctly in the server. Again, via exec. +cat >$TMPD/exec.json <<EOF +{ "AttachStdout":true,"Cmd":["stat","-c","%u:%g","/tmp/hello.txt"]} +EOF -# TODO: uid/gid should be also preserved on way back (GET request) -# right now it ends up as root:root instead of 1042:1043 -#if [[ "$(tar -tvf "${TMPD}/body.tar")" != *"1042/1043"* ]]; then -# echo -e "${red}NOK: UID/GID of the file doesn't match.${nc}" 1>&2; -# ARCHIVE_TEST_ERROR="1" -#fi +t POST containers/${CTR}/exec $TMPD/exec.json 201 .Id~[0-9a-f]\\{64\\} +eid=$(jq -r '.Id' <<<"$output") +t POST exec/$eid/start 200 $'\001\012'1042:1043 cleanUpArchiveTest -if [[ "${ARCHIVE_TEST_ERROR}" ]] ; then - exit 1; -fi diff --git a/test/apiv2/26-containersWait.at b/test/apiv2/26-containersWait.at index 55bcd4592..41938d567 100644 --- a/test/apiv2/26-containersWait.at +++ b/test/apiv2/26-containersWait.at @@ -3,9 +3,6 @@ # test more container-related endpoints # -red='\e[31m' -nc='\e[0m' - podman pull "${IMAGE}" &>/dev/null # Ensure clean slate @@ -21,29 +18,29 @@ t POST "containers/${CTR}/wait?condition=non-existent-cond" 400 t POST "containers/${CTR}/wait?condition=not-running" 200 +# Test waiting for EXIT (need to start a background trigger first) +(sleep 2;podman start "${CTR}") & +child_pid=$! + +# This will block until the background job completes t POST "containers/${CTR}/wait?condition=next-exit" 200 \ .StatusCode=0 \ - .Error=null & -child_pid=$! -podman start "${CTR}" + .Error=null wait "${child_pid}" - -# check if headers are sent in advance before body -WAIT_TEST_ERROR="" -curl -I -X POST "http://$HOST:$PORT/containers/${CTR}/wait?condition=next-exit" &> "/dev/null" & -child_pid=$! -sleep 0.5 -if kill -2 "${child_pid}" 2> "/dev/null"; then - echo -e "${red}NOK: Failed to get response headers immediately.${nc}" 1>&2; - WAIT_TEST_ERROR="1" +# Test that headers are sent before body. (We should actually never get a body) +APIV2_TEST_EXPECT_TIMEOUT=2 t POST "containers/${CTR}/wait?condition=next-exit" 999 +like "$(<$WORKDIR/curl.headers.out)" ".*HTTP.* 200 OK.*" \ + "Received headers from /wait" +if [[ -e $WORKDIR/curl.result.out ]]; then + _show_ok 0 "UNEXPECTED: curl on /wait returned results" fi -t POST "containers/${CTR}/wait?condition=removed" 200 & +# Test waiting for REMOVE. Like above, start a background trigger. +(sleep 2;podman container rm "${CTR}") & child_pid=$! -podman container rm "${CTR}" -wait "${child_pid}" -if [[ "${WAIT_TEST_ERROR}" ]] ; then - exit 1; -fi +t POST "containers/${CTR}/wait?condition=removed" 200 \ + .StatusCode=0 \ + .Error=null +wait "${child_pid}" diff --git a/test/apiv2/40-pods.at b/test/apiv2/40-pods.at index d21b3d1a9..0e0f1cb18 100644 --- a/test/apiv2/40-pods.at +++ b/test/apiv2/40-pods.at @@ -134,23 +134,17 @@ t GET libpod/pods/json?filters='{"label":["testl' 400 \ t DELETE libpod/pods/foo 200 t DELETE "libpod/pods/foo (pod has already been deleted)" 404 -t_timeout 5 GET "libpod/pods/stats?stream=true&delay=1" 200 +# Expect this to time out +APIV2_TEST_EXPECT_TIMEOUT=5 t GET "libpod/pods/stats?stream=true&delay=1" 999 podman pod create --name=specgen TMPD=$(mktemp -d podman-apiv2-test.build.XXXXXXXX) -podman generate spec -f ${TMPD}/input.txt -c specgen +podman generate spec -f ${TMPD}/myspec.json -c specgen -curl -XPOST -o ${TMPD}/response.txt --dump-header ${TMPD}/headers.txt -H content-type:application/json http://$HOST:$PORT/v4.0.0/libpod/pods/create -d "@${TMPD}/input.txt" - -if ! grep -q '201 Created' "${TMPD}/headers.txt"; then - cat "${TMPD}/headers.txt" - cat "${TMPD}/response.txt" - echo -e "${red}NOK: pod create failed" - rm -rf $TMPD - exit 1 -fi +t POST libpod/pods/create ${TMPD}/myspec.json 201 \ + .Id~[0-9a-f]\\{64\\} rm -rf $TMPD diff --git a/test/apiv2/70-short-names.at b/test/apiv2/70-short-names.at index 643cbc25b..952dd2ad1 100644 --- a/test/apiv2/70-short-names.at +++ b/test/apiv2/70-short-names.at @@ -33,18 +33,8 @@ RUN touch /foo EOF tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_TAR} containerfile &> /dev/null - curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \ - -H "content-type: application/x-tar" \ - --dump-header "${TMPD}/headers.txt" \ - -o "${TMPD}/response.txt" \ - "http://$HOST:$PORT/build?dockerfile=containerfile&t=$tag" &> /dev/null - - if ! grep -q '200 OK' "${TMPD}/headers.txt"; then - cat "${TMPD}/headers.txt" - cat "${TMPD}/response.txt" - echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/x-tar)" - exit 1 - fi + t POST "/build?dockerfile=containerfile&t=$tag" $CONTAINERFILE_TAR 200 \ + .stream~".*Successfully tagged .*" rm -rf $TMPD t DELETE "images/$fqn" 200 diff --git a/test/apiv2/README.md b/test/apiv2/README.md index 63d1f5b13..712124d1b 100644 --- a/test/apiv2/README.md +++ b/test/apiv2/README.md @@ -46,6 +46,9 @@ with POST parameters if present, and compares return status and | +----------- POST params +--------------------------------- note the missing slash +Never, ever, ever, seriously _EVER_ `exit` from a test. Just don't. +That skips cleanup, and leaves the system in a broken state. + Notes: * If the endpoint has a leading slash (`/_ping`), `t` leaves it unchanged. @@ -61,14 +64,19 @@ of POST parameters in the form 'key=value', separated by spaces: `t` will convert the param list to JSON form for passing to the server. A numeric status code terminates processing of POST parameters. ** As a special case, when one POST argument is a string ending in `.tar`, -`t` will invoke `curl` with `--data-binary @PATH` and -set `Content-type: application/x-tar`. This is useful for `build` endpoints. +`.yaml`, or `.json`, `t` will invoke `curl` with `--data-binary @PATH` and +set `Content-type` as appropriate. This is useful for `build` endpoints. (To override `Content-type`, simply pass along an extra string argument matching `application/*`): t POST myentrypoint /mytmpdir/myfile.tar application/foo 400 +** Like above, when using PUT, `t` does `--upload-time` instead of +`--data-binary` * The final arguments are one or more expected string results. If an argument starts with a dot, `t` will invoke `jq` on the output to fetch that field, and will compare it to the right-hand side of the argument. If the separator is `=` (equals), `t` will require an exact match; if `~` (tilde), `t` will use `expr` to compare. + +* If your test expects `curl` to time out: + APIV2_TEST_EXPECT_TIMEOUT=5 t POST /foo 999 diff --git a/test/apiv2/python/rest_api/fixtures/api_testcase.py b/test/apiv2/python/rest_api/fixtures/api_testcase.py index f47136555..edb34b31e 100644 --- a/test/apiv2/python/rest_api/fixtures/api_testcase.py +++ b/test/apiv2/python/rest_api/fixtures/api_testcase.py @@ -20,7 +20,7 @@ class APITestCase(unittest.TestCase): APITestCase.podman = Podman() APITestCase.service = APITestCase.podman.open( - "system", "service", "tcp:localhost:8080", "--time=0" + "system", "service", "tcp://localhost:8080", "--time=0" ) # give the service some time to be ready... time.sleep(2) diff --git a/test/apiv2/python/rest_api/v1_test_rest_v1_0_0.py b/test/apiv2/python/rest_api/v1_test_rest_v1_0_0.py index 905c29683..2274f25bf 100644 --- a/test/apiv2/python/rest_api/v1_test_rest_v1_0_0.py +++ b/test/apiv2/python/rest_api/v1_test_rest_v1_0_0.py @@ -63,7 +63,7 @@ class TestApi(unittest.TestCase): podman(), "system", "service", - "tcp:localhost:8080", + "tcp://localhost:8080", "--log-level=debug", "--time=0", ], diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2 index 0c3c6e672..aca7db0dd 100755 --- a/test/apiv2/test-apiv2 +++ b/test/apiv2/test-apiv2 @@ -23,8 +23,6 @@ REGISTRY_IMAGE="${PODMAN_TEST_IMAGE_REGISTRY}/${PODMAN_TEST_IMAGE_USER}/registry ############################################################################### # BEGIN setup -USER=$PODMAN_ROOTLESS_USER -UID=$PODMAN_ROOTLESS_UID TMPDIR=${TMPDIR:-/tmp} WORKDIR=$(mktemp --tmpdir -d $ME.tmp.XXXXXX) @@ -56,9 +54,6 @@ fi # Path to podman binary PODMAN_BIN=${PODMAN:-${CONTAINERS_HELPER_BINARY_DIR}/podman} -# Timeout for streamed responses -CURL_TIMEOUT=0 - # Cleanup handlers clean_up_server() { if [ -n "$service_pid" ]; then @@ -135,7 +130,8 @@ function like() { ############## function _show_ok() { local ok=$1 - local testname=$2 + # Exec tests include control characters; filter them out + local testname=$(tr -d \\012 <<<"$2"|cat -vT) # If output is a tty, colorize pass/fail local red= @@ -220,21 +216,6 @@ function jsonify() { } ####### -# t_timeout # Timeout wrapper for test helper -####### -function t_timeout() { - CURL_TIMEOUT=$1; shift - local min_runtime=$((CURL_TIMEOUT - 1)) - start=`date +%s` - t $@ - local end=`date +%s` - local runtime=$((end-start)) - if ! [[ "$runtime" -ge "$min_runtime" ]]; then - die "Error: Streaming time should be greater or equal to '$min_runtime'" - fi -} - -####### # t # Main test helper ####### function t() { @@ -245,23 +226,28 @@ function t() { local testname="$method $path" - if [[ $CURL_TIMEOUT != 0 ]]; then - local c_timeout=$CURL_TIMEOUT - curl_args+=("-m $CURL_TIMEOUT") - CURL_TIMEOUT=0 # 'consume' timeout - fi # POST and PUT requests may be followed by one or more key=value pairs. # Slurp the command line until we see a 3-digit status code. if [[ $method = "POST" || $method == "PUT" || $method = "DELETE" ]]; then local -a post_args + + if [[ $method = "POST" ]]; then + function _add_curl_args() { curl_args+=(--data-binary @$1); } + else + function _add_curl_args() { curl_args+=(--upload-file $1); } + fi + for arg; do case "$arg" in *=*) post_args+=("$arg"); shift;; - *.tar) curl_args+=(--data-binary @$arg); + *.json) _add_curl_args $arg; + content_type="application/json"; + shift;; + *.tar) _add_curl_args $arg; content_type="application/x-tar"; shift;; - *.yaml) curl_args+=(--data-binary @$arg); + *.yaml) _add_curl_args $arg; shift;; application/*) content_type="$arg"; shift;; @@ -301,6 +287,11 @@ function t() { curl_args+=("--head") fi + # If this is set, we're *expecting* curl to time out + if [[ -n "$APIV2_TEST_EXPECT_TIMEOUT" ]]; then + curl_args+=("-m" $APIV2_TEST_EXPECT_TIMEOUT) + fi + local expected_code=$1; shift # Log every action we do @@ -316,8 +307,19 @@ function t() { --write-out '%{http_code}^%{content_type}^%{time_total}' \ -o $WORKDIR/curl.result.out "$url"); rc=$?; } || : + # Special case: this means we *expect and want* a timeout + if [[ -n "$APIV2_TEST_EXPECT_TIMEOUT" ]]; then + # Hardcoded. See curl(1) for list of exit codes + if [[ $rc -eq 28 ]]; then + _show_ok 1 "$testname: curl timed out (expected)" + else + _show_ok 0 "$testname: expected curl to time out; it did not" + fi + return + fi + # Any error from curl is instant bad news, from which we can't recover - if [[ $rc -ne 0 ]] && [[ $c_timeout -eq 0 ]]; then + if [[ $rc -ne 0 ]]; then die "curl failure ($rc) on $url - cannot continue" fi diff --git a/test/e2e/build/Containerfile.userns-auto b/test/e2e/build/Containerfile.userns-auto new file mode 100644 index 000000000..921610982 --- /dev/null +++ b/test/e2e/build/Containerfile.userns-auto @@ -0,0 +1,2 @@ +FROM alpine +RUN cat /proc/self/uid_map diff --git a/test/e2e/config/containers.conf b/test/e2e/config/containers.conf index c33f32ab4..94bb316b1 100644 --- a/test/e2e/config/containers.conf +++ b/test/e2e/config/containers.conf @@ -61,6 +61,8 @@ no_hosts=true network_cmd_options=["allow_host_loopback=true"] service_timeout=1234 +volume_plugin_timeout = 15 + # We need to ensure each test runs on a separate plugin instance... # For now, let's just make a bunch of plugin paths and have each test use one. [engine.volume_plugins] diff --git a/test/e2e/container_clone_test.go b/test/e2e/container_clone_test.go index 94ccd6ffe..1ba5de1a3 100644 --- a/test/e2e/container_clone_test.go +++ b/test/e2e/container_clone_test.go @@ -87,6 +87,7 @@ var _ = Describe("Podman container clone", func() { }) It("podman container clone resource limits override", func() { + SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1") create := podmanTest.Podman([]string{"create", "--cpus=5", ALPINE}) create.WaitWithDefaultTimeout() Expect(create).To(Exit(0)) @@ -292,4 +293,20 @@ var _ = Describe("Podman container clone", func() { Expect(ok).To(BeTrue()) }) + + It("podman container clone env test", func() { + session := podmanTest.Podman([]string{"run", "--name", "env_ctr", "-e", "ENV_TEST=123", ALPINE, "printenv", "ENV_TEST"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"container", "clone", "env_ctr"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"start", "-a", "env_ctr-clone"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).Should(ContainSubstring("123")) + + }) }) diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index 9679aad24..b35d0f3c5 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -438,6 +438,7 @@ var _ = Describe("Podman create", func() { }) It("podman create with -m 1000000 sets swap to 2000000", func() { + SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1") numMem := 1000000 ctrName := "testCtr" session := podmanTest.Podman([]string{"create", "-t", "-m", fmt.Sprintf("%db", numMem), "--name", ctrName, ALPINE, "/bin/sh"}) @@ -452,6 +453,7 @@ var _ = Describe("Podman create", func() { }) It("podman create --cpus 5 sets nanocpus", func() { + SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1") numCpus := 5 nanoCPUs := numCpus * 1000000000 ctrName := "testCtr" diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 142f32d19..e7ceaf2d2 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -490,6 +490,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman generate kube on pod with memory limit", func() { + SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1") podName := "testMemoryLimit" podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName}) podSession.WaitWithDefaultTimeout() @@ -515,6 +516,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman generate kube on pod with cpu limit", func() { + SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1") podName := "testCpuLimit" podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName}) podSession.WaitWithDefaultTimeout() diff --git a/test/e2e/generate_spec_test.go b/test/e2e/generate_spec_test.go index 57cd9546b..9188b5222 100644 --- a/test/e2e/generate_spec_test.go +++ b/test/e2e/generate_spec_test.go @@ -41,6 +41,7 @@ var _ = Describe("Podman generate spec", func() { }) It("podman generate spec basic usage", func() { + SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1") session := podmanTest.Podman([]string{"create", "--cpus", "5", "--name", "specgen", ALPINE}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -51,6 +52,7 @@ var _ = Describe("Podman generate spec", func() { }) It("podman generate spec file", func() { + SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1") session := podmanTest.Podman([]string{"create", "--cpus", "5", "--name", "specgen", ALPINE}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go index fd4e763f9..969f83b19 100644 --- a/test/e2e/healthcheck_run_test.go +++ b/test/e2e/healthcheck_run_test.go @@ -317,6 +317,12 @@ HEALTHCHECK CMD ls -l / 2>&1`, ALPINE) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + // Check if image inspect contains CMD-SHELL generated by healthcheck. + session = podmanTest.Podman([]string{"image", "inspect", "--format", "{{.Config.Healthcheck}}", "test"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("CMD-SHELL")) + run := podmanTest.Podman([]string{"run", "-dt", "--name", "hctest", "test", "ls"}) run.WaitWithDefaultTimeout() Expect(run).Should(Exit(0)) diff --git a/test/e2e/manifest_test.go b/test/e2e/manifest_test.go index ee954a1a4..60b72dcaa 100644 --- a/test/e2e/manifest_test.go +++ b/test/e2e/manifest_test.go @@ -46,9 +46,23 @@ var _ = Describe("Podman manifest", func() { processTestResult(f) }) It("create w/o image", func() { - session := podmanTest.Podman([]string{"manifest", "create", "foo"}) - session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) + for _, amend := range []string{"--amend", "-a"} { + session := podmanTest.Podman([]string{"manifest", "create", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"manifest", "create", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) + + session = podmanTest.Podman([]string{"manifest", "create", amend, "foo"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"manifest", "rm", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + } }) It("create w/ image", func() { @@ -336,6 +350,33 @@ var _ = Describe("Podman manifest", func() { Expect(foundZstdFile).To(BeTrue()) }) + It("push progress", func() { + SkipIfRemote("manifest push to dir not supported in remote mode") + + session := podmanTest.Podman([]string{"manifest", "create", "foo", imageList}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + dest := filepath.Join(podmanTest.TempDir, "pushed") + err := os.MkdirAll(dest, os.ModePerm) + Expect(err).To(BeNil()) + defer func() { + os.RemoveAll(dest) + }() + + session = podmanTest.Podman([]string{"push", "foo", "-q", "dir:" + dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.ErrorToString()).To(BeEmpty()) + + session = podmanTest.Podman([]string{"push", "foo", "dir:" + dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + output := session.ErrorToString() + Expect(output).To(ContainSubstring("Writing manifest list to image destination")) + Expect(output).To(ContainSubstring("Storing list signatures")) + }) + It("authenticated push", func() { registryOptions := &podmanRegistry.Options{ Image: "docker-archive:" + imageTarPath(REGISTRY_IMAGE), diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go index ece1b519d..30a5c6482 100644 --- a/test/e2e/network_connect_disconnect_test.go +++ b/test/e2e/network_connect_disconnect_test.go @@ -157,7 +157,7 @@ var _ = Describe("Podman network connect and disconnect", func() { Expect(con.ErrorToString()).To(ContainSubstring(`"slirp4netns" is not supported: invalid network mode`)) }) - It("podman connect on a container that already is connected to the network should error", func() { + It("podman connect on a container that already is connected to the network should error after init", func() { netName := "aliasTest" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", netName}) session.WaitWithDefaultTimeout() @@ -177,7 +177,15 @@ var _ = Describe("Podman network connect and disconnect", func() { con := podmanTest.Podman([]string{"network", "connect", netName, "test"}) con.WaitWithDefaultTimeout() - Expect(con).Should(ExitWithError()) + Expect(con).Should(Exit(0)) + + init := podmanTest.Podman([]string{"init", "test"}) + init.WaitWithDefaultTimeout() + Expect(init).Should(Exit(0)) + + con2 := podmanTest.Podman([]string{"network", "connect", netName, "test"}) + con2.WaitWithDefaultTimeout() + Expect(con2).Should(ExitWithError()) }) It("podman network connect", func() { diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go index 12f14fdc8..ba717f393 100644 --- a/test/e2e/pull_test.go +++ b/test/e2e/pull_test.go @@ -545,4 +545,18 @@ var _ = Describe("Podman pull", func() { Expect(data[0]).To(HaveField("Os", runtime.GOOS)) Expect(data[0]).To(HaveField("Architecture", "arm64")) }) + + It("podman pull progress", func() { + session := podmanTest.Podman([]string{"pull", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + output := session.ErrorToString() + Expect(output).To(ContainSubstring("Getting image source signatures")) + Expect(output).To(ContainSubstring("Copying blob ")) + + session = podmanTest.Podman([]string{"pull", "-q", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.ErrorToString()).To(BeEmpty()) + }) }) diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go index b3052623b..9df884292 100644 --- a/test/e2e/restart_test.go +++ b/test/e2e/restart_test.go @@ -1,6 +1,8 @@ package integration import ( + "fmt" + "io/ioutil" "os" "time" @@ -33,13 +35,13 @@ var _ = Describe("Podman restart", func() { }) - It("Podman restart bogus container", func() { + It("podman restart bogus container", func() { session := podmanTest.Podman([]string{"start", "123"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(125)) }) - It("Podman restart stopped container by name", func() { + It("podman restart stopped container by name", func() { _, exitCode, _ := podmanTest.RunLsContainer("test1") Expect(exitCode).To(Equal(0)) startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1"}) @@ -53,7 +55,7 @@ var _ = Describe("Podman restart", func() { Expect(restartTime.OutputToString()).To(Not(Equal(startTime.OutputToString()))) }) - It("Podman restart stopped container by ID", func() { + It("podman restart stopped container by ID", func() { session := podmanTest.Podman([]string{"create", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -73,7 +75,7 @@ var _ = Describe("Podman restart", func() { Expect(restartTime.OutputToString()).To(Not(Equal(startTime.OutputToString()))) }) - It("Podman restart running container", func() { + It("podman restart running container", func() { _ = podmanTest.RunTopContainer("test1") ok := WaitForContainer(podmanTest) Expect(ok).To(BeTrue()) @@ -88,7 +90,7 @@ var _ = Describe("Podman restart", func() { Expect(restartTime.OutputToString()).To(Not(Equal(startTime.OutputToString()))) }) - It("Podman container restart running container", func() { + It("podman container restart running container", func() { _ = podmanTest.RunTopContainer("test1") ok := WaitForContainer(podmanTest) Expect(ok).To(BeTrue()) @@ -103,7 +105,7 @@ var _ = Describe("Podman restart", func() { Expect(restartTime.OutputToString()).To(Not(Equal(startTime.OutputToString()))) }) - It("Podman restart multiple containers", func() { + It("podman restart multiple containers", func() { _, exitCode, _ := podmanTest.RunLsContainer("test1") Expect(exitCode).To(Equal(0)) @@ -121,7 +123,7 @@ var _ = Describe("Podman restart", func() { Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1]))) }) - It("Podman restart the latest container", func() { + It("podman restart the latest container", func() { _, exitCode, _ := podmanTest.RunLsContainer("test1") Expect(exitCode).To(Equal(0)) @@ -144,7 +146,7 @@ var _ = Describe("Podman restart", func() { Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1]))) }) - It("Podman restart non-stop container with short timeout", func() { + It("podman restart non-stop container with short timeout", func() { session := podmanTest.Podman([]string{"run", "-d", "--name", "test1", "--env", "STOPSIGNAL=SIGKILL", ALPINE, "sleep", "999"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -157,7 +159,7 @@ var _ = Describe("Podman restart", func() { Expect(timeSince).To(BeNumerically(">", 2*time.Second)) }) - It("Podman restart --all", func() { + It("podman restart --all", func() { _, exitCode, _ := podmanTest.RunLsContainer("test1") Expect(exitCode).To(Equal(0)) @@ -177,7 +179,7 @@ var _ = Describe("Podman restart", func() { Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1]))) }) - It("Podman restart --all --running", func() { + It("podman restart --all --running", func() { _, exitCode, _ := podmanTest.RunLsContainer("test1") Expect(exitCode).To(Equal(0)) @@ -197,7 +199,7 @@ var _ = Describe("Podman restart", func() { Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1]))) }) - It("Podman restart a container in a pod and hosts should not duplicated", func() { + It("podman restart a container in a pod and hosts should not duplicated", func() { // Fixes: https://github.com/containers/podman/issues/8921 _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}}) @@ -226,7 +228,7 @@ var _ = Describe("Podman restart", func() { Expect(beforeRestart.OutputToString()).To(Equal(afterRestart.OutputToString())) }) - It("podman restart --all", func() { + It("podman restart all stopped containers with --all", func() { session := podmanTest.RunTopContainer("") session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -247,4 +249,113 @@ var _ = Describe("Podman restart", func() { Expect(session).Should(Exit(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) }) + + It("podman restart --cidfile", func() { + tmpDir, err := ioutil.TempDir("", "") + Expect(err).To(BeNil()) + tmpFile := tmpDir + "cid" + + defer os.RemoveAll(tmpDir) + + session := podmanTest.Podman([]string{"create", "--cidfile", tmpFile, ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + cid := session.OutputToStringArray()[0] + + session = podmanTest.Podman([]string{"start", cid}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + result := podmanTest.Podman([]string{"restart", "--cidfile", tmpFile}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + output := result.OutputToString() + Expect(output).To(ContainSubstring(cid)) + }) + + It("podman restart multiple --cidfile", func() { + tmpDir, err := ioutil.TempDir("", "") + Expect(err).To(BeNil()) + tmpFile1 := tmpDir + "cid-1" + tmpFile2 := tmpDir + "cid-2" + + defer os.RemoveAll(tmpDir) + + session := podmanTest.Podman([]string{"run", "--cidfile", tmpFile1, "-d", ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + cid1 := session.OutputToStringArray()[0] + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + session = podmanTest.Podman([]string{"run", "--cidfile", tmpFile2, "-d", ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + cid2 := session.OutputToStringArray()[0] + Expect(podmanTest.NumberOfContainers()).To(Equal(2)) + + result := podmanTest.Podman([]string{"restart", "--cidfile", tmpFile1, "--cidfile", tmpFile2}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + output := result.OutputToString() + Expect(output).To(ContainSubstring(cid1)) + Expect(output).To(ContainSubstring(cid2)) + Expect(podmanTest.NumberOfContainers()).To(Equal(2)) + }) + + It("podman restart invalid --latest and --cidfile and --all", func() { + SkipIfRemote("--latest flag n/a") + result := podmanTest.Podman([]string{"restart", "--cidfile", "foobar", "--latest"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(125)) + Expect(result.ErrorToString()).To(ContainSubstring("cannot be used together")) + result = podmanTest.Podman([]string{"restart", "--cidfile", "foobar", "--all"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(125)) + Expect(result.ErrorToString()).To(ContainSubstring("cannot be used together")) + result = podmanTest.Podman([]string{"restart", "--cidfile", "foobar", "--all", "--latest"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(125)) + Expect(result.ErrorToString()).To(ContainSubstring("cannot be used together")) + result = podmanTest.Podman([]string{"restart", "--latest", "--all"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(125)) + Expect(result.ErrorToString()).To(ContainSubstring("cannot be used together")) + }) + + It("podman pause --filter", func() { + session1 := podmanTest.RunTopContainer("") + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + cid1 := session1.OutputToString() + + session1 = podmanTest.RunTopContainer("") + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + cid2 := session1.OutputToString() + + session1 = podmanTest.RunTopContainer("") + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + cid3 := session1.OutputToString() + shortCid3 := cid3[0:5] + + session1 = podmanTest.Podman([]string{"restart", cid1, "-f", "status=test"}) + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(125)) + + session1 = podmanTest.Podman([]string{"restart", "-a", "--filter", fmt.Sprintf("id=%swrongid", shortCid3)}) + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + Expect(session1.OutputToString()).To(HaveLen(0)) + + session1 = podmanTest.Podman([]string{"restart", "-a", "--filter", fmt.Sprintf("id=%s", shortCid3)}) + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + Expect(session1.OutputToString()).To(BeEquivalentTo(cid3)) + + session1 = podmanTest.Podman([]string{"restart", "-f", fmt.Sprintf("id=%s", cid2)}) + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + Expect(session1.OutputToString()).To(BeEquivalentTo(cid2)) + }) }) diff --git a/test/e2e/run_env_test.go b/test/e2e/run_env_test.go index bab52efc5..2b2d67f57 100644 --- a/test/e2e/run_env_test.go +++ b/test/e2e/run_env_test.go @@ -58,6 +58,13 @@ var _ = Describe("Podman run", func() { Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(ContainSubstring("/bin")) + // Verify environ keys with spaces do not blow up podman command + os.Setenv("FOO BAR", "BAZ") + session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "true"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + os.Unsetenv("FOO BAR") + os.Setenv("FOO", "BAR") session = podmanTest.Podman([]string{"run", "--rm", "--env", "FOO", ALPINE, "printenv", "FOO"}) session.WaitWithDefaultTimeout() @@ -82,6 +89,17 @@ var _ = Describe("Podman run", func() { Expect(session.OutputToString()).To(ContainSubstring("HOSTNAME")) }) + It("podman run with --env-merge", func() { + dockerfile := `FROM quay.io/libpod/alpine:latest +ENV hello=world +` + podmanTest.BuildImage(dockerfile, "test", "false") + session := podmanTest.Podman([]string{"run", "--rm", "--env-merge", "hello=${hello}-earth", "test", "env"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("world-earth")) + }) + It("podman run --env-host environment test", func() { env := append(os.Environ(), "FOO=BAR") session := podmanTest.PodmanAsUser([]string{"run", "--rm", "--env-host", ALPINE, "/bin/printenv", "FOO"}, 0, 0, "", env) diff --git a/test/e2e/run_memory_test.go b/test/e2e/run_memory_test.go index 083020f08..3f611040b 100644 --- a/test/e2e/run_memory_test.go +++ b/test/e2e/run_memory_test.go @@ -66,6 +66,24 @@ var _ = Describe("Podman run memory", func() { Expect(session.OutputToString()).To(Equal("41943040")) }) + It("podman run memory-swap test", func() { + var ( + session *PodmanSessionIntegration + expect string + ) + + if CGROUPSV2 { + session = podmanTest.Podman([]string{"run", "--memory=20m", "--memory-swap=30M", "--net=none", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/memory.swap.max"}) + expect = "10485760" + } else { + session = podmanTest.Podman([]string{"run", "--memory=20m", "--memory-swap=30M", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"}) + expect = "31457280" + } + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(Equal(expect)) + }) + for _, limit := range []string{"0", "15", "100"} { limit := limit // Keep this value in a proper scope testName := fmt.Sprintf("podman run memory-swappiness test(%s)", limit) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index c7a0b3f2b..1f6b6fa3d 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1235,9 +1235,8 @@ USER mail`, BB) }) It("podman run --mount type=bind,bind-nonrecursive", func() { - // crun: mount `/` to `/host`: Invalid argument - SkipIfRootless("FIXME: rootless users are not allowed to mount bind-nonrecursive (Could this be a Kernel bug?") - session := podmanTest.Podman([]string{"run", "--mount", "type=bind,bind-nonrecursive,slave,src=/,target=/host", fedoraMinimal, "findmnt", "-nR", "/host"}) + SkipIfRootless("FIXME: rootless users are not allowed to mount bind-nonrecursive") + session := podmanTest.Podman([]string{"run", "--mount", "type=bind,bind-nonrecursive,private,src=/sys,target=/host-sys", fedoraMinimal, "findmnt", "-nR", "/host-sys"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.OutputToStringArray()).To(HaveLen(1)) diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go index f247b2dac..62e512d3a 100644 --- a/test/e2e/run_userns_test.go +++ b/test/e2e/run_userns_test.go @@ -8,6 +8,7 @@ import ( "strings" . "github.com/containers/podman/v4/test/utils" + "github.com/containers/storage" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" @@ -42,6 +43,33 @@ var _ = Describe("Podman UserNS support", func() { }) + // Note: Lot of tests for build with --userns=auto are already there in buildah + // but they are skipped in podman CI because bud tests are executed in rootfull + // environment ( where mappings for the `containers` user is not present in /etc/subuid ) + // causing them to skip hence this is a redundant test for sanity to make sure + // we don't break this feature for podman-remote. + It("podman build with --userns=auto", func() { + u, err := user.Current() + Expect(err).To(BeNil()) + name := u.Name + if name == "root" { + name = "containers" + } + content, err := ioutil.ReadFile("/etc/subuid") + if err != nil { + Skip("cannot read /etc/subuid") + } + if !strings.Contains(string(content), name) { + Skip("cannot find mappings for the current user") + } + session := podmanTest.Podman([]string{"build", "-f", "build/Containerfile.userns-auto", "-t", "test", "--userns=auto"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + // `1024` is the default size or length of the range of user IDs + // that is mapped between the two user namespaces by --userns=auto. + Expect(session.OutputToString()).To(ContainSubstring(fmt.Sprintf("%d", storage.AutoUserNsMinSize))) + }) + It("podman uidmapping and gidmapping", func() { session := podmanTest.Podman([]string{"run", "--uidmap=0:100:5000", "--gidmap=0:200:5000", "alpine", "echo", "hello"}) session.WaitWithDefaultTimeout() @@ -157,6 +185,8 @@ var _ = Describe("Podman UserNS support", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) l := session.OutputToString() + // `1024` is the default size or length of the range of user IDs + // that is mapped between the two user namespaces by --userns=auto. Expect(l).To(ContainSubstring("1024")) m[l] = l } diff --git a/test/e2e/secret_test.go b/test/e2e/secret_test.go index ed328d84a..c6d5e6391 100644 --- a/test/e2e/secret_test.go +++ b/test/e2e/secret_test.go @@ -40,7 +40,7 @@ var _ = Describe("Podman secret", func() { err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755) Expect(err).To(BeNil()) - session := podmanTest.Podman([]string{"secret", "create", "--driver-opts", "opt1=val", "a", secretFilePath}) + session := podmanTest.Podman([]string{"secret", "create", "-d", "file", "--driver-opts", "opt1=val", "a", secretFilePath}) session.WaitWithDefaultTimeout() secrID := session.OutputToString() Expect(session).Should(Exit(0)) @@ -49,7 +49,7 @@ var _ = Describe("Podman secret", func() { inspect.WaitWithDefaultTimeout() Expect(inspect).Should(Exit(0)) Expect(inspect.OutputToString()).To(Equal(secrID)) - inspect = podmanTest.Podman([]string{"secret", "inspect", "--format", "{{.Spec.Driver.Options}}", secrID}) + inspect = podmanTest.Podman([]string{"secret", "inspect", "-f", "{{.Spec.Driver.Options}}", secrID}) inspect.WaitWithDefaultTimeout() Expect(inspect).Should(Exit(0)) Expect(inspect.OutputToString()).To(ContainSubstring("opt1:val")) @@ -145,6 +145,36 @@ var _ = Describe("Podman secret", func() { }) + It("podman secret ls --quiet", func() { + secretFilePath := filepath.Join(podmanTest.TempDir, "secret") + err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755) + Expect(err).To(BeNil()) + + secretName := "a" + + session := podmanTest.Podman([]string{"secret", "create", secretName, secretFilePath}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + secretID := session.OutputToString() + + list := podmanTest.Podman([]string{"secret", "ls", "-q"}) + list.WaitWithDefaultTimeout() + Expect(list).Should(Exit(0)) + Expect(list.OutputToString()).To(Equal(secretID)) + + list = podmanTest.Podman([]string{"secret", "ls", "--quiet"}) + list.WaitWithDefaultTimeout() + Expect(list).Should(Exit(0)) + Expect(list.OutputToString()).To(Equal(secretID)) + + // Prefer format over quiet + list = podmanTest.Podman([]string{"secret", "ls", "-q", "--format", "{{.Name}}"}) + list.WaitWithDefaultTimeout() + Expect(list).Should(Exit(0)) + Expect(list.OutputToString()).To(Equal(secretName)) + + }) + It("podman secret ls with filters", func() { secretFilePath := filepath.Join(podmanTest.TempDir, "secret") err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755) diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go index 3000a819f..981c00316 100644 --- a/test/e2e/stats_test.go +++ b/test/e2e/stats_test.go @@ -79,9 +79,10 @@ var _ = Describe("Podman stats", func() { session := podmanTest.RunTopContainer("") session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - session = podmanTest.Podman([]string{"stats", "--all", "--no-stream", "--format", "\"{{.ID}}\""}) + session = podmanTest.Podman([]string{"stats", "--all", "--no-trunc", "--no-stream", "--format", "\"{{.ID}}\""}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + Expect(len(session.OutputToStringArray()[0])).Should(BeEquivalentTo(66)) }) It("podman stats with GO template", func() { diff --git a/test/e2e/top_test.go b/test/e2e/top_test.go index 66bb887dc..5f51742d1 100644 --- a/test/e2e/top_test.go +++ b/test/e2e/top_test.go @@ -133,4 +133,15 @@ var _ = Describe("Podman top", func() { Expect(result).Should(Exit(125)) }) + It("podman top on privileged container", func() { + session := podmanTest.Podman([]string{"run", "--privileged", "-d", ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + cid := session.OutputToString() + + result := podmanTest.Podman([]string{"top", cid, "capeff"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(result.OutputToStringArray()).To(Equal([]string{"EFFECTIVE CAPS", "full"})) + }) }) diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go index 7a975f6a5..499283cab 100644 --- a/test/e2e/volume_create_test.go +++ b/test/e2e/volume_create_test.go @@ -162,19 +162,4 @@ var _ = Describe("Podman volume create", func() { Expect(inspectOpts).Should(Exit(0)) Expect(inspectOpts.OutputToString()).To(Equal(optionStrFormatExpect)) }) - - It("podman create volume with o=timeout", func() { - volName := "testVol" - timeout := 10 - timeoutStr := "10" - session := podmanTest.Podman([]string{"volume", "create", "--opt", fmt.Sprintf("o=timeout=%d", timeout), volName}) - session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) - - inspectTimeout := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .Timeout }}", volName}) - inspectTimeout.WaitWithDefaultTimeout() - Expect(inspectTimeout).Should(Exit(0)) - Expect(inspectTimeout.OutputToString()).To(Equal(timeoutStr)) - - }) }) diff --git a/test/e2e/volume_plugin_test.go b/test/e2e/volume_plugin_test.go index b585f8dd8..a44e75a54 100644 --- a/test/e2e/volume_plugin_test.go +++ b/test/e2e/volume_plugin_test.go @@ -256,4 +256,38 @@ Removed: Expect(session.OutputToStringArray()).To(ContainElements(localvol, vol2)) Expect(session.ErrorToString()).To(Equal("")) // make no errors are shown }) + + It("volume driver timeouts test", func() { + podmanTest.AddImageToRWStore(volumeTest) + + pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes") + err := os.Mkdir(pluginStatePath, 0755) + Expect(err).ToNot(HaveOccurred()) + + // Keep this distinct within tests to avoid multiple tests using the same plugin. + pluginName := "testvol6" + plugin := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath}) + plugin.WaitWithDefaultTimeout() + Expect(plugin).Should(Exit(0)) + + volName := "testVolume1" + create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName}) + create.WaitWithDefaultTimeout() + Expect(create).Should(Exit(0)) + + volInspect := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .Timeout }}", volName}) + volInspect.WaitWithDefaultTimeout() + Expect(volInspect).Should(Exit(0)) + Expect(volInspect.OutputToString()).To(ContainSubstring("15")) + + volName2 := "testVolume2" + create2 := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, "--opt", "o=timeout=3", volName2}) + create2.WaitWithDefaultTimeout() + Expect(create2).Should(Exit(0)) + + volInspect2 := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .Timeout }}", volName2}) + volInspect2.WaitWithDefaultTimeout() + Expect(volInspect2).Should(Exit(0)) + Expect(volInspect2.OutputToString()).To(ContainSubstring("3")) + }) }) diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 908c169ee..a3bfe5780 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -56,7 +56,12 @@ echo $rand | 0 | $rand @test "podman run --memory=0 runtime option" { run_podman run --memory=0 --rm $IMAGE echo hello - is "$output" "hello" "failed to run when --memory is set to 0" + if is_rootless && ! is_cgroupsv2; then + is "${lines[0]}" "Resource limits are not supported and ignored on cgroups V1 rootless systems" "--memory is not supported" + is "${lines[1]}" "hello" "--memory is ignored" + else + is "$output" "hello" "failed to run when --memory is set to 0" + fi } # 'run --preserve-fds' passes a number of additional file descriptors into the container diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index b1b9ee5e1..e3a9ec4c3 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -61,7 +61,7 @@ function teardown() { @test "podman pod create - custom infra image" { - skip_if_remote "CONTAINERS_CONF only effects server side" + skip_if_remote "CONTAINERS_CONF only affects server side" image="i.do/not/exist:image" tmpdir=$PODMAN_TMPDIR/pod-test mkdir -p $tmpdir @@ -478,7 +478,6 @@ spec: } @test "pod resource limits" { - # FIXME: #15074 - possible flake on aarch64 skip_if_remote "resource limits only implemented on non-remote" skip_if_rootless "resource limits only work with root" skip_if_cgroupsv1 "resource limits only meaningful on cgroups V2" @@ -493,30 +492,24 @@ spec: lomajmin=$(losetup -l --noheadings --output MAJ:MIN $LOOPDEVICE | tr -d ' ') run grep -w bfq /sys/block/$(basename ${LOOPDEVICE})/queue/scheduler if [ $status -ne 0 ]; then + losetup -d $LOOPDEVICE + LOOPDEVICE= skip "BFQ scheduler is not supported on the system" - if [ -f ${lofile} ]; then - run_podman '?' rm -t 0 --all --force --ignore - - while read path dev; do - if [[ "$path" == "$lofile" ]]; then - losetup -d $dev - fi - done < <(losetup -l --noheadings --output BACK-FILE,NAME) - rm ${lofile} - fi fi echo bfq > /sys/block/$(basename ${LOOPDEVICE})/queue/scheduler + # FIXME: #15464: blkio-weight-device not working expected_limits=" cpu.max | 500000 100000 memory.max | 5242880 memory.swap.max | 1068498944 +io.bfq.weight | default 50 io.max | $lomajmin rbps=1048576 wbps=1048576 riops=max wiops=max " for cgm in systemd cgroupfs; do local name=resources-$cgm - run_podman --cgroup-manager=$cgm pod create --name=$name --cpus=5 --memory=5m --memory-swap=1g --cpu-shares=1000 --cpuset-cpus=0 --cpuset-mems=0 --device-read-bps=${LOOPDEVICE}:1mb --device-write-bps=${LOOPDEVICE}:1mb --blkio-weight-device=${LOOPDEVICE}:123 --blkio-weight=50 + run_podman --cgroup-manager=$cgm pod create --name=$name --cpus=5 --memory=5m --memory-swap=1g --cpu-shares=1000 --cpuset-cpus=0 --cpuset-mems=0 --device-read-bps=${LOOPDEVICE}:1mb --device-write-bps=${LOOPDEVICE}:1mb --blkio-weight=50 run_podman --cgroup-manager=$cgm pod start $name run_podman pod inspect --format '{{.CgroupPath}}' $name local cgroup_path="$output" diff --git a/test/system/272-system-connection.bats b/test/system/272-system-connection.bats index e9e9a01ea..e937a7273 100644 --- a/test/system/272-system-connection.bats +++ b/test/system/272-system-connection.bats @@ -95,12 +95,12 @@ $c2[ ]\+tcp://localhost:54321[ ]\+true" \ # we need for the server. ${PODMAN%%-remote*} --root ${PODMAN_TMPDIR}/root \ --runroot ${PODMAN_TMPDIR}/runroot \ - system service -t 99 tcp:localhost:$_SERVICE_PORT & + system service -t 99 tcp://localhost:$_SERVICE_PORT & _SERVICE_PID=$! wait_for_port localhost $_SERVICE_PORT _run_podman_remote info --format '{{.Host.RemoteSocket.Path}}' - is "$output" "tcp:localhost:$_SERVICE_PORT" \ + is "$output" "tcp://localhost:$_SERVICE_PORT" \ "podman info works, and talks to the correct server" _run_podman_remote info --format '{{.Store.GraphRoot}}' diff --git a/test/system/700-play.bats b/test/system/700-play.bats index e1955cfd1..bad9544ff 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -361,3 +361,28 @@ status: {} run_podman pod rm -a run_podman rm -a } + +@test "podman kube play - URL" { + TESTDIR=$PODMAN_TMPDIR/testdir + mkdir -p $TESTDIR + echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml + + HOST_PORT=$(random_free_port) + SERVER=http://127.0.0.1:$HOST_PORT + + run_podman run -d --name myyaml -p "$HOST_PORT:80" \ + -v $PODMAN_TMPDIR/test.yaml:/var/www/testpod.yaml:Z \ + -w /var/www \ + $IMAGE /bin/busybox-extras httpd -f -p 80 + + run_podman kube play $SERVER/testpod.yaml + run_podman inspect test_pod-test --format "{{.State.Running}}" + is "$output" "true" + run_podman kube down $SERVER/testpod.yaml + run_podman 125 inspect test_pod-test + is "$output" ".*Error: inspecting object: no such object: \"test_pod-test\"" + + run_podman pod rm -a -f + run_podman rm -a -f + run_podman rm -f -t0 myyaml +} diff --git a/test/system/710-kube.bats b/test/system/710-kube.bats new file mode 100644 index 000000000..58e42148a --- /dev/null +++ b/test/system/710-kube.bats @@ -0,0 +1,171 @@ +#!/usr/bin/env bats -*- bats -*- +# +# Test podman kube generate +# + +load helpers + +# standard capability drop list +capabilities='{"drop":["CAP_MKNOD","CAP_NET_RAW","CAP_AUDIT_WRITE"]}' + +# Warning that is emitted once on containers, multiple times on pods +kubernetes_63='Truncation Annotation: .* Kubernetes only allows 63 characters' + +# filter: convert yaml to json, because bash+yaml=madness +function yaml2json() { + egrep -v "$kubernetes_63" | python3 -c 'import yaml +import json +import sys +json.dump(yaml.safe_load(sys.stdin), sys.stdout)' +} + +############################################################################### +# BEGIN tests + +@test "podman kube generate - usage message" { + run_podman kube generate --help + is "$output" ".*podman.* kube generate \[options\] {CONTAINER...|POD...|VOLUME...}" + run_podman generate kube --help + is "$output" ".*podman.* generate kube \[options\] {CONTAINER...|POD...|VOLUME...}" +} + +@test "podman kube generate - container" { + cname=c$(random_string 15) + run_podman container create --name $cname $IMAGE top + run_podman kube generate $cname + + # Convert yaml to json, and dump to stdout (to help in case of errors) + json=$(yaml2json <<<"$output") + jq . <<<"$json" + + # What we expect to see. This is by necessity an incomplete list. + # For instance, it does not include org.opencontainers.image.base.* + # because sometimes we get that, sometimes we don't. No clue why. + # + # And, unfortunately, if new fields are added to the YAML, we won't + # test those unless a developer remembers to add them here. + # + # Reasons for doing it this way, instead of straight-comparing yaml: + # 1) the arbitrariness of the org.opencontainers.image.base annotations + # 2) YAML order is nondeterministic, so on a pod with two containers + # (as in the pod test below) we cannot rely on cname1/cname2. + expect=" +apiVersion | = | v1 +kind | = | Pod + +metadata.annotations.\"io.kubernetes.cri-o.TTY/$cname\" | = | false +metadata.annotations.\"io.podman.annotations.autoremove/$cname\" | = | FALSE +metadata.annotations.\"io.podman.annotations.init/$cname\" | = | FALSE +metadata.annotations.\"io.podman.annotations.privileged/$cname\" | = | FALSE +metadata.annotations.\"io.podman.annotations.publish-all/$cname\" | = | FALSE + +metadata.creationTimestamp | =~ | [0-9T:-]\\+Z +metadata.labels.app | = | ${cname}-pod +metadata.name | = | ${cname}-pod + +spec.containers[0].command | = | [\"top\"] +spec.containers[0].image | = | $IMAGE +spec.containers[0].name | = | $cname + +spec.containers[0].securityContext.capabilities | = | $capabilities + +status | = | null +" + + # Parse and check all those + while read key op expect; do + actual=$(jq -r -c ".$key" <<<"$json") + assert "$actual" $op "$expect" ".$key" + done < <(parse_table "$expect") + + if ! is_remote; then + count=$(egrep -c "$kubernetes_63" <<<"$output") + assert "$count" = 1 "1 instance of the Kubernetes-63-char warning" + fi + + run_podman rm $cname +} + +@test "podman kube generate - pod" { + local pname=p$(random_string 15) + local cname1=c1$(random_string 15) + local cname2=c2$(random_string 15) + + run_podman pod create --name $pname --publish 9999:8888 + + # Needs at least one container. Error is slightly different between + # regular and remote podman: + # regular: Error: pod ... only has... + # remote: Error: error generating YAML: pod ... only has... + run_podman 125 kube generate $pname + assert "$output" =~ "Error: .* only has an infra container" + + run_podman container create --name $cname1 --pod $pname $IMAGE top + run_podman container create --name $cname2 --pod $pname $IMAGE bottom + run_podman kube generate $pname + + json=$(yaml2json <<<"$output") + jq . <<<"$json" + + # See container test above for description of this table + expect=" +apiVersion | = | v1 +kind | = | Pod + +metadata.annotations.\"io.kubernetes.cri-o.ContainerType/$cname1\" | = | container +metadata.annotations.\"io.kubernetes.cri-o.ContainerType/$cname2\" | = | container +metadata.annotations.\"io.kubernetes.cri-o.SandboxID/$cname1\" | =~ | [0-9a-f]\\{56\\} +metadata.annotations.\"io.kubernetes.cri-o.SandboxID/$cname2\" | =~ | [0-9a-f]\\{56\\} +metadata.annotations.\"io.kubernetes.cri-o.TTY/$cname1\" | = | false +metadata.annotations.\"io.kubernetes.cri-o.TTY/$cname2\" | = | false +metadata.annotations.\"io.podman.annotations.autoremove/$cname1\" | = | FALSE +metadata.annotations.\"io.podman.annotations.autoremove/$cname2\" | = | FALSE +metadata.annotations.\"io.podman.annotations.init/$cname1\" | = | FALSE +metadata.annotations.\"io.podman.annotations.init/$cname2\" | = | FALSE +metadata.annotations.\"io.podman.annotations.privileged/$cname1\" | = | FALSE +metadata.annotations.\"io.podman.annotations.privileged/$cname2\" | = | FALSE +metadata.annotations.\"io.podman.annotations.publish-all/$cname1\" | = | FALSE +metadata.annotations.\"io.podman.annotations.publish-all/$cname2\" | = | FALSE + +metadata.creationTimestamp | =~ | [0-9T:-]\\+Z +metadata.labels.app | = | ${pname} +metadata.name | = | ${pname} + +spec.hostname | = | $pname +spec.restartPolicy | = | Never + +spec.containers[0].command | = | [\"top\"] +spec.containers[0].image | = | $IMAGE +spec.containers[0].name | = | $cname1 +spec.containers[0].ports[0].containerPort | = | 8888 +spec.containers[0].ports[0].hostPort | = | 9999 +spec.containers[0].resources | = | {} + +spec.containers[1].command | = | [\"bottom\"] +spec.containers[1].image | = | $IMAGE +spec.containers[1].name | = | $cname2 +spec.containers[1].ports | = | null +spec.containers[1].resources | = | {} + +spec.containers[0].securityContext.capabilities | = | $capabilities + +status | = | {} +" + + while read key op expect; do + actual=$(jq -r -c ".$key" <<<"$json") + assert "$actual" $op "$expect" ".$key" + done < <(parse_table "$expect") + + # Why 4? Maybe two for each container? + if ! is_remote; then + count=$(egrep -c "$kubernetes_63" <<<"$output") + assert "$count" = 4 "instances of the Kubernetes-63-char warning" + fi + + run_podman rm $cname1 $cname2 + run_podman pod rm $pname + run_podman rmi $(pause_image) +} + +# vim: filetype=sh diff --git a/test/system/900-ssh.bats b/test/system/900-ssh.bats index 0757f5838..4f1682d48 100644 --- a/test/system/900-ssh.bats +++ b/test/system/900-ssh.bats @@ -46,7 +46,7 @@ function _run_podman_remote() { ${PODMAN%%-remote*} --root ${PODMAN_TMPDIR}/root \ --runroot ${PODMAN_TMPDIR}/runroot \ - system service -t 99 tcp:localhost:$_SERVICE_PORT & + system service -t 99 tcp://localhost:$_SERVICE_PORT & _SERVICE_PID=$! wait_for_port localhost $_SERVICE_PORT diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 5ff3fae6d..f2eb3016c 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -36,20 +36,6 @@ fi # That way individual tests can override with their own setup/teardown, # while retaining the ability to include these if they so desire. -# Some CI systems set this to runc, overriding the default crun. -if [[ -n $OCI_RUNTIME ]]; then - if [[ -z $CONTAINERS_CONF ]]; then - # FIXME: BATS provides no mechanism for end-of-run cleanup[1]; how - # can we avoid leaving this file behind when we finish? - # [1] https://github.com/bats-core/bats-core/issues/39 - export CONTAINERS_CONF=$(mktemp --tmpdir=${BATS_TMPDIR:-/tmp} podman-bats-XXXXXXX.containers.conf) - cat >$CONTAINERS_CONF <<EOF -[engine] -runtime="$OCI_RUNTIME" -EOF - fi -fi - # Setup helper: establish a test environment with exactly the images needed function basic_setup() { # Clean up all containers diff --git a/test/testvol/util.go b/test/testvol/util.go index b50bb3afb..b4961e097 100644 --- a/test/testvol/util.go +++ b/test/testvol/util.go @@ -25,5 +25,5 @@ func getPluginName(pathOrName string) string { func getPlugin(sockNameOrPath string) (*plugin.VolumePlugin, error) { path := getSocketPath(sockNameOrPath) name := getPluginName(sockNameOrPath) - return plugin.GetVolumePlugin(name, path, 0) + return plugin.GetVolumePlugin(name, path, nil, nil) } diff --git a/troubleshooting.md b/troubleshooting.md index 6d46a543f..0e767926b 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -678,23 +678,28 @@ $ podman run --rootfs /path/to/rootfs:O .... Modifications to the mount point are destroyed when the container finishes executing, similar to a tmpfs mount point being unmounted. -### 26) Running containers with CPU limits fails with a permissions error +### 26) Running containers with resource limits fails with a permissions error -On some systemd-based systems, non-root users do not have CPU limit delegation -permissions. This causes setting CPU limits to fail. +On some systemd-based systems, non-root users do not have resource limit delegation +permissions. This causes setting resource limits to fail. #### Symptom -Running a container with a CPU limit options such as `--cpus`, `--cpu-period`, -or `--cpu-quota` will fail with an error similar to the following: +Running a container with a resource limit options will fail with an error similar to the following: - Error: opening file `cpu.max` for writing: Permission denied: OCI runtime permission denied error +`--cpus`, `--cpu-period`, `--cpu-quota`, `--cpu-shares`: -This means that CPU limit delegation is not enabled for the current user. + Error: OCI runtime error: crun: the requested cgroup controller `cpu` is not available + +`--cpuset-cpus`, `--cpuset-mems`: + + Error: OCI runtime error: crun: the requested cgroup controller `cpuset` is not available + +This means that resource limit delegation is not enabled for the current user. #### Solution -You can verify whether CPU limit delegation is enabled by running the following command: +You can verify whether resource limit delegation is enabled by running the following command: ```console $ cat "/sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers" @@ -704,27 +709,27 @@ Example output might be: memory pids -In the above example, `cpu` is not listed, which means the current user does -not have permission to set CPU limits. +In the above example, `cpu` and `cpuset` are not listed, which means the current user does +not have permission to set CPU or CPUSET limits. -If you want to enable CPU limit delegation for all users, you can create the +If you want to enable CPU or CPUSET limit delegation for all users, you can create the file `/etc/systemd/system/user@.service.d/delegate.conf` with the contents: ```ini [Service] -Delegate=memory pids cpu io +Delegate=memory pids cpu cpuset ``` -After logging out and logging back in, you should have permission to set CPU -limits. +After logging out and logging back in, you should have permission to set +CPU and CPUSET limits. -### 26) `exec container process '/bin/sh': Exec format error` (or another binary than `bin/sh`) +### 27) `exec container process '/bin/sh': Exec format error` (or another binary than `bin/sh`) This can happen when running a container from an image for another architecture than the one you are running on. For example, if a remote repository only has, and thus send you, a `linux/arm64` _OS/ARCH_ but you run on `linux/amd64` (as happened in https://github.com/openMF/community-app/issues/3323 due to https://github.com/timbru31/docker-ruby-node/issues/564). -### 27) `Error: failed to create sshClient: Connection to bastion host (ssh://user@host:22/run/user/.../podman/podman.sock) failed.: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain` +### 28) `Error: failed to create sshClient: Connection to bastion host (ssh://user@host:22/run/user/.../podman/podman.sock) failed.: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain` In some situations where the client is not on the same machine as where the podman daemon is running the client key could be using a cipher not supported by the host. This indicates an issue with one's SSH config. Until remedied using podman over ssh with a pre-shared key will be impossible. @@ -761,7 +766,7 @@ And now this should work: $ podman-remote info ``` -### 28) Rootless CNI networking fails in RHEL with Podman v2.2.1 to v3.0.1. +### 29) Rootless CNI networking fails in RHEL with Podman v2.2.1 to v3.0.1. A failure is encountered when trying to use networking on a rootless container in Podman v2.2.1 through v3.0.1 on RHEL. This error does not @@ -780,7 +785,7 @@ instructions for building the Infra container image can be found for v2.2.1 [here](https://github.com/containers/podman/tree/v2.2.1-rhel/contrib/rootless-cni-infra), and for v3.0.1 [here](https://github.com/containers/podman/tree/v3.0.1-rhel/contrib/rootless-cni-infra). -### 29) Container related firewall rules are lost after reloading firewalld +### 30) Container related firewall rules are lost after reloading firewalld Container network can't be reached after `firewall-cmd --reload` and `systemctl restart firewalld` Running `podman network reload` will fix it but it has to be done manually. #### Symptom @@ -918,7 +923,7 @@ if __name__ == "__main__": signal_listener() ``` -### 30) Podman run fails with `ERRO[0000] XDG_RUNTIME_DIR directory "/run/user/0" is not owned by the current user` or `Error: error creating tmpdir: mkdir /run/user/1000: permission denied`. +### 31) Podman run fails with `ERRO[0000] XDG_RUNTIME_DIR directory "/run/user/0" is not owned by the current user` or `Error: error creating tmpdir: mkdir /run/user/1000: permission denied`. A failure is encountered when performing `podman run` with a warning `XDG_RUNTIME_DIR is pointing to a path which is not writable. Most likely podman will fail.` @@ -960,7 +965,7 @@ Alternatives: * Before invoking Podman command create a valid login session for your rootless user using `loginctl enable-linger <username>` -### 31) 127.0.0.1:7777 port already bound +### 32) 127.0.0.1:7777 port already bound After deleting a VM on macOS, the initialization of subsequent VMs fails. @@ -972,7 +977,7 @@ After deleting a client VM on macOS via `podman machine stop` && `podman machine You will need to remove the hanging gv-proxy process bound to the port in question. For example, if the port mentioned in the error message is 127.0.0.1:7777, you can use the command `kill -9 $(lsof -i:7777)` in order to identify and remove the hanging process which prevents you from starting a new VM on that default port. -### 32) The sshd process fails to run inside of the container. +### 33) The sshd process fails to run inside of the container. #### Symptom @@ -991,7 +996,7 @@ then using podman -remote to start the container or simply by running something like `systemd-run podman run ...`. In this case the container will only need `CAP_AUDIT_WRITE`. -### 33) Container creates a file that is not owned by the user's regular UID +### 34) Container creates a file that is not owned by the user's regular UID After running a container with rootless Podman, the non-root user sees a numerical UID and GID instead of a username and groupname. @@ -1106,7 +1111,7 @@ Another variant of the same problem could occur when using in some way (e.g by creating them themselves, or switching the effective UID to a rootless user and then creates files). -### 34) Passed-in devices or files can't be accessed in rootless container (UID/GID mapping problem) +### 35) Passed-in devices or files can't be accessed in rootless container (UID/GID mapping problem) As a non-root user you have access rights to devices, files and directories that you want to pass into a rootless container with `--device=...`, `--volume=...` or `--mount=..`. @@ -1203,7 +1208,7 @@ can sometimes be an alternative solution, but it forces the regular user's host UID to be mapped to the same UID inside the container so it provides less flexibility than using `--uidmap` and `--gidmap`. -### 35) Images in the additional stores can be deleted even if there are containers using them +### 36) Images in the additional stores can be deleted even if there are containers using them When an image in an additional store is used, it is not locked thus it can be deleted even if there are containers using it. @@ -1218,7 +1223,7 @@ It is the user responsibility to make sure images in an additional store are not deleted while being used by containers in another store. -### 36) Syncing bugfixes for podman-remote or setups using Podman API +### 37) Syncing bugfixes for podman-remote or setups using Podman API After upgrading Podman to a newer version an issue with the earlier version of Podman still presents itself while using podman-remote. @@ -1232,7 +1237,7 @@ When upgrading Podman to a particular version for the required fixes, users ofte Example: If a particular bug was fixed in `v4.1.0` then the Podman client must have version `v4.1.0` as well the Podman server must have version `v4.1.0`. -### 37) Unexpected carriage returns are outputted on the terminal +### 38) Unexpected carriage returns are outputted on the terminal When using the __--tty__ (__-t__) flag, unexpected carriage returns are outputted on the terminal. diff --git a/utils/utils_freebsd.go b/utils/utils_freebsd.go new file mode 100644 index 000000000..d239e9a5d --- /dev/null +++ b/utils/utils_freebsd.go @@ -0,0 +1,22 @@ +//go:build freebsd +// +build freebsd + +package utils + +import "errors" + +func RunUnderSystemdScope(pid int, slice string, unitName string) error { + return errors.New("not implemented for freebsd") +} + +func MoveUnderCgroupSubtree(subtree string) error { + return errors.New("not implemented for freebsd") +} + +func GetOwnCgroup() (string, error) { + return "", errors.New("not implemented for freebsd") +} + +func GetCgroupProcess(pid int) (string, error) { + return "", errors.New("not implemented for freebsd") +} diff --git a/vendor/github.com/Microsoft/hcsshim/internal/jobobject/iocp.go b/vendor/github.com/Microsoft/hcsshim/internal/jobobject/iocp.go index 3d640ac7b..5d6acd69e 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/jobobject/iocp.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/jobobject/iocp.go @@ -57,7 +57,7 @@ func pollIOCP(ctx context.Context, iocpHandle windows.Handle) { }).Warn("failed to parse job object message") continue } - if err := msq.Write(notification); err == queue.ErrQueueClosed { + if err := msq.Enqueue(notification); err == queue.ErrQueueClosed { // Write will only return an error when the queue is closed. // The only time a queue would ever be closed is when we call `Close` on // the job it belongs to which also removes it from the jobMap, so something diff --git a/vendor/github.com/Microsoft/hcsshim/internal/jobobject/jobobject.go b/vendor/github.com/Microsoft/hcsshim/internal/jobobject/jobobject.go index 9c2726416..c9fdd921a 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/jobobject/jobobject.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/jobobject/jobobject.go @@ -68,6 +68,9 @@ type Options struct { // `UseNTVariant` specifies if we should use the `Nt` variant of Open/CreateJobObject. // Defaults to false. UseNTVariant bool + // `IOTracking` enables tracking I/O statistics on the job object. More specifically this + // calls SetInformationJobObject with the JobObjectIoAttribution class. + EnableIOTracking bool } // Create creates a job object. @@ -134,6 +137,12 @@ func Create(ctx context.Context, options *Options) (_ *JobObject, err error) { job.mq = mq } + if options.EnableIOTracking { + if err := enableIOTracking(jobHandle); err != nil { + return nil, err + } + } + return job, nil } @@ -235,7 +244,7 @@ func (job *JobObject) PollNotification() (interface{}, error) { if job.mq == nil { return nil, ErrNotRegistered } - return job.mq.ReadOrWait() + return job.mq.Dequeue() } // UpdateProcThreadAttribute updates the passed in ProcThreadAttributeList to contain what is necessary to @@ -330,7 +339,7 @@ func (job *JobObject) Pids() ([]uint32, error) { err := winapi.QueryInformationJobObject( job.handle, winapi.JobObjectBasicProcessIdList, - uintptr(unsafe.Pointer(&info)), + unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)), nil, ) @@ -356,7 +365,7 @@ func (job *JobObject) Pids() ([]uint32, error) { if err = winapi.QueryInformationJobObject( job.handle, winapi.JobObjectBasicProcessIdList, - uintptr(unsafe.Pointer(&buf[0])), + unsafe.Pointer(&buf[0]), uint32(len(buf)), nil, ); err != nil { @@ -384,7 +393,7 @@ func (job *JobObject) QueryMemoryStats() (*winapi.JOBOBJECT_MEMORY_USAGE_INFORMA if err := winapi.QueryInformationJobObject( job.handle, winapi.JobObjectMemoryUsageInformation, - uintptr(unsafe.Pointer(&info)), + unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)), nil, ); err != nil { @@ -406,7 +415,7 @@ func (job *JobObject) QueryProcessorStats() (*winapi.JOBOBJECT_BASIC_ACCOUNTING_ if err := winapi.QueryInformationJobObject( job.handle, winapi.JobObjectBasicAccountingInformation, - uintptr(unsafe.Pointer(&info)), + unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)), nil, ); err != nil { @@ -415,7 +424,9 @@ func (job *JobObject) QueryProcessorStats() (*winapi.JOBOBJECT_BASIC_ACCOUNTING_ return &info, nil } -// QueryStorageStats gets the storage (I/O) stats for the job object. +// QueryStorageStats gets the storage (I/O) stats for the job object. This call will error +// if either `EnableIOTracking` wasn't set to true on creation of the job, or SetIOTracking() +// hasn't been called since creation of the job. func (job *JobObject) QueryStorageStats() (*winapi.JOBOBJECT_IO_ATTRIBUTION_INFORMATION, error) { job.handleLock.RLock() defer job.handleLock.RUnlock() @@ -430,7 +441,7 @@ func (job *JobObject) QueryStorageStats() (*winapi.JOBOBJECT_IO_ATTRIBUTION_INFO if err := winapi.QueryInformationJobObject( job.handle, winapi.JobObjectIoAttribution, - uintptr(unsafe.Pointer(&info)), + unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)), nil, ); err != nil { @@ -476,7 +487,7 @@ func (job *JobObject) QueryPrivateWorkingSet() (uint64, error) { status := winapi.NtQueryInformationProcess( h, winapi.ProcessVmCounters, - uintptr(unsafe.Pointer(&vmCounters)), + unsafe.Pointer(&vmCounters), uint32(unsafe.Sizeof(vmCounters)), nil, ) @@ -497,3 +508,31 @@ func (job *JobObject) QueryPrivateWorkingSet() (uint64, error) { return jobWorkingSetSize, nil } + +// SetIOTracking enables IO tracking for processes in the job object. +// This enables use of the QueryStorageStats method. +func (job *JobObject) SetIOTracking() error { + job.handleLock.RLock() + defer job.handleLock.RUnlock() + + if job.handle == 0 { + return ErrAlreadyClosed + } + + return enableIOTracking(job.handle) +} + +func enableIOTracking(job windows.Handle) error { + info := winapi.JOBOBJECT_IO_ATTRIBUTION_INFORMATION{ + ControlFlags: winapi.JOBOBJECT_IO_ATTRIBUTION_CONTROL_ENABLE, + } + if _, err := windows.SetInformationJobObject( + job, + winapi.JobObjectIoAttribution, + uintptr(unsafe.Pointer(&info)), + uint32(unsafe.Sizeof(info)), + ); err != nil { + return fmt.Errorf("failed to enable IO tracking on job object: %w", err) + } + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/internal/jobobject/limits.go b/vendor/github.com/Microsoft/hcsshim/internal/jobobject/limits.go index 4be297788..4efde292c 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/jobobject/limits.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/jobobject/limits.go @@ -202,7 +202,7 @@ func (job *JobObject) getExtendedInformation() (*windows.JOBOBJECT_EXTENDED_LIMI if err := winapi.QueryInformationJobObject( job.handle, windows.JobObjectExtendedLimitInformation, - uintptr(unsafe.Pointer(&info)), + unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)), nil, ); err != nil { @@ -224,7 +224,7 @@ func (job *JobObject) getCPURateControlInformation() (*winapi.JOBOBJECT_CPU_RATE if err := winapi.QueryInformationJobObject( job.handle, windows.JobObjectCpuRateControlInformation, - uintptr(unsafe.Pointer(&info)), + unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)), nil, ); err != nil { diff --git a/vendor/github.com/Microsoft/hcsshim/internal/queue/mq.go b/vendor/github.com/Microsoft/hcsshim/internal/queue/mq.go index e177c9a62..4eb9bb9f1 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/queue/mq.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/queue/mq.go @@ -5,10 +5,7 @@ import ( "sync" ) -var ( - ErrQueueClosed = errors.New("the queue is closed for reading and writing") - ErrQueueEmpty = errors.New("the queue is empty") -) +var ErrQueueClosed = errors.New("the queue is closed for reading and writing") // MessageQueue represents a threadsafe message queue to be used to retrieve or // write messages to. @@ -29,8 +26,8 @@ func NewMessageQueue() *MessageQueue { } } -// Write writes `msg` to the queue. -func (mq *MessageQueue) Write(msg interface{}) error { +// Enqueue writes `msg` to the queue. +func (mq *MessageQueue) Enqueue(msg interface{}) error { mq.m.Lock() defer mq.m.Unlock() @@ -43,55 +40,37 @@ func (mq *MessageQueue) Write(msg interface{}) error { return nil } -// Read will read a value from the queue if available, otherwise return an error. -func (mq *MessageQueue) Read() (interface{}, error) { +// Dequeue will read a value from the queue and remove it. If the queue +// is empty, this will block until the queue is closed or a value gets enqueued. +func (mq *MessageQueue) Dequeue() (interface{}, error) { mq.m.Lock() defer mq.m.Unlock() - if mq.closed { - return nil, ErrQueueClosed - } - if mq.isEmpty() { - return nil, ErrQueueEmpty + + for !mq.closed && mq.size() == 0 { + mq.c.Wait() } - val := mq.messages[0] - mq.messages[0] = nil - mq.messages = mq.messages[1:] - return val, nil -} -// ReadOrWait will read a value from the queue if available, else it will wait for a -// value to become available. This will block forever if nothing gets written or until -// the queue gets closed. -func (mq *MessageQueue) ReadOrWait() (interface{}, error) { - mq.m.Lock() + // We got woken up, check if it's because the queue got closed. if mq.closed { - mq.m.Unlock() return nil, ErrQueueClosed } - if mq.isEmpty() { - for !mq.closed && mq.isEmpty() { - mq.c.Wait() - } - mq.m.Unlock() - return mq.Read() - } + val := mq.messages[0] mq.messages[0] = nil mq.messages = mq.messages[1:] - mq.m.Unlock() return val, nil } -// IsEmpty returns if the queue is empty -func (mq *MessageQueue) IsEmpty() bool { +// Size returns the size of the queue. +func (mq *MessageQueue) Size() int { mq.m.RLock() defer mq.m.RUnlock() - return len(mq.messages) == 0 + return mq.size() } -// Nonexported empty check that doesn't lock so we can call this in Read and Write. -func (mq *MessageQueue) isEmpty() bool { - return len(mq.messages) == 0 +// Nonexported size check to check if the queue is empty inside already locked functions. +func (mq *MessageQueue) size() int { + return len(mq.messages) } // Close closes the queue for future writes or reads. Any attempts to read or write from the @@ -99,13 +78,15 @@ func (mq *MessageQueue) isEmpty() bool { func (mq *MessageQueue) Close() { mq.m.Lock() defer mq.m.Unlock() - // Already closed + + // Already closed, noop if mq.closed { return } + mq.messages = nil mq.closed = true - // If there's anybody currently waiting on a value from ReadOrWait, we need to + // If there's anybody currently waiting on a value from Dequeue, we need to // broadcast so the read(s) can return ErrQueueClosed. mq.c.Broadcast() } diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go index 479649db3..7eb13f8f0 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go @@ -175,7 +175,7 @@ type JOBOBJECT_ASSOCIATE_COMPLETION_PORT struct { // LPDWORD lpReturnLength // ); // -//sys QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo uintptr, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) = kernel32.QueryInformationJobObject +//sys QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo unsafe.Pointer, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) = kernel32.QueryInformationJobObject // HANDLE OpenJobObjectW( // DWORD dwDesiredAccess, diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go index 5f9e03fd2..222529f43 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go @@ -18,7 +18,7 @@ const ProcessVmCounters = 3 // [out, optional] PULONG ReturnLength // ); // -//sys NtQueryInformationProcess(processHandle windows.Handle, processInfoClass uint32, processInfo uintptr, processInfoLength uint32, returnLength *uint32) (status uint32) = ntdll.NtQueryInformationProcess +//sys NtQueryInformationProcess(processHandle windows.Handle, processInfoClass uint32, processInfo unsafe.Pointer, processInfoLength uint32, returnLength *uint32) (status uint32) = ntdll.NtQueryInformationProcess // typedef struct _VM_COUNTERS_EX // { diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/system.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/system.go index 327f57d7c..78fe01a4b 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/system.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/system.go @@ -12,7 +12,8 @@ const STATUS_INFO_LENGTH_MISMATCH = 0xC0000004 // ULONG SystemInformationLength, // PULONG ReturnLength // ); -//sys NtQuerySystemInformation(systemInfoClass int, systemInformation uintptr, systemInfoLength uint32, returnLength *uint32) (status uint32) = ntdll.NtQuerySystemInformation +// +//sys NtQuerySystemInformation(systemInfoClass int, systemInformation unsafe.Pointer, systemInfoLength uint32, returnLength *uint32) (status uint32) = ntdll.NtQuerySystemInformation type SYSTEM_PROCESS_INFORMATION struct { NextEntryOffset uint32 // ULONG diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go index 39fb3e1ad..1f16cf0b8 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go @@ -100,7 +100,7 @@ func resizePseudoConsole(hPc windows.Handle, size uint32) (hr error) { return } -func NtQuerySystemInformation(systemInfoClass int, systemInformation uintptr, systemInfoLength uint32, returnLength *uint32) (status uint32) { +func NtQuerySystemInformation(systemInfoClass int, systemInformation unsafe.Pointer, systemInfoLength uint32, returnLength *uint32) (status uint32) { r0, _, _ := syscall.Syscall6(procNtQuerySystemInformation.Addr(), 4, uintptr(systemInfoClass), uintptr(systemInformation), uintptr(systemInfoLength), uintptr(unsafe.Pointer(returnLength)), 0, 0) status = uint32(r0) return @@ -152,7 +152,7 @@ func IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result return } -func QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo uintptr, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) { +func QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo unsafe.Pointer, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) { r1, _, e1 := syscall.Syscall6(procQueryInformationJobObject.Addr(), 5, uintptr(jobHandle), uintptr(infoClass), uintptr(jobObjectInfo), uintptr(jobObjectInformationLength), uintptr(unsafe.Pointer(lpReturnLength)), 0) if r1 == 0 { if e1 != 0 { @@ -244,7 +244,7 @@ func LocalFree(ptr uintptr) { return } -func NtQueryInformationProcess(processHandle windows.Handle, processInfoClass uint32, processInfo uintptr, processInfoLength uint32, returnLength *uint32) (status uint32) { +func NtQueryInformationProcess(processHandle windows.Handle, processInfoClass uint32, processInfo unsafe.Pointer, processInfoLength uint32, returnLength *uint32) (status uint32) { r0, _, _ := syscall.Syscall6(procNtQueryInformationProcess.Addr(), 5, uintptr(processHandle), uintptr(processInfoClass), uintptr(processInfo), uintptr(processInfoLength), uintptr(unsafe.Pointer(returnLength)), 0) status = uint32(r0) return diff --git a/vendor/github.com/containers/common/libimage/inspect.go b/vendor/github.com/containers/common/libimage/inspect.go index 5da8df1bf..c6632d9a2 100644 --- a/vendor/github.com/containers/common/libimage/inspect.go +++ b/vendor/github.com/containers/common/libimage/inspect.go @@ -190,7 +190,7 @@ func (i *Image) Inspect(ctx context.Context, options *InspectOptions) (*ImageDat // NOTE: Health checks may be listed in the container config or // the config. data.HealthCheck = dockerManifest.ContainerConfig.Healthcheck - if data.HealthCheck == nil { + if data.HealthCheck == nil && dockerManifest.Config != nil { data.HealthCheck = dockerManifest.Config.Healthcheck } } diff --git a/vendor/github.com/containers/common/libimage/load.go b/vendor/github.com/containers/common/libimage/load.go index 89faa4635..593eef04b 100644 --- a/vendor/github.com/containers/common/libimage/load.go +++ b/vendor/github.com/containers/common/libimage/load.go @@ -99,7 +99,7 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ( } // loadMultiImageDockerArchive loads the docker archive specified by ref. In -// case the path@reference notation was used, only the specifiec image will be +// case the path@reference notation was used, only the specified image will be // loaded. Otherwise, all images will be loaded. func (r *Runtime) loadMultiImageDockerArchive(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) { // If we cannot stat the path, it either does not exist OR the correct diff --git a/vendor/github.com/containers/common/libnetwork/cni/network.go b/vendor/github.com/containers/common/libnetwork/cni/network.go index fce8f0066..11f1bbe14 100644 --- a/vendor/github.com/containers/common/libnetwork/cni/network.go +++ b/vendor/github.com/containers/common/libnetwork/cni/network.go @@ -19,6 +19,7 @@ import ( "github.com/containers/common/pkg/config" "github.com/containers/storage/pkg/lockfile" "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) type cniNetwork struct { @@ -62,6 +63,8 @@ type InitConfig struct { CNIConfigDir string // CNIPluginDirs is a list of directories where cni should look for the plugins. CNIPluginDirs []string + // RunDir is a directory where temporary files can be stored. + RunDir string // DefaultNetwork is the name for the default network. DefaultNetwork string @@ -81,7 +84,16 @@ func NewCNINetworkInterface(conf *InitConfig) (types.ContainerNetwork, error) { // TODO: consider using a shared memory lock lock, err := lockfile.GetLockfile(filepath.Join(conf.CNIConfigDir, "cni.lock")) if err != nil { - return nil, err + // If we're on a read-only filesystem, there is no risk of + // contention. Fall back to a local lockfile. + if errors.Is(err, unix.EROFS) { + lock, err = lockfile.GetLockfile(filepath.Join(conf.RunDir, "cni.lock")) + if err != nil { + return nil, err + } + } else { + return nil, err + } } defaultNetworkName := conf.DefaultNetwork diff --git a/vendor/github.com/containers/common/libnetwork/network/interface.go b/vendor/github.com/containers/common/libnetwork/network/interface.go index 639ff4e45..545655fd3 100644 --- a/vendor/github.com/containers/common/libnetwork/network/interface.go +++ b/vendor/github.com/containers/common/libnetwork/network/interface.go @@ -169,6 +169,7 @@ func getCniInterface(conf *config.Config) (types.ContainerNetwork, error) { return cni.NewCNINetworkInterface(&cni.InitConfig{ CNIConfigDir: confDir, CNIPluginDirs: conf.Network.CNIPluginDirs, + RunDir: conf.Engine.TmpDir, DefaultNetwork: conf.Network.DefaultNetwork, DefaultSubnet: conf.Network.DefaultSubnet, DefaultsubnetPools: conf.Network.DefaultSubnetPools, diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go index a6276fbef..858f961b6 100644 --- a/vendor/github.com/containers/common/pkg/config/config.go +++ b/vendor/github.com/containers/common/pkg/config/config.go @@ -7,6 +7,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "sort" "strings" "sync" @@ -27,6 +28,8 @@ const ( _configPath = "containers/containers.conf" // UserOverrideContainersConfig holds the containers config path overridden by the rootless user UserOverrideContainersConfig = ".config/" + _configPath + // Token prefix for looking for helper binary under $BINDIR + bindirPrefix = "$BINDIR" ) // RuntimeStateStore is a constant indicating which state store implementation @@ -234,6 +237,10 @@ type EngineConfig struct { // The first path pointing to a valid file will be used. ConmonPath []string `toml:"conmon_path,omitempty"` + // ConmonRsPath is the path to the Conmon-rs binary used for managing containers. + // The first path pointing to a valid file will be used. + ConmonRsPath []string `toml:"conmonrs_path,omitempty"` + // CompatAPIEnforceDockerHub enforces using docker.io for completing // short names in Podman's compatibility REST API. Note that this will // ignore unqualified-search-registries and short-name aliases defined @@ -450,6 +457,13 @@ type EngineConfig struct { // may not be by other drivers. VolumePath string `toml:"volume_path,omitempty"` + // VolumePluginTimeout sets the default timeout, in seconds, for + // operations that must contact a volume plugin. Plugins are external + // programs accessed via REST API; this sets a timeout for requests to + // that API. + // A value of 0 is treated as no timeout. + VolumePluginTimeout uint `toml:"volume_plugin_timeout,omitempty,omitzero"` + // VolumePlugins is a set of plugins that can be used as the backend for // Podman named volumes. Each volume is specified as a name (what Podman // will refer to the plugin as) mapped to a path, which must point to a @@ -811,6 +825,18 @@ func (c *Config) Validate() error { return nil } +// URI returns the URI Path to the machine image +func (m *MachineConfig) URI() string { + uri := m.Image + for _, val := range []string{"$ARCH", "$arch"} { + uri = strings.Replace(uri, val, runtime.GOARCH, 1) + } + for _, val := range []string{"$OS", "$os"} { + uri = strings.Replace(uri, val, runtime.GOOS, 1) + } + return uri +} + func (c *EngineConfig) findRuntime() string { // Search for crun first followed by runc, kata, runsc for _, name := range []string{"crun", "runc", "runj", "kata", "runsc"} { @@ -915,8 +941,12 @@ func (c *NetworkConfig) Validate() error { // to first (version) matching conmon binary. If non is found, we try // to do a path lookup of "conmon". func (c *Config) FindConmon() (string, error) { + return findConmonPath(c.Engine.ConmonPath, "conmon", _conmonMinMajorVersion, _conmonMinMinorVersion, _conmonMinPatchVersion) +} + +func findConmonPath(paths []string, binaryName string, major int, minor int, patch int) (string, error) { foundOutdatedConmon := false - for _, path := range c.Engine.ConmonPath { + for _, path := range paths { stat, err := os.Stat(path) if err != nil { continue @@ -934,7 +964,7 @@ func (c *Config) FindConmon() (string, error) { } // Search the $PATH as last fallback - if path, err := exec.LookPath("conmon"); err == nil { + if path, err := exec.LookPath(binaryName); err == nil { if err := probeConmon(path); err != nil { logrus.Warnf("Conmon at %s is invalid: %v", path, err) foundOutdatedConmon = true @@ -946,11 +976,18 @@ func (c *Config) FindConmon() (string, error) { if foundOutdatedConmon { return "", fmt.Errorf("please update to v%d.%d.%d or later: %w", - _conmonMinMajorVersion, _conmonMinMinorVersion, _conmonMinPatchVersion, ErrConmonOutdated) + major, minor, patch, ErrConmonOutdated) } return "", fmt.Errorf("could not find a working conmon binary (configured options: %v: %w)", - c.Engine.ConmonPath, ErrInvalidArg) + paths, ErrInvalidArg) +} + +// FindConmonRs iterates over (*Config).ConmonRsPath and returns the path +// to first (version) matching conmonrs binary. If non is found, we try +// to do a path lookup of "conmonrs". +func (c *Config) FindConmonRs() (string, error) { + return findConmonPath(c.Engine.ConmonRsPath, "conmonrs", _conmonrsMinMajorVersion, _conmonrsMinMinorVersion, _conmonrsMinPatchVersion) } // GetDefaultEnv returns the environment variables for the container. @@ -1226,10 +1263,37 @@ func (c *Config) ActiveDestination() (uri, identity string, err error) { return "", "", errors.New("no service destination configured") } +var ( + bindirFailed = false + bindirCached = "" +) + +func findBindir() string { + if bindirCached != "" || bindirFailed { + return bindirCached + } + execPath, err := os.Executable() + if err == nil { + // Resolve symbolic links to find the actual binary file path. + execPath, err = filepath.EvalSymlinks(execPath) + } + if err != nil { + // If failed to find executable (unlikely to happen), warn about it. + // The bindirFailed flag will track this, so we only warn once. + logrus.Warnf("Failed to find $BINDIR: %v", err) + bindirFailed = true + return "" + } + bindirCached = filepath.Dir(execPath) + return bindirCached +} + // FindHelperBinary will search the given binary name in the configured directories. // If searchPATH is set to true it will also search in $PATH. func (c *Config) FindHelperBinary(name string, searchPATH bool) (string, error) { dirList := c.Engine.HelperBinariesDir + bindirPath := "" + bindirSearched := false // If set, search this directory first. This is used in testing. if dir, found := os.LookupEnv("CONTAINERS_HELPER_BINARY_DIR"); found { @@ -1237,6 +1301,24 @@ func (c *Config) FindHelperBinary(name string, searchPATH bool) (string, error) } for _, path := range dirList { + if path == bindirPrefix || strings.HasPrefix(path, bindirPrefix+string(filepath.Separator)) { + // Calculate the path to the executable first time we encounter a $BINDIR prefix. + if !bindirSearched { + bindirSearched = true + bindirPath = findBindir() + } + // If there's an error, don't stop the search for the helper binary. + // findBindir() will have warned once during the first failure. + if bindirPath == "" { + continue + } + // Replace the $BINDIR prefix with the path to the directory of the current binary. + if path == bindirPrefix { + path = bindirPath + } else { + path = filepath.Join(bindirPath, strings.TrimPrefix(path, bindirPrefix+string(filepath.Separator))) + } + } fullpath := filepath.Join(path, name) if fi, err := os.Stat(fullpath); err == nil && fi.Mode().IsRegular() { return fullpath, nil diff --git a/vendor/github.com/containers/common/pkg/config/config_darwin.go b/vendor/github.com/containers/common/pkg/config/config_darwin.go index 0ab9e0294..5283665e1 100644 --- a/vendor/github.com/containers/common/pkg/config/config_darwin.go +++ b/vendor/github.com/containers/common/pkg/config/config_darwin.go @@ -35,4 +35,6 @@ var defaultHelperBinariesDir = []string{ "/usr/local/lib/podman", "/usr/libexec/podman", "/usr/lib/podman", + // Relative to the binary directory + "$BINDIR/../libexec/podman", } diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf index d1ac7c0e8..5b5aaa00a 100644 --- a/vendor/github.com/containers/common/pkg/config/containers.conf +++ b/vendor/github.com/containers/common/pkg/config/containers.conf @@ -605,6 +605,12 @@ default_sysctls = [ # #volume_path = "/var/lib/containers/storage/volumes" +# Default timeout (in seconds) for volume plugin operations. +# Plugins are external programs accessed via a REST API; this sets a timeout +# for requests to that API. +# A value of 0 is treated as no timeout. +#volume_plugin_timeout = 5 + # Paths to look for a valid OCI runtime (crun, runc, kata, runsc, krun, etc) [engine.runtimes] #crun = [ @@ -665,9 +671,16 @@ default_sysctls = [ # #disk_size=10 -# The image used when creating a podman-machine VM. +# Default image URI when creating a new VM using `podman machine init`. +# Options: On Linux/Mac, `testing`, `stable`, `next`. On Windows, the major +# version of the OS (e.g `36`) for Fedora 36. For all platforms you can +# alternatively specify a custom download URL to an image. Container engines +# translate URIs $OS and $ARCH to the native OS and ARCH. URI +# "https://example.com/$OS/$ARCH/foobar.ami" becomes +# "https://example.com/linux/amd64/foobar.ami" on a Linux AMD machine. +# The default value is `testing`. # -#image = "testing" +# image = "testing" # Memory in MB a machine is created with. # diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go index c7ddf90ee..b0d62779b 100644 --- a/vendor/github.com/containers/common/pkg/config/default.go +++ b/vendor/github.com/containers/common/pkg/config/default.go @@ -33,6 +33,15 @@ const ( // _conmonMinPatchVersion is the sub-minor version required for conmon. _conmonMinPatchVersion = 1 + // _conmonrsMinMajorVersion is the major version required for conmonrs. + _conmonrsMinMajorVersion = 0 + + // _conmonrsMinMinorVersion is the minor version required for conmonrs. + _conmonrsMinMinorVersion = 1 + + // _conmonrsMinPatchVersion is the sub-minor version required for conmonrs. + _conmonrsMinPatchVersion = 0 + // _conmonVersionFormatErr is used when the expected versio-format of conmon // has changed. _conmonVersionFormatErr = "conmon version changed format: %w" @@ -159,6 +168,8 @@ const ( SeccompOverridePath = _etcDir + "/containers/seccomp.json" // SeccompDefaultPath defines the default seccomp path. SeccompDefaultPath = _installPrefix + "/share/containers/seccomp.json" + // DefaultVolumePluginTimeout is the default volume plugin timeout, in seconds + DefaultVolumePluginTimeout = 5 ) // DefaultConfig defines the default values from containers.conf. @@ -255,7 +266,7 @@ func defaultMachineConfig() MachineConfig { Image: getDefaultMachineImage(), Memory: 2048, User: getDefaultMachineUser(), - Volumes: []string{"$HOME:$HOME"}, + Volumes: getDefaultMachineVolumes(), } } @@ -276,7 +287,9 @@ func defaultConfigFromMemory() (*EngineConfig, error) { c.CompatAPIEnforceDockerHub = true if path, ok := os.LookupEnv("CONTAINERS_STORAGE_CONF"); ok { - types.SetDefaultConfigFilePath(path) + if err := types.SetDefaultConfigFilePath(path); err != nil { + return nil, err + } } storeOpts, err := types.DefaultStoreOptions(unshare.IsRootless(), unshare.GetRootlessUID()) if err != nil { @@ -293,6 +306,8 @@ func defaultConfigFromMemory() (*EngineConfig, error) { c.StaticDir = filepath.Join(storeOpts.GraphRoot, "libpod") c.VolumePath = filepath.Join(storeOpts.GraphRoot, "volumes") + c.VolumePluginTimeout = DefaultVolumePluginTimeout + c.HelperBinariesDir = defaultHelperBinariesDir if additionalHelperBinariesDir != "" { c.HelperBinariesDir = append(c.HelperBinariesDir, additionalHelperBinariesDir) @@ -372,6 +387,16 @@ func defaultConfigFromMemory() (*EngineConfig, error) { "/usr/local/sbin/conmon", "/run/current-system/sw/bin/conmon", } + c.ConmonRsPath = []string{ + "/usr/libexec/podman/conmonrs", + "/usr/local/libexec/podman/conmonrs", + "/usr/local/lib/podman/conmonrs", + "/usr/bin/conmonrs", + "/usr/sbin/conmonrs", + "/usr/local/bin/conmonrs", + "/usr/local/sbin/conmonrs", + "/run/current-system/sw/bin/conmonrs", + } c.PullPolicy = DefaultPullPolicy c.RuntimeSupportsJSON = []string{ "crun", @@ -434,42 +459,55 @@ func probeConmon(conmonBinary string) error { if err := cmd.Run(); err != nil { return err } - r := regexp.MustCompile(`^conmon version (?P<Major>\d+).(?P<Minor>\d+).(?P<Patch>\d+)`) + r := regexp.MustCompile(`^(version:|conmon version)? (?P<Major>\d+).(?P<Minor>\d+).(?P<Patch>\d+)`) matches := r.FindStringSubmatch(out.String()) - if len(matches) != 4 { - return errors.New(_conmonVersionFormatErr) + if len(matches) != 5 { + return fmt.Errorf(_conmonVersionFormatErr, errors.New("invalid version format")) } - major, err := strconv.Atoi(matches[1]) + major, err := strconv.Atoi(matches[2]) + + var minMajor, minMinor, minPatch int + // conmon-rs returns "^version:" + if matches[1] == "version:" { + minMajor = _conmonrsMinMajorVersion + minMinor = _conmonrsMinMinorVersion + minPatch = _conmonrsMinPatchVersion + } else { + minMajor = _conmonMinMajorVersion + minMinor = _conmonMinMinorVersion + minPatch = _conmonMinPatchVersion + } + if err != nil { return fmt.Errorf(_conmonVersionFormatErr, err) } - if major < _conmonMinMajorVersion { + if major < minMajor { return ErrConmonOutdated } - if major > _conmonMinMajorVersion { + if major > minMajor { return nil } - minor, err := strconv.Atoi(matches[2]) + minor, err := strconv.Atoi(matches[3]) if err != nil { return fmt.Errorf(_conmonVersionFormatErr, err) } - if minor < _conmonMinMinorVersion { + if minor < minMinor { return ErrConmonOutdated } - if minor > _conmonMinMinorVersion { + if minor > minMinor { return nil } - patch, err := strconv.Atoi(matches[3]) + patch, err := strconv.Atoi(matches[4]) if err != nil { return fmt.Errorf(_conmonVersionFormatErr, err) } - if patch < _conmonMinPatchVersion { + if patch < minPatch { return ErrConmonOutdated } - if patch > _conmonMinPatchVersion { + if patch > minPatch { return nil } diff --git a/vendor/github.com/containers/common/pkg/config/default_darwin.go b/vendor/github.com/containers/common/pkg/config/default_darwin.go index c502ea55e..5d857df4f 100644 --- a/vendor/github.com/containers/common/pkg/config/default_darwin.go +++ b/vendor/github.com/containers/common/pkg/config/default_darwin.go @@ -11,3 +11,8 @@ func getDefaultLockType() string { func getLibpodTmpDir() string { return "/run/libpod" } + +// getDefaultMachineVolumes returns default mounted volumes (possibly with env vars, which will be expanded) +func getDefaultMachineVolumes() []string { + return []string{"$HOME:$HOME"} +} diff --git a/vendor/github.com/containers/common/pkg/config/default_freebsd.go b/vendor/github.com/containers/common/pkg/config/default_freebsd.go index 8b10ac1f7..9c827dbfe 100644 --- a/vendor/github.com/containers/common/pkg/config/default_freebsd.go +++ b/vendor/github.com/containers/common/pkg/config/default_freebsd.go @@ -18,3 +18,8 @@ func getDefaultLockType() string { func getLibpodTmpDir() string { return "/var/run/libpod" } + +// getDefaultMachineVolumes returns default mounted volumes (possibly with env vars, which will be expanded) +func getDefaultMachineVolumes() []string { + return []string{"$HOME:$HOME"} +} diff --git a/vendor/github.com/containers/common/pkg/config/default_linux.go b/vendor/github.com/containers/common/pkg/config/default_linux.go index 86873beb1..15052c10e 100644 --- a/vendor/github.com/containers/common/pkg/config/default_linux.go +++ b/vendor/github.com/containers/common/pkg/config/default_linux.go @@ -70,3 +70,8 @@ func getDefaultLockType() string { func getLibpodTmpDir() string { return "/run/libpod" } + +// getDefaultMachineVolumes returns default mounted volumes (possibly with env vars, which will be expanded) +func getDefaultMachineVolumes() []string { + return []string{"$HOME:$HOME"} +} diff --git a/vendor/github.com/containers/common/pkg/config/default_windows.go b/vendor/github.com/containers/common/pkg/config/default_windows.go index 1ff88fc42..08a0bf223 100644 --- a/vendor/github.com/containers/common/pkg/config/default_windows.go +++ b/vendor/github.com/containers/common/pkg/config/default_windows.go @@ -44,3 +44,8 @@ func getDefaultLockType() string { func getLibpodTmpDir() string { return "/run/libpod" } + +// getDefaultMachineVolumes returns default mounted volumes (possibly with env vars, which will be expanded) +func getDefaultMachineVolumes() []string { + return []string{} +} diff --git a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go index ff82b5a39..02b6dfb09 100644 --- a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go +++ b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go @@ -372,7 +372,7 @@ func mountExists(mounts []rspec.Mount, dest string) bool { return false } -// resolveSymbolicLink resolves a possbile symlink path. If the path is a symlink, returns resolved +// resolveSymbolicLink resolves symlink paths. If the path is a symlink, returns resolved // path; if not, returns the original path. func resolveSymbolicLink(path string) (string, error) { info, err := os.Lstat(path) diff --git a/vendor/github.com/containers/psgo/go.mod b/vendor/github.com/containers/psgo/go.mod index 1489be7c3..6e55e8219 100644 --- a/vendor/github.com/containers/psgo/go.mod +++ b/vendor/github.com/containers/psgo/go.mod @@ -3,8 +3,8 @@ module github.com/containers/psgo go 1.14 require ( - github.com/containers/storage v1.38.0 - github.com/opencontainers/runc v1.1.0 - github.com/stretchr/testify v1.7.0 - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 + github.com/containers/storage v1.42.0 + github.com/opencontainers/runc v1.1.3 + github.com/stretchr/testify v1.8.0 + golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 ) diff --git a/vendor/github.com/containers/psgo/go.sum b/vendor/github.com/containers/psgo/go.sum index 71bfe7abe..60567abdf 100644 --- a/vendor/github.com/containers/psgo/go.sum +++ b/vendor/github.com/containers/psgo/go.sum @@ -36,7 +36,7 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935 github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= @@ -46,7 +46,7 @@ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugX github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -55,7 +55,7 @@ github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2 github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= -github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= @@ -172,7 +172,7 @@ github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFY github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= -github.com/containerd/stargz-snapshotter/estargz v0.10.1/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0= +github.com/containerd/stargz-snapshotter/estargz v0.12.0/go.mod h1:AIQ59TewBFJ4GOPEQXujcrJ/EKxh5xXZegW1rkR1P/M= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= @@ -196,8 +196,8 @@ github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRD github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= -github.com/containers/storage v1.38.0 h1:QTgqmtQeb2tk1VucK0nZwCJKmlVLZGybrMMMlixedFY= -github.com/containers/storage v1.38.0/go.mod h1:lBzt28gAk5ADZuRtwdndRJyqX22vnRaXmlF+7ktfMYc= +github.com/containers/storage v1.42.0 h1:zm2AQD4NDeTB3JQ8X+Wo5+VRqNB+b4ocEd7Qj6ylPJA= +github.com/containers/storage v1.42.0/go.mod h1:JiUJwOgOo1dr2DdOUc1MRe2GCAXABYoYmOdPF8yvH78= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= @@ -412,8 +412,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.14.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.7/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -451,8 +451,9 @@ github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQ github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -501,8 +502,8 @@ github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= -github.com/opencontainers/runc v1.1.0 h1:O9+X96OcDjkmmZyfaG996kV7yq8HsoU2h1XRRQcefG8= -github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= +github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -514,13 +515,13 @@ github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqi github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -562,7 +563,7 @@ github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiB github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= -github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= @@ -571,8 +572,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -595,14 +597,17 @@ github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -821,8 +826,10 @@ golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 h1:TyKJRhyo17yWxOMCTHKWrc5rddHORMlnZ/j57umaUd8= +golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -988,8 +995,9 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= diff --git a/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go b/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go index 1a60b96c4..9545ed57b 100644 --- a/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go +++ b/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go @@ -63,11 +63,14 @@ var ( 35: "WAKE_ALARM", 36: "BLOCK_SUSPEND", 37: "AUDIT_READ", + 38: "PERFMON", + 39: "BPF", + 40: "CHECKPOINT_RESTORE", } // FullCAPs represents the value of a bitmask with a full capability // set. - FullCAPs = uint64(0x3FFFFFFFFF) + FullCAPs = uint64(0x1FFFFFFFFFF) ) // TranslateMask iterates over mask and returns a slice of corresponding diff --git a/vendor/github.com/containers/psgo/internal/proc/stat.go b/vendor/github.com/containers/psgo/internal/proc/stat.go index e3286704c..5e0bafb2b 100644 --- a/vendor/github.com/containers/psgo/internal/proc/stat.go +++ b/vendor/github.com/containers/psgo/internal/proc/stat.go @@ -32,7 +32,7 @@ type Stat struct { // whether or not the executable is swapped out. Comm string // (3) The process state (e.g., running, sleeping, zombie, dead). - // Refer to proc(5) for further deatils. + // Refer to proc(5) for further details. State string // (4) The PID of the parent of this process. Ppid string diff --git a/vendor/github.com/vbauerster/mpb/v7/bar.go b/vendor/github.com/vbauerster/mpb/v7/bar.go index 4991f4f15..7db860e30 100644 --- a/vendor/github.com/vbauerster/mpb/v7/bar.go +++ b/vendor/github.com/vbauerster/mpb/v7/bar.go @@ -29,7 +29,7 @@ type Bar struct { recoveredPanic interface{} } -type extenderFunc func(in io.Reader, reqWidth int, st decor.Statistics) (out io.Reader, lines int) +type extenderFunc func(rows []io.Reader, width int, stat decor.Statistics) []io.Reader // bState is actual bar's state. type bState struct { @@ -57,14 +57,15 @@ type bState struct { extender extenderFunc debugOut io.Writer - afterBar *Bar // key for (*pState).queueBars - sync bool + wait struct { + bar *Bar // key for (*pState).queueBars + sync bool + } } type renderFrame struct { - reader io.Reader - lines int - shutdown bool + rows []io.Reader + shutdown int } func newBar(container *Progress, bs *bState) *Bar { @@ -339,8 +340,8 @@ func (b *Bar) Wait() { func (b *Bar) serve(ctx context.Context, bs *bState) { defer b.container.bwg.Done() - if bs.afterBar != nil && bs.sync { - bs.afterBar.Wait() + if bs.wait.bar != nil && bs.wait.sync { + bs.wait.bar.Wait() } for { select { @@ -359,48 +360,58 @@ func (b *Bar) serve(ctx context.Context, bs *bState) { func (b *Bar) render(tw int) { select { case b.operateState <- func(s *bState) { - var reader io.Reader - var lines int + var rows []io.Reader stat := newStatistics(tw, s) defer func() { // recovering if user defined decorator panics for example if p := recover(); p != nil { if s.debugOut != nil { - fmt.Fprintln(s.debugOut, p) - _, _ = s.debugOut.Write(debug.Stack()) + for _, fn := range []func() (int, error){ + func() (int, error) { + return fmt.Fprintln(s.debugOut, p) + }, + func() (int, error) { + return s.debugOut.Write(debug.Stack()) + }, + } { + if _, err := fn(); err != nil { + panic(err) + } + } } s.aborted = !s.completed s.extender = makePanicExtender(p) - reader, lines = s.extender(nil, s.reqWidth, stat) b.recoveredPanic = p } - frame := renderFrame{ - reader: reader, - lines: lines + 1, - shutdown: s.completed || s.aborted, + if fn := s.extender; fn != nil { + rows = fn(rows, s.reqWidth, stat) + } + frame := &renderFrame{ + rows: rows, } - if frame.shutdown { + if s.completed || s.aborted { b.cancel() + frame.shutdown++ } - b.frameCh <- &frame + b.frameCh <- frame }() if b.recoveredPanic == nil { - reader = s.draw(stat) + rows = append(rows, s.draw(stat)) } - reader, lines = s.extender(reader, s.reqWidth, stat) }: case <-b.done: - var reader io.Reader - var lines int - stat, s := newStatistics(tw, b.bs), b.bs + var rows []io.Reader + s, stat := b.bs, newStatistics(tw, b.bs) if b.recoveredPanic == nil { - reader = s.draw(stat) + rows = append(rows, s.draw(stat)) + } + if fn := s.extender; fn != nil { + rows = fn(rows, s.reqWidth, stat) } - reader, lines = s.extender(reader, s.reqWidth, stat) - b.frameCh <- &renderFrame{ - reader: reader, - lines: lines + 1, + frame := &renderFrame{ + rows: rows, } + b.frameCh <- frame } } @@ -446,7 +457,7 @@ func (b *Bar) wSyncTable() [][]chan int { func (s *bState) draw(stat decor.Statistics) io.Reader { bufP, bufB, bufA := s.buffers[0], s.buffers[1], s.buffers[2] - nlr := strings.NewReader("\n") + nlr := bytes.NewReader([]byte("\n")) tw := stat.AvailableWidth for _, d := range s.pDecorators { str := d.Decor(stat) @@ -596,11 +607,11 @@ func extractBaseDecorator(d decor.Decorator) decor.Decorator { func makePanicExtender(p interface{}) extenderFunc { pstr := fmt.Sprint(p) - return func(_ io.Reader, _ int, st decor.Statistics) (io.Reader, int) { - mr := io.MultiReader( - strings.NewReader(runewidth.Truncate(pstr, st.AvailableWidth, "…")), - strings.NewReader("\n"), + return func(rows []io.Reader, _ int, stat decor.Statistics) []io.Reader { + r := io.MultiReader( + strings.NewReader(runewidth.Truncate(pstr, stat.AvailableWidth, "…")), + bytes.NewReader([]byte("\n")), ) - return mr, 0 + return append(rows, r) } } diff --git a/vendor/github.com/vbauerster/mpb/v7/bar_option.go b/vendor/github.com/vbauerster/mpb/v7/bar_option.go index 8599f0a57..3506ed2f1 100644 --- a/vendor/github.com/vbauerster/mpb/v7/bar_option.go +++ b/vendor/github.com/vbauerster/mpb/v7/bar_option.go @@ -60,6 +60,7 @@ func BarWidth(width int) BarOption { } // BarQueueAfter puts this (being constructed) bar into the queue. +// BarPriority will be inherited from the argument bar. // When argument bar completes or aborts queued bar replaces its place. // If sync is true queued bar is suspended until argument bar completes // or aborts. @@ -68,8 +69,8 @@ func BarQueueAfter(bar *Bar, sync bool) BarOption { return nil } return func(s *bState) { - s.afterBar = bar - s.sync = sync + s.wait.bar = bar + s.wait.sync = sync } } @@ -111,29 +112,61 @@ func BarFillerMiddleware(middle func(BarFiller) BarFiller) BarOption { } // BarPriority sets bar's priority. Zero is highest priority, i.e. bar -// will be on top. If `BarReplaceOnComplete` option is supplied, this -// option is ignored. +// will be on top. This option isn't effective with `BarQueueAfter` option. func BarPriority(priority int) BarOption { return func(s *bState) { s.priority = priority } } -// BarExtender provides a way to extend bar to the next new line. +// BarExtender extends bar with arbitrary lines. Provided BarFiller will be +// called at each render/flush cycle. Any lines written to the underlying +// io.Writer will be printed after the bar itself. func BarExtender(filler BarFiller) BarOption { + return barExtender(filler, false) +} + +// BarExtenderRev extends bar with arbitrary lines in reverse order. Provided +// BarFiller will be called at each render/flush cycle. Any lines written +// to the underlying io.Writer will be printed before the bar itself. +func BarExtenderRev(filler BarFiller) BarOption { + return barExtender(filler, true) +} + +func barExtender(filler BarFiller, rev bool) BarOption { if filler == nil { return nil } return func(s *bState) { - s.extender = makeExtenderFunc(filler) + s.extender = makeExtenderFunc(filler, rev) } } -func makeExtenderFunc(filler BarFiller) extenderFunc { +func makeExtenderFunc(filler BarFiller, rev bool) extenderFunc { buf := new(bytes.Buffer) - return func(r io.Reader, reqWidth int, st decor.Statistics) (io.Reader, int) { - filler.Fill(buf, reqWidth, st) - return io.MultiReader(r, buf), bytes.Count(buf.Bytes(), []byte("\n")) + base := func(rows []io.Reader, width int, stat decor.Statistics) []io.Reader { + buf.Reset() + filler.Fill(buf, width, stat) + for { + b, err := buf.ReadBytes('\n') + if err != nil { + break + } + rows = append(rows, bytes.NewReader(b)) + } + return rows + } + + if !rev { + return base + } else { + return func(rows []io.Reader, width int, stat decor.Statistics) []io.Reader { + rows = base(rows, width, stat) + for left, right := 0, len(rows)-1; left < right; left, right = left+1, right-1 { + rows[left], rows[right] = rows[right], rows[left] + } + return rows + } } } diff --git a/vendor/github.com/vbauerster/mpb/v7/container_option.go b/vendor/github.com/vbauerster/mpb/v7/container_option.go index e523a1759..bfaa3286a 100644 --- a/vendor/github.com/vbauerster/mpb/v7/container_option.go +++ b/vendor/github.com/vbauerster/mpb/v7/container_option.go @@ -31,7 +31,7 @@ func WithWidth(width int) ContainerOption { } } -// WithRefreshRate overrides default 120ms refresh rate. +// WithRefreshRate overrides default 150ms refresh rate. func WithRefreshRate(d time.Duration) ContainerOption { return func(s *pState) { s.rr = d diff --git a/vendor/github.com/vbauerster/mpb/v7/cwriter/writer.go b/vendor/github.com/vbauerster/mpb/v7/cwriter/writer.go index fac15b3bc..19fd90e94 100644 --- a/vendor/github.com/vbauerster/mpb/v7/cwriter/writer.go +++ b/vendor/github.com/vbauerster/mpb/v7/cwriter/writer.go @@ -20,19 +20,30 @@ const ( // Writer is a buffered the writer that updates the terminal. The // contents of writer will be flushed when Flush is called. type Writer struct { - out io.Writer - buf bytes.Buffer - lines int - fd int - isTerminal bool + out io.Writer + buf bytes.Buffer + lines int // how much lines to clear before flushing new ones + fd int + terminal bool + termSize func(int) (int, int, error) } // New returns a new Writer with defaults. func New(out io.Writer) *Writer { - w := &Writer{out: out} + w := &Writer{ + out: out, + termSize: func(_ int) (int, int, error) { + return -1, -1, ErrNotTTY + }, + } if f, ok := out.(*os.File); ok { w.fd = int(f.Fd()) - w.isTerminal = IsTerminal(w.fd) + if IsTerminal(w.fd) { + w.terminal = true + w.termSize = func(fd int) (int, int, error) { + return GetSize(fd) + } + } } return w } @@ -67,13 +78,9 @@ func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) { return w.buf.ReadFrom(r) } -// GetWidth returns width of underlying terminal. -func (w *Writer) GetWidth() (int, error) { - if !w.isTerminal { - return -1, ErrNotTTY - } - tw, _, err := GetSize(w.fd) - return tw, err +// GetTermSize returns WxH of underlying terminal. +func (w *Writer) GetTermSize() (width, height int, err error) { + return w.termSize(w.fd) } func (w *Writer) ansiCuuAndEd() error { diff --git a/vendor/github.com/vbauerster/mpb/v7/cwriter/writer_windows.go b/vendor/github.com/vbauerster/mpb/v7/cwriter/writer_windows.go index 8f99dbe32..2c4c3707b 100644 --- a/vendor/github.com/vbauerster/mpb/v7/cwriter/writer_windows.go +++ b/vendor/github.com/vbauerster/mpb/v7/cwriter/writer_windows.go @@ -16,7 +16,7 @@ var ( ) func (w *Writer) clearLines() error { - if !w.isTerminal { + if !w.terminal { // hope it's cygwin or similar return w.ansiCuuAndEd() } diff --git a/vendor/github.com/vbauerster/mpb/v7/decor/on_condition.go b/vendor/github.com/vbauerster/mpb/v7/decor/on_condition.go index a9db0653a..74a3d9667 100644 --- a/vendor/github.com/vbauerster/mpb/v7/decor/on_condition.go +++ b/vendor/github.com/vbauerster/mpb/v7/decor/on_condition.go @@ -1,27 +1,55 @@ package decor -// OnPredicate returns decorator if predicate evaluates to true. +// OnCondition applies decorator only if a condition is true. // // `decorator` Decorator // -// `predicate` func() bool +// `cond` bool // -func OnPredicate(decorator Decorator, predicate func() bool) Decorator { - if predicate() { - return decorator - } - return nil +func OnCondition(decorator Decorator, cond bool) Decorator { + return Conditional(cond, decorator, nil) } -// OnCondition returns decorator if condition is true. +// OnPredicate applies decorator only if a predicate evaluates to true. // // `decorator` Decorator // +// `predicate` func() bool +// +func OnPredicate(decorator Decorator, predicate func() bool) Decorator { + return Predicative(predicate, decorator, nil) +} + +// Conditional returns decorator `a` if condition is true, otherwise +// decorator `b`. +// // `cond` bool // -func OnCondition(decorator Decorator, cond bool) Decorator { +// `a` Decorator +// +// `b` Decorator +// +func Conditional(cond bool, a, b Decorator) Decorator { if cond { - return decorator + return a + } else { + return b + } +} + +// Predicative returns decorator `a` if predicate evaluates to true, +// otherwise decorator `b`. +// +// `predicate` func() bool +// +// `a` Decorator +// +// `b` Decorator +// +func Predicative(predicate func() bool, a, b Decorator) Decorator { + if predicate() { + return a + } else { + return b } - return nil } diff --git a/vendor/github.com/vbauerster/mpb/v7/priority_queue.go b/vendor/github.com/vbauerster/mpb/v7/priority_queue.go index 29d9bd5a8..152482e9a 100644 --- a/vendor/github.com/vbauerster/mpb/v7/priority_queue.go +++ b/vendor/github.com/vbauerster/mpb/v7/priority_queue.go @@ -6,7 +6,8 @@ type priorityQueue []*Bar func (pq priorityQueue) Len() int { return len(pq) } func (pq priorityQueue) Less(i, j int) bool { - return pq[i].priority < pq[j].priority + // less priority pops first + return pq[i].priority > pq[j].priority } func (pq priorityQueue) Swap(i, j int) { diff --git a/vendor/github.com/vbauerster/mpb/v7/progress.go b/vendor/github.com/vbauerster/mpb/v7/progress.go index 1d9a53e5c..ea5a0c15e 100644 --- a/vendor/github.com/vbauerster/mpb/v7/progress.go +++ b/vendor/github.com/vbauerster/mpb/v7/progress.go @@ -12,7 +12,6 @@ import ( "time" "github.com/vbauerster/mpb/v7/cwriter" - "github.com/vbauerster/mpb/v7/decor" ) const ( @@ -41,6 +40,7 @@ type pState struct { // following are provided/overrided by user idCount int reqWidth int + popPriority int popCompleted bool outputDiscarded bool rr time.Duration @@ -64,10 +64,11 @@ func New(options ...ContainerOption) *Progress { // method has been called. func NewWithContext(ctx context.Context, options ...ContainerOption) *Progress { s := &pState{ - bHeap: priorityQueue{}, - rr: prr, - queueBars: make(map[*Bar]*Bar), - output: os.Stdout, + bHeap: priorityQueue{}, + rr: prr, + queueBars: make(map[*Bar]*Bar), + output: os.Stdout, + popPriority: math.MinInt32, } for _, opt := range options { @@ -118,8 +119,8 @@ func (p *Progress) Add(total int64, filler BarFiller, options ...BarOption) *Bar case p.operateState <- func(ps *pState) { bs := ps.makeBarState(total, filler, options...) bar := newBar(p, bs) - if bs.afterBar != nil { - ps.queueBars[bs.afterBar] = bar + if bs.wait.bar != nil { + ps.queueBars[bs.wait.bar] = bar } else { heap.Push(&ps.bHeap, bar) ps.heapUpdated = true @@ -204,33 +205,27 @@ func (p *Progress) serve(s *pState, cw *cwriter.Writer) { p.refreshCh = s.newTicker(p.done) + render := func(debugOut io.Writer) { + err := s.render(cw) + for err != nil { + if debugOut != nil { + _, err = fmt.Fprintln(debugOut, err) + } else { + panic(err) + } + debugOut = nil + } + } + for { select { case op := <-p.operateState: op(s) case <-p.refreshCh: - if err := s.render(cw); err != nil { - if s.debugOut != nil { - _, e := fmt.Fprintln(s.debugOut, err) - if e != nil { - panic(err) - } - } else { - panic(err) - } - } + render(s.debugOut) case <-s.shutdownNotifier: for s.heapUpdated { - if err := s.render(cw); err != nil { - if s.debugOut != nil { - _, e := fmt.Fprintln(s.debugOut, err) - if e != nil { - panic(err) - } - } else { - panic(err) - } - } + render(s.debugOut) } return } @@ -245,42 +240,52 @@ func (s *pState) render(cw *cwriter.Writer) error { syncWidth(s.pMatrix) syncWidth(s.aMatrix) - tw, err := cw.GetWidth() + width, height, err := cw.GetTermSize() if err != nil { - tw = s.reqWidth + width = s.reqWidth + height = s.bHeap.Len() } for i := 0; i < s.bHeap.Len(); i++ { bar := s.bHeap[i] - go bar.render(tw) + go bar.render(width) } - return s.flush(cw) + return s.flush(cw, height) } -func (s *pState) flush(cw *cwriter.Writer) error { - var lines int +func (s *pState) flush(cw *cwriter.Writer, height int) error { + var popCount int + rows := make([]io.Reader, 0, height) pool := make([]*Bar, 0, s.bHeap.Len()) for s.bHeap.Len() > 0 { + var frameRowsUsed int b := heap.Pop(&s.bHeap).(*Bar) frame := <-b.frameCh - lines += frame.lines - _, err := cw.ReadFrom(frame.reader) - if err != nil { - return err + for i := len(frame.rows) - 1; i >= 0; i-- { + if len(rows) == height { + break + } + rows = append(rows, frame.rows[i]) + frameRowsUsed++ } - if frame.shutdown { + if frame.shutdown != 0 { b.Wait() // waiting for b.done, so it's safe to read b.bs - var toDrop bool + drop := b.bs.dropOnComplete if qb, ok := s.queueBars[b]; ok { delete(s.queueBars, b) qb.priority = b.priority pool = append(pool, qb) - toDrop = true + drop = true } else if s.popCompleted && !b.bs.noPop { - lines -= frame.lines - toDrop = true + if frame.shutdown > 1 { + popCount += frameRowsUsed + drop = true + } else { + s.popPriority++ + b.priority = s.popPriority + } } - if toDrop || b.bs.dropOnComplete { + if drop { s.heapUpdated = true continue } @@ -292,7 +297,14 @@ func (s *pState) flush(cw *cwriter.Writer) error { heap.Push(&s.bHeap, b) } - return cw.Flush(lines) + for i := len(rows) - 1; i >= 0; i-- { + _, err := cw.ReadFrom(rows[i]) + if err != nil { + return err + } + } + + return cw.Flush(len(rows) - popCount) } func (s *pState) newTicker(done <-chan struct{}) chan time.Time { @@ -358,7 +370,6 @@ func (s *pState) makeBarState(total int64, filler BarFiller, options ...BarOptio reqWidth: s.reqWidth, total: total, filler: filler, - extender: func(r io.Reader, _ int, _ decor.Statistics) (io.Reader, int) { return r, 0 }, debugOut: s.debugOut, } @@ -377,10 +388,6 @@ func (s *pState) makeBarState(total int64, filler BarFiller, options ...BarOptio bs.middleware = nil } - if s.popCompleted && !bs.noPop { - bs.priority = -(math.MaxInt32 - s.idCount) - } - for i := 0; i < len(bs.buffers); i++ { bs.buffers[i] = bytes.NewBuffer(make([]byte, 0, 512)) } diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_arm64.go index bbaba18bc..f3eb993bf 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_arm64.go +++ b/vendor/golang.org/x/sys/cpu/cpu_arm64.go @@ -6,7 +6,10 @@ package cpu import "runtime" -const cacheLineSize = 64 +// cacheLineSize is used to prevent false sharing of cache lines. +// We choose 128 because Apple Silicon, a.k.a. M1, has 128-byte cache line size. +// It doesn't cost much and is much more future-proof. +const cacheLineSize = 128 func initOptions() { options = []option{ diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh index 6fc18353d..3b2335d5f 100644 --- a/vendor/golang.org/x/sys/unix/mkall.sh +++ b/vendor/golang.org/x/sys/unix/mkall.sh @@ -156,10 +156,10 @@ openbsd_amd64) mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; openbsd_arm) + mkasm="go run mkasm.go" mkerrors="$mkerrors" - mksyscall="go run mksyscall.go -l32 -openbsd -arm" + mksyscall="go run mksyscall.go -l32 -openbsd -arm -libc" mksysctl="go run mksysctl_openbsd.go" - mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'" # Let the type of C char be signed for making the bare syscall # API consistent across platforms. mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd_libc.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_libc.go index e23c33de6..5930a8972 100644 --- a/vendor/golang.org/x/sys/unix/syscall_openbsd_libc.go +++ b/vendor/golang.org/x/sys/unix/syscall_openbsd_libc.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm64 +//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) +// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 package unix diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go index 69f803006..8da6791d1 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -l32 -openbsd -arm -tags openbsd,arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go +// go run mksyscall.go -l32 -openbsd -arm -libc -tags openbsd,arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build openbsd && arm @@ -16,7 +16,7 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + r0, _, e1 := syscall_rawSyscall(libc_getgroups_trampoline_addr, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -24,20 +24,28 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) { return } +var libc_getgroups_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getgroups getgroups "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + _, _, e1 := syscall_rawSyscall(libc_setgroups_trampoline_addr, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setgroups_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setgroups setgroups "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + r0, _, e1 := syscall_syscall6(libc_wait4_trampoline_addr, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) wpid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -45,10 +53,14 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err return } +var libc_wait4_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_wait4 wait4 "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r0, _, e1 := syscall_syscall(libc_accept_trampoline_addr, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -56,30 +68,42 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { return } +var libc_accept_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_accept accept "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(libc_bind_trampoline_addr, uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_bind_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_bind bind "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(libc_connect_trampoline_addr, uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_connect_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_connect connect "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + r0, _, e1 := syscall_rawSyscall(libc_socket_trampoline_addr, uintptr(domain), uintptr(typ), uintptr(proto)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -87,66 +111,94 @@ func socket(domain int, typ int, proto int) (fd int, err error) { return } +var libc_socket_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_socket socket "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + _, _, e1 := syscall_syscall6(libc_getsockopt_trampoline_addr, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_getsockopt_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getsockopt getsockopt "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + _, _, e1 := syscall_syscall6(libc_setsockopt_trampoline_addr, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setsockopt_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setsockopt setsockopt "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(libc_getpeername_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +var libc_getpeername_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getpeername getpeername "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(libc_getsockname_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +var libc_getsockname_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getsockname getsockname "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Shutdown(s int, how int) (err error) { - _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + _, _, e1 := syscall_syscall(libc_shutdown_trampoline_addr, uintptr(s), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_shutdown_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_shutdown shutdown "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + _, _, e1 := syscall_rawSyscall6(libc_socketpair_trampoline_addr, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_socketpair_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_socketpair socketpair "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { @@ -156,7 +208,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + r0, _, e1 := syscall_syscall6(libc_recvfrom_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -164,6 +216,10 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl return } +var libc_recvfrom_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_recvfrom recvfrom "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { @@ -173,17 +229,21 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) ( } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + _, _, e1 := syscall_syscall6(libc_sendto_trampoline_addr, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_sendto_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_sendto sendto "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(libc_recvmsg_trampoline_addr, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -191,10 +251,14 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +var libc_recvmsg_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_recvmsg recvmsg "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(libc_sendmsg_trampoline_addr, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -202,10 +266,14 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +var libc_sendmsg_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_sendmsg sendmsg "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + r0, _, e1 := syscall_syscall6(libc_kevent_trampoline_addr, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -213,6 +281,10 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne return } +var libc_kevent_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_kevent kevent "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func utimes(path string, timeval *[2]Timeval) (err error) { @@ -221,27 +293,35 @@ func utimes(path string, timeval *[2]Timeval) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(libc_utimes_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_utimes_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_utimes utimes "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(libc_futimes_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_futimes_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_futimes futimes "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { - r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + r0, _, e1 := syscall_syscall(libc_poll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -249,6 +329,10 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { return } +var libc_poll_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_poll poll "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Madvise(b []byte, behav int) (err error) { @@ -258,13 +342,17 @@ func Madvise(b []byte, behav int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + _, _, e1 := syscall_syscall(libc_madvise_trampoline_addr, uintptr(_p0), uintptr(len(b)), uintptr(behav)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_madvise_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_madvise madvise "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlock(b []byte) (err error) { @@ -274,23 +362,31 @@ func Mlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(libc_mlock_trampoline_addr, uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_mlock_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mlock mlock "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlockall(flags int) (err error) { - _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall(libc_mlockall_trampoline_addr, uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_mlockall_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mlockall mlockall "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mprotect(b []byte, prot int) (err error) { @@ -300,13 +396,17 @@ func Mprotect(b []byte, prot int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + _, _, e1 := syscall_syscall(libc_mprotect_trampoline_addr, uintptr(_p0), uintptr(len(b)), uintptr(prot)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_mprotect_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mprotect mprotect "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Msync(b []byte, flags int) (err error) { @@ -316,13 +416,17 @@ func Msync(b []byte, flags int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + _, _, e1 := syscall_syscall(libc_msync_trampoline_addr, uintptr(_p0), uintptr(len(b)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_msync_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_msync msync "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlock(b []byte) (err error) { @@ -332,33 +436,45 @@ func Munlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(libc_munlock_trampoline_addr, uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_munlock_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_munlock munlock "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlockall() (err error) { - _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + _, _, e1 := syscall_syscall(libc_munlockall_trampoline_addr, 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_munlockall_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_munlockall munlockall "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pipe2(p *[2]_C_int, flags int) (err error) { - _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + _, _, e1 := syscall_rawSyscall(libc_pipe2_trampoline_addr, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_pipe2_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pipe2 pipe2 "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getdents(fd int, buf []byte) (n int, err error) { @@ -368,7 +484,7 @@ func Getdents(fd int, buf []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf))) + r0, _, e1 := syscall_syscall(libc_getdents_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -376,6 +492,10 @@ func Getdents(fd int, buf []byte) (n int, err error) { return } +var libc_getdents_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getdents getdents "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getcwd(buf []byte) (n int, err error) { @@ -385,7 +505,7 @@ func Getcwd(buf []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + r0, _, e1 := syscall_syscall(libc_getcwd_trampoline_addr, uintptr(_p0), uintptr(len(buf)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -393,16 +513,24 @@ func Getcwd(buf []byte) (n int, err error) { return } +var libc_getcwd_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getcwd getcwd "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ioctl(fd int, req uint, arg uintptr) (err error) { - _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_ioctl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_ioctl ioctl "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { @@ -412,17 +540,21 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + _, _, e1 := syscall_syscall6(libc_sysctl_trampoline_addr, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_sysctl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_sysctl sysctl "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { - r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) + r0, _, e1 := syscall_syscall6(libc_ppoll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -430,6 +562,10 @@ func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, return } +var libc_ppoll_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_ppoll ppoll "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Access(path string, mode uint32) (err error) { @@ -438,23 +574,31 @@ func Access(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_access_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_access_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_access access "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + _, _, e1 := syscall_syscall(libc_adjtime_trampoline_addr, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_adjtime_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_adjtime adjtime "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chdir(path string) (err error) { @@ -463,13 +607,17 @@ func Chdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_chdir_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_chdir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_chdir chdir "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chflags(path string, flags int) (err error) { @@ -478,13 +626,17 @@ func Chflags(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(libc_chflags_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_chflags_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_chflags chflags "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chmod(path string, mode uint32) (err error) { @@ -493,13 +645,17 @@ func Chmod(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_chmod_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_chmod_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_chmod chmod "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chown(path string, uid int, gid int) (err error) { @@ -508,13 +664,17 @@ func Chown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(libc_chown_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_chown_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_chown chown "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chroot(path string) (err error) { @@ -523,27 +683,35 @@ func Chroot(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_chroot_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_chroot_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_chroot chroot "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Close(fd int) (err error) { - _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(libc_close_trampoline_addr, uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_close_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_close close "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup(fd int) (nfd int, err error) { - r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + r0, _, e1 := syscall_syscall(libc_dup_trampoline_addr, uintptr(fd), 0, 0) nfd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -551,33 +719,49 @@ func Dup(fd int) (nfd int, err error) { return } +var libc_dup_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_dup dup "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup2(from int, to int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + _, _, e1 := syscall_syscall(libc_dup2_trampoline_addr, uintptr(from), uintptr(to), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_dup2_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_dup2 dup2 "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup3(from int, to int, flags int) (err error) { - _, _, e1 := Syscall(SYS_DUP3, uintptr(from), uintptr(to), uintptr(flags)) + _, _, e1 := syscall_syscall(libc_dup3_trampoline_addr, uintptr(from), uintptr(to), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_dup3_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_dup3 dup3 "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT, uintptr(code), 0, 0) + syscall_syscall(libc_exit_trampoline_addr, uintptr(code), 0, 0) return } +var libc_exit_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_exit exit "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -586,43 +770,59 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_faccessat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_faccessat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_faccessat faccessat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchdir(fd int) (err error) { - _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(libc_fchdir_trampoline_addr, uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fchdir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fchdir fchdir "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchflags(fd int, flags int) (err error) { - _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + _, _, e1 := syscall_syscall(libc_fchflags_trampoline_addr, uintptr(fd), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fchflags_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fchflags fchflags "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_fchmod_trampoline_addr, uintptr(fd), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fchmod_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fchmod fchmod "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -631,23 +831,31 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_fchmodat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fchmodat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fchmodat fchmodat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(libc_fchown_trampoline_addr, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fchown_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fchown fchown "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { @@ -656,27 +864,35 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(libc_fchownat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fchownat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fchownat fchownat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Flock(fd int, how int) (err error) { - _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + _, _, e1 := syscall_syscall(libc_flock_trampoline_addr, uintptr(fd), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_flock_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_flock flock "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + r0, _, e1 := syscall_syscall(libc_fpathconf_trampoline_addr, uintptr(fd), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -684,16 +900,24 @@ func Fpathconf(fd int, name int) (val int, err error) { return } +var libc_fpathconf_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fpathconf fpathconf "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_fstat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fstat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fstat fstat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { @@ -702,71 +926,99 @@ func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_fstatat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fstatat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fstatat fstatat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_fstatfs_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fstatfs_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fstatfs fstatfs "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fsync(fd int) (err error) { - _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(libc_fsync_trampoline_addr, uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_fsync_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fsync fsync "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0) + _, _, e1 := syscall_syscall6(libc_ftruncate_trampoline_addr, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_ftruncate_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_ftruncate ftruncate "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getegid_trampoline_addr, 0, 0, 0) egid = int(r0) return } +var libc_getegid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getegid getegid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_geteuid_trampoline_addr, 0, 0, 0) uid = int(r0) return } +var libc_geteuid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_geteuid geteuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getgid_trampoline_addr, 0, 0, 0) gid = int(r0) return } +var libc_getgid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getgid getgid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_getpgid_trampoline_addr, uintptr(pid), 0, 0) pgid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -774,34 +1026,50 @@ func Getpgid(pid int) (pgid int, err error) { return } +var libc_getpgid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getpgid getpgid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgrp() (pgrp int) { - r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getpgrp_trampoline_addr, 0, 0, 0) pgrp = int(r0) return } +var libc_getpgrp_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getpgrp getpgrp "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getpid_trampoline_addr, 0, 0, 0) pid = int(r0) return } +var libc_getpid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getpid getpid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getppid_trampoline_addr, 0, 0, 0) ppid = int(r0) return } +var libc_getppid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getppid getppid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + r0, _, e1 := syscall_syscall(libc_getpriority_trampoline_addr, uintptr(which), uintptr(who), 0) prio = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -809,20 +1077,28 @@ func Getpriority(which int, who int) (prio int, err error) { return } +var libc_getpriority_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getpriority getpriority "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(libc_getrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_getrlimit_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getrlimit getrlimit "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrtable() (rtable int, err error) { - r0, _, e1 := RawSyscall(SYS_GETRTABLE, 0, 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_getrtable_trampoline_addr, 0, 0, 0) rtable = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -830,20 +1106,28 @@ func Getrtable() (rtable int, err error) { return } +var libc_getrtable_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getrtable getrtable "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + _, _, e1 := syscall_rawSyscall(libc_getrusage_trampoline_addr, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_getrusage_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getrusage getrusage "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getsid(pid int) (sid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_getsid_trampoline_addr, uintptr(pid), 0, 0) sid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -851,46 +1135,66 @@ func Getsid(pid int) (sid int, err error) { return } +var libc_getsid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getsid getsid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettimeofday(tv *Timeval) (err error) { - _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_gettimeofday_trampoline_addr, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_gettimeofday_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_gettimeofday gettimeofday "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getuid_trampoline_addr, 0, 0, 0) uid = int(r0) return } +var libc_getuid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_getuid getuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Issetugid() (tainted bool) { - r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0) + r0, _, _ := syscall_syscall(libc_issetugid_trampoline_addr, 0, 0, 0) tainted = bool(r0 != 0) return } +var libc_issetugid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_issetugid issetugid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kill(pid int, signum syscall.Signal) (err error) { - _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0) + _, _, e1 := syscall_syscall(libc_kill_trampoline_addr, uintptr(pid), uintptr(signum), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_kill_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_kill kill "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kqueue() (fd int, err error) { - r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + r0, _, e1 := syscall_syscall(libc_kqueue_trampoline_addr, 0, 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -898,6 +1202,10 @@ func Kqueue() (fd int, err error) { return } +var libc_kqueue_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_kqueue kqueue "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Lchown(path string, uid int, gid int) (err error) { @@ -906,13 +1214,17 @@ func Lchown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(libc_lchown_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_lchown_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_lchown lchown "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Link(path string, link string) (err error) { @@ -926,13 +1238,17 @@ func Link(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(libc_link_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_link_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_link link "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { @@ -946,23 +1262,31 @@ func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err er if err != nil { return } - _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(libc_linkat_trampoline_addr, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_linkat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_linkat linkat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Listen(s int, backlog int) (err error) { - _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + _, _, e1 := syscall_syscall(libc_listen_trampoline_addr, uintptr(s), uintptr(backlog), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_listen_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_listen listen "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Lstat(path string, stat *Stat_t) (err error) { @@ -971,13 +1295,17 @@ func Lstat(path string, stat *Stat_t) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_lstat_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_lstat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_lstat lstat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkdir(path string, mode uint32) (err error) { @@ -986,13 +1314,17 @@ func Mkdir(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_mkdir_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_mkdir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mkdir mkdir "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkdirat(dirfd int, path string, mode uint32) (err error) { @@ -1001,13 +1333,17 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + _, _, e1 := syscall_syscall(libc_mkdirat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_mkdirat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mkdirat mkdirat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkfifo(path string, mode uint32) (err error) { @@ -1016,13 +1352,17 @@ func Mkfifo(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_mkfifo_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_mkfifo_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mkfifo mkfifo "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkfifoat(dirfd int, path string, mode uint32) (err error) { @@ -1031,13 +1371,17 @@ func Mkfifoat(dirfd int, path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKFIFOAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + _, _, e1 := syscall_syscall(libc_mkfifoat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_mkfifoat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mkfifoat mkfifoat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mknod(path string, mode uint32, dev int) (err error) { @@ -1046,13 +1390,17 @@ func Mknod(path string, mode uint32, dev int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + _, _, e1 := syscall_syscall(libc_mknod_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_mknod_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mknod mknod "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { @@ -1061,23 +1409,31 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + _, _, e1 := syscall_syscall6(libc_mknodat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_mknodat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mknodat mknodat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Nanosleep(time *Timespec, leftover *Timespec) (err error) { - _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) + _, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_nanosleep_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_nanosleep nanosleep "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Open(path string, mode int, perm uint32) (fd int, err error) { @@ -1086,7 +1442,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + r0, _, e1 := syscall_syscall(libc_open_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1094,6 +1450,10 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } +var libc_open_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_open open "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { @@ -1102,7 +1462,7 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + r0, _, e1 := syscall_syscall6(libc_openat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1110,6 +1470,10 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { return } +var libc_openat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_openat openat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pathconf(path string, name int) (val int, err error) { @@ -1118,7 +1482,7 @@ func Pathconf(path string, name int) (val int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + r0, _, e1 := syscall_syscall(libc_pathconf_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1126,6 +1490,10 @@ func Pathconf(path string, name int) (val int, err error) { return } +var libc_pathconf_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pathconf pathconf "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pread(fd int, p []byte, offset int64) (n int, err error) { @@ -1135,7 +1503,7 @@ func pread(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) + r0, _, e1 := syscall_syscall6(libc_pread_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1143,6 +1511,10 @@ func pread(fd int, p []byte, offset int64) (n int, err error) { return } +var libc_pread_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pread pread "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pwrite(fd int, p []byte, offset int64) (n int, err error) { @@ -1152,7 +1524,7 @@ func pwrite(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) + r0, _, e1 := syscall_syscall6(libc_pwrite_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1160,6 +1532,10 @@ func pwrite(fd int, p []byte, offset int64) (n int, err error) { return } +var libc_pwrite_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pwrite pwrite "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func read(fd int, p []byte) (n int, err error) { @@ -1169,7 +1545,7 @@ func read(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(libc_read_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1177,6 +1553,10 @@ func read(fd int, p []byte) (n int, err error) { return } +var libc_read_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_read read "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlink(path string, buf []byte) (n int, err error) { @@ -1191,7 +1571,7 @@ func Readlink(path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + r0, _, e1 := syscall_syscall(libc_readlink_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1199,6 +1579,10 @@ func Readlink(path string, buf []byte) (n int, err error) { return } +var libc_readlink_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readlink readlink "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { @@ -1213,7 +1597,7 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + r0, _, e1 := syscall_syscall6(libc_readlinkat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1221,6 +1605,10 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { return } +var libc_readlinkat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readlinkat readlinkat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rename(from string, to string) (err error) { @@ -1234,13 +1622,17 @@ func Rename(from string, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(libc_rename_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_rename_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_rename rename "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Renameat(fromfd int, from string, tofd int, to string) (err error) { @@ -1254,13 +1646,17 @@ func Renameat(fromfd int, from string, tofd int, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := syscall_syscall6(libc_renameat_trampoline_addr, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_renameat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_renameat renameat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Revoke(path string) (err error) { @@ -1269,13 +1665,17 @@ func Revoke(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_revoke_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_revoke_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_revoke revoke "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rmdir(path string) (err error) { @@ -1284,17 +1684,21 @@ func Rmdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_rmdir_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_rmdir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_rmdir rmdir "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0) + r0, r1, e1 := syscall_syscall6(libc_lseek_trampoline_addr, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0) newoffset = int64(int64(r1)<<32 | int64(r0)) if e1 != 0 { err = errnoErr(e1) @@ -1302,10 +1706,14 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return } +var libc_lseek_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_lseek lseek "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { - r0, _, e1 := Syscall6(SYS_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + r0, _, e1 := syscall_syscall6(libc_select_trampoline_addr, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1313,36 +1721,52 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err return } +var libc_select_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_select select "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setegid(egid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_setegid_trampoline_addr, uintptr(egid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setegid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setegid setegid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seteuid(euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_seteuid_trampoline_addr, uintptr(euid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_seteuid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_seteuid seteuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setgid(gid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_setgid_trampoline_addr, uintptr(gid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setgid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setgid setgid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setlogin(name string) (err error) { @@ -1351,97 +1775,133 @@ func Setlogin(name string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_setlogin_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setlogin_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setlogin setlogin "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + _, _, e1 := syscall_rawSyscall(libc_setpgid_trampoline_addr, uintptr(pid), uintptr(pgid), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setpgid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setpgid setpgid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + _, _, e1 := syscall_syscall(libc_setpriority_trampoline_addr, uintptr(which), uintptr(who), uintptr(prio)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setpriority_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setpriority setpriority "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setregid(rgid int, egid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + _, _, e1 := syscall_rawSyscall(libc_setregid_trampoline_addr, uintptr(rgid), uintptr(egid), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setregid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setregid setregid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + _, _, e1 := syscall_rawSyscall(libc_setreuid_trampoline_addr, uintptr(ruid), uintptr(euid), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setreuid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setreuid setreuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setresgid(rgid int, egid int, sgid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)) + _, _, e1 := syscall_rawSyscall(libc_setresgid_trampoline_addr, uintptr(rgid), uintptr(egid), uintptr(sgid)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setresgid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setresgid setresgid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setresuid(ruid int, euid int, suid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)) + _, _, e1 := syscall_rawSyscall(libc_setresuid_trampoline_addr, uintptr(ruid), uintptr(euid), uintptr(suid)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setresuid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setresuid setresuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setrlimit_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setrtable(rtable int) (err error) { - _, _, e1 := RawSyscall(SYS_SETRTABLE, uintptr(rtable), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_setrtable_trampoline_addr, uintptr(rtable), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setrtable_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setrtable setrtable "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setsid() (pid int, err error) { - r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_setsid_trampoline_addr, 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1449,26 +1909,38 @@ func Setsid() (pid int, err error) { return } +var libc_setsid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setsid setsid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_settimeofday_trampoline_addr, uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_settimeofday_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_settimeofday settimeofday "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setuid(uid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_setuid_trampoline_addr, uintptr(uid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_setuid_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_setuid setuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Stat(path string, stat *Stat_t) (err error) { @@ -1477,13 +1949,17 @@ func Stat(path string, stat *Stat_t) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_stat_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_stat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_stat stat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Statfs(path string, stat *Statfs_t) (err error) { @@ -1492,13 +1968,17 @@ func Statfs(path string, stat *Statfs_t) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_statfs_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_statfs_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_statfs statfs "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Symlink(path string, link string) (err error) { @@ -1512,13 +1992,17 @@ func Symlink(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(libc_symlink_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_symlink_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_symlink symlink "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { @@ -1532,23 +2016,31 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + _, _, e1 := syscall_syscall(libc_symlinkat_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) if e1 != 0 { err = errnoErr(e1) } return } +var libc_symlinkat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_symlinkat symlinkat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Sync() (err error) { - _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + _, _, e1 := syscall_syscall(libc_sync_trampoline_addr, 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_sync_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_sync sync "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Truncate(path string, length int64) (err error) { @@ -1557,21 +2049,29 @@ func Truncate(path string, length int64) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) + _, _, e1 := syscall_syscall6(libc_truncate_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_truncate_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_truncate truncate "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(newmask int) (oldmask int) { - r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + r0, _, _ := syscall_syscall(libc_umask_trampoline_addr, uintptr(newmask), 0, 0) oldmask = int(r0) return } +var libc_umask_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_umask umask "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlink(path string) (err error) { @@ -1580,13 +2080,17 @@ func Unlink(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_unlink_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_unlink_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_unlink unlink "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlinkat(dirfd int, path string, flags int) (err error) { @@ -1595,13 +2099,17 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + _, _, e1 := syscall_syscall(libc_unlinkat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +var libc_unlinkat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_unlinkat unlinkat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unmount(path string, flags int) (err error) { @@ -1610,13 +2118,17 @@ func Unmount(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(libc_unmount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_unmount_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_unmount unmount "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func write(fd int, p []byte) (n int, err error) { @@ -1626,7 +2138,7 @@ func write(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(libc_write_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1634,10 +2146,14 @@ func write(fd int, p []byte) (n int, err error) { return } +var libc_write_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_write write "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0) + r0, _, e1 := syscall_syscall9(libc_mmap_trampoline_addr, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0) ret = uintptr(r0) if e1 != 0 { err = errnoErr(e1) @@ -1645,20 +2161,28 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) ( return } +var libc_mmap_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mmap mmap "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + _, _, e1 := syscall_syscall(libc_munmap_trampoline_addr, uintptr(addr), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } +var libc_munmap_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_munmap munmap "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(libc_read_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1669,7 +2193,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(libc_write_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1685,9 +2209,13 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error if err != nil { return } - _, _, e1 := Syscall6(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_utimensat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } + +var libc_utimensat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_utimensat utimensat "libc.so" diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s new file mode 100644 index 000000000..9ad116d9f --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s @@ -0,0 +1,796 @@ +// go run mkasm.go openbsd arm +// Code generated by the command above; DO NOT EDIT. + +#include "textflag.h" + +TEXT libc_getgroups_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getgroups(SB) + +GLOBL ·libc_getgroups_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getgroups_trampoline_addr(SB)/4, $libc_getgroups_trampoline<>(SB) + +TEXT libc_setgroups_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setgroups(SB) + +GLOBL ·libc_setgroups_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setgroups_trampoline_addr(SB)/4, $libc_setgroups_trampoline<>(SB) + +TEXT libc_wait4_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_wait4(SB) + +GLOBL ·libc_wait4_trampoline_addr(SB), RODATA, $4 +DATA ·libc_wait4_trampoline_addr(SB)/4, $libc_wait4_trampoline<>(SB) + +TEXT libc_accept_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_accept(SB) + +GLOBL ·libc_accept_trampoline_addr(SB), RODATA, $4 +DATA ·libc_accept_trampoline_addr(SB)/4, $libc_accept_trampoline<>(SB) + +TEXT libc_bind_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_bind(SB) + +GLOBL ·libc_bind_trampoline_addr(SB), RODATA, $4 +DATA ·libc_bind_trampoline_addr(SB)/4, $libc_bind_trampoline<>(SB) + +TEXT libc_connect_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_connect(SB) + +GLOBL ·libc_connect_trampoline_addr(SB), RODATA, $4 +DATA ·libc_connect_trampoline_addr(SB)/4, $libc_connect_trampoline<>(SB) + +TEXT libc_socket_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_socket(SB) + +GLOBL ·libc_socket_trampoline_addr(SB), RODATA, $4 +DATA ·libc_socket_trampoline_addr(SB)/4, $libc_socket_trampoline<>(SB) + +TEXT libc_getsockopt_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getsockopt(SB) + +GLOBL ·libc_getsockopt_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getsockopt_trampoline_addr(SB)/4, $libc_getsockopt_trampoline<>(SB) + +TEXT libc_setsockopt_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setsockopt(SB) + +GLOBL ·libc_setsockopt_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setsockopt_trampoline_addr(SB)/4, $libc_setsockopt_trampoline<>(SB) + +TEXT libc_getpeername_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getpeername(SB) + +GLOBL ·libc_getpeername_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getpeername_trampoline_addr(SB)/4, $libc_getpeername_trampoline<>(SB) + +TEXT libc_getsockname_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getsockname(SB) + +GLOBL ·libc_getsockname_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getsockname_trampoline_addr(SB)/4, $libc_getsockname_trampoline<>(SB) + +TEXT libc_shutdown_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_shutdown(SB) + +GLOBL ·libc_shutdown_trampoline_addr(SB), RODATA, $4 +DATA ·libc_shutdown_trampoline_addr(SB)/4, $libc_shutdown_trampoline<>(SB) + +TEXT libc_socketpair_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_socketpair(SB) + +GLOBL ·libc_socketpair_trampoline_addr(SB), RODATA, $4 +DATA ·libc_socketpair_trampoline_addr(SB)/4, $libc_socketpair_trampoline<>(SB) + +TEXT libc_recvfrom_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_recvfrom(SB) + +GLOBL ·libc_recvfrom_trampoline_addr(SB), RODATA, $4 +DATA ·libc_recvfrom_trampoline_addr(SB)/4, $libc_recvfrom_trampoline<>(SB) + +TEXT libc_sendto_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sendto(SB) + +GLOBL ·libc_sendto_trampoline_addr(SB), RODATA, $4 +DATA ·libc_sendto_trampoline_addr(SB)/4, $libc_sendto_trampoline<>(SB) + +TEXT libc_recvmsg_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_recvmsg(SB) + +GLOBL ·libc_recvmsg_trampoline_addr(SB), RODATA, $4 +DATA ·libc_recvmsg_trampoline_addr(SB)/4, $libc_recvmsg_trampoline<>(SB) + +TEXT libc_sendmsg_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sendmsg(SB) + +GLOBL ·libc_sendmsg_trampoline_addr(SB), RODATA, $4 +DATA ·libc_sendmsg_trampoline_addr(SB)/4, $libc_sendmsg_trampoline<>(SB) + +TEXT libc_kevent_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_kevent(SB) + +GLOBL ·libc_kevent_trampoline_addr(SB), RODATA, $4 +DATA ·libc_kevent_trampoline_addr(SB)/4, $libc_kevent_trampoline<>(SB) + +TEXT libc_utimes_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_utimes(SB) + +GLOBL ·libc_utimes_trampoline_addr(SB), RODATA, $4 +DATA ·libc_utimes_trampoline_addr(SB)/4, $libc_utimes_trampoline<>(SB) + +TEXT libc_futimes_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_futimes(SB) + +GLOBL ·libc_futimes_trampoline_addr(SB), RODATA, $4 +DATA ·libc_futimes_trampoline_addr(SB)/4, $libc_futimes_trampoline<>(SB) + +TEXT libc_poll_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_poll(SB) + +GLOBL ·libc_poll_trampoline_addr(SB), RODATA, $4 +DATA ·libc_poll_trampoline_addr(SB)/4, $libc_poll_trampoline<>(SB) + +TEXT libc_madvise_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_madvise(SB) + +GLOBL ·libc_madvise_trampoline_addr(SB), RODATA, $4 +DATA ·libc_madvise_trampoline_addr(SB)/4, $libc_madvise_trampoline<>(SB) + +TEXT libc_mlock_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mlock(SB) + +GLOBL ·libc_mlock_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mlock_trampoline_addr(SB)/4, $libc_mlock_trampoline<>(SB) + +TEXT libc_mlockall_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mlockall(SB) + +GLOBL ·libc_mlockall_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mlockall_trampoline_addr(SB)/4, $libc_mlockall_trampoline<>(SB) + +TEXT libc_mprotect_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mprotect(SB) + +GLOBL ·libc_mprotect_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mprotect_trampoline_addr(SB)/4, $libc_mprotect_trampoline<>(SB) + +TEXT libc_msync_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_msync(SB) + +GLOBL ·libc_msync_trampoline_addr(SB), RODATA, $4 +DATA ·libc_msync_trampoline_addr(SB)/4, $libc_msync_trampoline<>(SB) + +TEXT libc_munlock_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_munlock(SB) + +GLOBL ·libc_munlock_trampoline_addr(SB), RODATA, $4 +DATA ·libc_munlock_trampoline_addr(SB)/4, $libc_munlock_trampoline<>(SB) + +TEXT libc_munlockall_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_munlockall(SB) + +GLOBL ·libc_munlockall_trampoline_addr(SB), RODATA, $4 +DATA ·libc_munlockall_trampoline_addr(SB)/4, $libc_munlockall_trampoline<>(SB) + +TEXT libc_pipe2_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pipe2(SB) + +GLOBL ·libc_pipe2_trampoline_addr(SB), RODATA, $4 +DATA ·libc_pipe2_trampoline_addr(SB)/4, $libc_pipe2_trampoline<>(SB) + +TEXT libc_getdents_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getdents(SB) + +GLOBL ·libc_getdents_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getdents_trampoline_addr(SB)/4, $libc_getdents_trampoline<>(SB) + +TEXT libc_getcwd_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getcwd(SB) + +GLOBL ·libc_getcwd_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getcwd_trampoline_addr(SB)/4, $libc_getcwd_trampoline<>(SB) + +TEXT libc_ioctl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_ioctl(SB) + +GLOBL ·libc_ioctl_trampoline_addr(SB), RODATA, $4 +DATA ·libc_ioctl_trampoline_addr(SB)/4, $libc_ioctl_trampoline<>(SB) + +TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sysctl(SB) + +GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $4 +DATA ·libc_sysctl_trampoline_addr(SB)/4, $libc_sysctl_trampoline<>(SB) + +TEXT libc_ppoll_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_ppoll(SB) + +GLOBL ·libc_ppoll_trampoline_addr(SB), RODATA, $4 +DATA ·libc_ppoll_trampoline_addr(SB)/4, $libc_ppoll_trampoline<>(SB) + +TEXT libc_access_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_access(SB) + +GLOBL ·libc_access_trampoline_addr(SB), RODATA, $4 +DATA ·libc_access_trampoline_addr(SB)/4, $libc_access_trampoline<>(SB) + +TEXT libc_adjtime_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_adjtime(SB) + +GLOBL ·libc_adjtime_trampoline_addr(SB), RODATA, $4 +DATA ·libc_adjtime_trampoline_addr(SB)/4, $libc_adjtime_trampoline<>(SB) + +TEXT libc_chdir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_chdir(SB) + +GLOBL ·libc_chdir_trampoline_addr(SB), RODATA, $4 +DATA ·libc_chdir_trampoline_addr(SB)/4, $libc_chdir_trampoline<>(SB) + +TEXT libc_chflags_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_chflags(SB) + +GLOBL ·libc_chflags_trampoline_addr(SB), RODATA, $4 +DATA ·libc_chflags_trampoline_addr(SB)/4, $libc_chflags_trampoline<>(SB) + +TEXT libc_chmod_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_chmod(SB) + +GLOBL ·libc_chmod_trampoline_addr(SB), RODATA, $4 +DATA ·libc_chmod_trampoline_addr(SB)/4, $libc_chmod_trampoline<>(SB) + +TEXT libc_chown_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_chown(SB) + +GLOBL ·libc_chown_trampoline_addr(SB), RODATA, $4 +DATA ·libc_chown_trampoline_addr(SB)/4, $libc_chown_trampoline<>(SB) + +TEXT libc_chroot_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_chroot(SB) + +GLOBL ·libc_chroot_trampoline_addr(SB), RODATA, $4 +DATA ·libc_chroot_trampoline_addr(SB)/4, $libc_chroot_trampoline<>(SB) + +TEXT libc_close_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_close(SB) + +GLOBL ·libc_close_trampoline_addr(SB), RODATA, $4 +DATA ·libc_close_trampoline_addr(SB)/4, $libc_close_trampoline<>(SB) + +TEXT libc_dup_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_dup(SB) + +GLOBL ·libc_dup_trampoline_addr(SB), RODATA, $4 +DATA ·libc_dup_trampoline_addr(SB)/4, $libc_dup_trampoline<>(SB) + +TEXT libc_dup2_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_dup2(SB) + +GLOBL ·libc_dup2_trampoline_addr(SB), RODATA, $4 +DATA ·libc_dup2_trampoline_addr(SB)/4, $libc_dup2_trampoline<>(SB) + +TEXT libc_dup3_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_dup3(SB) + +GLOBL ·libc_dup3_trampoline_addr(SB), RODATA, $4 +DATA ·libc_dup3_trampoline_addr(SB)/4, $libc_dup3_trampoline<>(SB) + +TEXT libc_exit_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_exit(SB) + +GLOBL ·libc_exit_trampoline_addr(SB), RODATA, $4 +DATA ·libc_exit_trampoline_addr(SB)/4, $libc_exit_trampoline<>(SB) + +TEXT libc_faccessat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_faccessat(SB) + +GLOBL ·libc_faccessat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_faccessat_trampoline_addr(SB)/4, $libc_faccessat_trampoline<>(SB) + +TEXT libc_fchdir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fchdir(SB) + +GLOBL ·libc_fchdir_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fchdir_trampoline_addr(SB)/4, $libc_fchdir_trampoline<>(SB) + +TEXT libc_fchflags_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fchflags(SB) + +GLOBL ·libc_fchflags_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fchflags_trampoline_addr(SB)/4, $libc_fchflags_trampoline<>(SB) + +TEXT libc_fchmod_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fchmod(SB) + +GLOBL ·libc_fchmod_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fchmod_trampoline_addr(SB)/4, $libc_fchmod_trampoline<>(SB) + +TEXT libc_fchmodat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fchmodat(SB) + +GLOBL ·libc_fchmodat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fchmodat_trampoline_addr(SB)/4, $libc_fchmodat_trampoline<>(SB) + +TEXT libc_fchown_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fchown(SB) + +GLOBL ·libc_fchown_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fchown_trampoline_addr(SB)/4, $libc_fchown_trampoline<>(SB) + +TEXT libc_fchownat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fchownat(SB) + +GLOBL ·libc_fchownat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fchownat_trampoline_addr(SB)/4, $libc_fchownat_trampoline<>(SB) + +TEXT libc_flock_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_flock(SB) + +GLOBL ·libc_flock_trampoline_addr(SB), RODATA, $4 +DATA ·libc_flock_trampoline_addr(SB)/4, $libc_flock_trampoline<>(SB) + +TEXT libc_fpathconf_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fpathconf(SB) + +GLOBL ·libc_fpathconf_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fpathconf_trampoline_addr(SB)/4, $libc_fpathconf_trampoline<>(SB) + +TEXT libc_fstat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fstat(SB) + +GLOBL ·libc_fstat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fstat_trampoline_addr(SB)/4, $libc_fstat_trampoline<>(SB) + +TEXT libc_fstatat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fstatat(SB) + +GLOBL ·libc_fstatat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fstatat_trampoline_addr(SB)/4, $libc_fstatat_trampoline<>(SB) + +TEXT libc_fstatfs_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fstatfs(SB) + +GLOBL ·libc_fstatfs_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fstatfs_trampoline_addr(SB)/4, $libc_fstatfs_trampoline<>(SB) + +TEXT libc_fsync_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fsync(SB) + +GLOBL ·libc_fsync_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fsync_trampoline_addr(SB)/4, $libc_fsync_trampoline<>(SB) + +TEXT libc_ftruncate_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_ftruncate(SB) + +GLOBL ·libc_ftruncate_trampoline_addr(SB), RODATA, $4 +DATA ·libc_ftruncate_trampoline_addr(SB)/4, $libc_ftruncate_trampoline<>(SB) + +TEXT libc_getegid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getegid(SB) + +GLOBL ·libc_getegid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getegid_trampoline_addr(SB)/4, $libc_getegid_trampoline<>(SB) + +TEXT libc_geteuid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_geteuid(SB) + +GLOBL ·libc_geteuid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_geteuid_trampoline_addr(SB)/4, $libc_geteuid_trampoline<>(SB) + +TEXT libc_getgid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getgid(SB) + +GLOBL ·libc_getgid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getgid_trampoline_addr(SB)/4, $libc_getgid_trampoline<>(SB) + +TEXT libc_getpgid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getpgid(SB) + +GLOBL ·libc_getpgid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getpgid_trampoline_addr(SB)/4, $libc_getpgid_trampoline<>(SB) + +TEXT libc_getpgrp_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getpgrp(SB) + +GLOBL ·libc_getpgrp_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getpgrp_trampoline_addr(SB)/4, $libc_getpgrp_trampoline<>(SB) + +TEXT libc_getpid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getpid(SB) + +GLOBL ·libc_getpid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getpid_trampoline_addr(SB)/4, $libc_getpid_trampoline<>(SB) + +TEXT libc_getppid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getppid(SB) + +GLOBL ·libc_getppid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getppid_trampoline_addr(SB)/4, $libc_getppid_trampoline<>(SB) + +TEXT libc_getpriority_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getpriority(SB) + +GLOBL ·libc_getpriority_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getpriority_trampoline_addr(SB)/4, $libc_getpriority_trampoline<>(SB) + +TEXT libc_getrlimit_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getrlimit(SB) + +GLOBL ·libc_getrlimit_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getrlimit_trampoline_addr(SB)/4, $libc_getrlimit_trampoline<>(SB) + +TEXT libc_getrtable_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getrtable(SB) + +GLOBL ·libc_getrtable_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getrtable_trampoline_addr(SB)/4, $libc_getrtable_trampoline<>(SB) + +TEXT libc_getrusage_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getrusage(SB) + +GLOBL ·libc_getrusage_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getrusage_trampoline_addr(SB)/4, $libc_getrusage_trampoline<>(SB) + +TEXT libc_getsid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getsid(SB) + +GLOBL ·libc_getsid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getsid_trampoline_addr(SB)/4, $libc_getsid_trampoline<>(SB) + +TEXT libc_gettimeofday_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_gettimeofday(SB) + +GLOBL ·libc_gettimeofday_trampoline_addr(SB), RODATA, $4 +DATA ·libc_gettimeofday_trampoline_addr(SB)/4, $libc_gettimeofday_trampoline<>(SB) + +TEXT libc_getuid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_getuid(SB) + +GLOBL ·libc_getuid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_getuid_trampoline_addr(SB)/4, $libc_getuid_trampoline<>(SB) + +TEXT libc_issetugid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_issetugid(SB) + +GLOBL ·libc_issetugid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_issetugid_trampoline_addr(SB)/4, $libc_issetugid_trampoline<>(SB) + +TEXT libc_kill_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_kill(SB) + +GLOBL ·libc_kill_trampoline_addr(SB), RODATA, $4 +DATA ·libc_kill_trampoline_addr(SB)/4, $libc_kill_trampoline<>(SB) + +TEXT libc_kqueue_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_kqueue(SB) + +GLOBL ·libc_kqueue_trampoline_addr(SB), RODATA, $4 +DATA ·libc_kqueue_trampoline_addr(SB)/4, $libc_kqueue_trampoline<>(SB) + +TEXT libc_lchown_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_lchown(SB) + +GLOBL ·libc_lchown_trampoline_addr(SB), RODATA, $4 +DATA ·libc_lchown_trampoline_addr(SB)/4, $libc_lchown_trampoline<>(SB) + +TEXT libc_link_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_link(SB) + +GLOBL ·libc_link_trampoline_addr(SB), RODATA, $4 +DATA ·libc_link_trampoline_addr(SB)/4, $libc_link_trampoline<>(SB) + +TEXT libc_linkat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_linkat(SB) + +GLOBL ·libc_linkat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_linkat_trampoline_addr(SB)/4, $libc_linkat_trampoline<>(SB) + +TEXT libc_listen_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_listen(SB) + +GLOBL ·libc_listen_trampoline_addr(SB), RODATA, $4 +DATA ·libc_listen_trampoline_addr(SB)/4, $libc_listen_trampoline<>(SB) + +TEXT libc_lstat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_lstat(SB) + +GLOBL ·libc_lstat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_lstat_trampoline_addr(SB)/4, $libc_lstat_trampoline<>(SB) + +TEXT libc_mkdir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mkdir(SB) + +GLOBL ·libc_mkdir_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mkdir_trampoline_addr(SB)/4, $libc_mkdir_trampoline<>(SB) + +TEXT libc_mkdirat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mkdirat(SB) + +GLOBL ·libc_mkdirat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mkdirat_trampoline_addr(SB)/4, $libc_mkdirat_trampoline<>(SB) + +TEXT libc_mkfifo_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mkfifo(SB) + +GLOBL ·libc_mkfifo_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mkfifo_trampoline_addr(SB)/4, $libc_mkfifo_trampoline<>(SB) + +TEXT libc_mkfifoat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mkfifoat(SB) + +GLOBL ·libc_mkfifoat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mkfifoat_trampoline_addr(SB)/4, $libc_mkfifoat_trampoline<>(SB) + +TEXT libc_mknod_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mknod(SB) + +GLOBL ·libc_mknod_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mknod_trampoline_addr(SB)/4, $libc_mknod_trampoline<>(SB) + +TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mknodat(SB) + +GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mknodat_trampoline_addr(SB)/4, $libc_mknodat_trampoline<>(SB) + +TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_nanosleep(SB) + +GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $4 +DATA ·libc_nanosleep_trampoline_addr(SB)/4, $libc_nanosleep_trampoline<>(SB) + +TEXT libc_open_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_open(SB) + +GLOBL ·libc_open_trampoline_addr(SB), RODATA, $4 +DATA ·libc_open_trampoline_addr(SB)/4, $libc_open_trampoline<>(SB) + +TEXT libc_openat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_openat(SB) + +GLOBL ·libc_openat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_openat_trampoline_addr(SB)/4, $libc_openat_trampoline<>(SB) + +TEXT libc_pathconf_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pathconf(SB) + +GLOBL ·libc_pathconf_trampoline_addr(SB), RODATA, $4 +DATA ·libc_pathconf_trampoline_addr(SB)/4, $libc_pathconf_trampoline<>(SB) + +TEXT libc_pread_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pread(SB) + +GLOBL ·libc_pread_trampoline_addr(SB), RODATA, $4 +DATA ·libc_pread_trampoline_addr(SB)/4, $libc_pread_trampoline<>(SB) + +TEXT libc_pwrite_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pwrite(SB) + +GLOBL ·libc_pwrite_trampoline_addr(SB), RODATA, $4 +DATA ·libc_pwrite_trampoline_addr(SB)/4, $libc_pwrite_trampoline<>(SB) + +TEXT libc_read_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_read(SB) + +GLOBL ·libc_read_trampoline_addr(SB), RODATA, $4 +DATA ·libc_read_trampoline_addr(SB)/4, $libc_read_trampoline<>(SB) + +TEXT libc_readlink_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readlink(SB) + +GLOBL ·libc_readlink_trampoline_addr(SB), RODATA, $4 +DATA ·libc_readlink_trampoline_addr(SB)/4, $libc_readlink_trampoline<>(SB) + +TEXT libc_readlinkat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readlinkat(SB) + +GLOBL ·libc_readlinkat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_readlinkat_trampoline_addr(SB)/4, $libc_readlinkat_trampoline<>(SB) + +TEXT libc_rename_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_rename(SB) + +GLOBL ·libc_rename_trampoline_addr(SB), RODATA, $4 +DATA ·libc_rename_trampoline_addr(SB)/4, $libc_rename_trampoline<>(SB) + +TEXT libc_renameat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_renameat(SB) + +GLOBL ·libc_renameat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_renameat_trampoline_addr(SB)/4, $libc_renameat_trampoline<>(SB) + +TEXT libc_revoke_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_revoke(SB) + +GLOBL ·libc_revoke_trampoline_addr(SB), RODATA, $4 +DATA ·libc_revoke_trampoline_addr(SB)/4, $libc_revoke_trampoline<>(SB) + +TEXT libc_rmdir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_rmdir(SB) + +GLOBL ·libc_rmdir_trampoline_addr(SB), RODATA, $4 +DATA ·libc_rmdir_trampoline_addr(SB)/4, $libc_rmdir_trampoline<>(SB) + +TEXT libc_lseek_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_lseek(SB) + +GLOBL ·libc_lseek_trampoline_addr(SB), RODATA, $4 +DATA ·libc_lseek_trampoline_addr(SB)/4, $libc_lseek_trampoline<>(SB) + +TEXT libc_select_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_select(SB) + +GLOBL ·libc_select_trampoline_addr(SB), RODATA, $4 +DATA ·libc_select_trampoline_addr(SB)/4, $libc_select_trampoline<>(SB) + +TEXT libc_setegid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setegid(SB) + +GLOBL ·libc_setegid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setegid_trampoline_addr(SB)/4, $libc_setegid_trampoline<>(SB) + +TEXT libc_seteuid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_seteuid(SB) + +GLOBL ·libc_seteuid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_seteuid_trampoline_addr(SB)/4, $libc_seteuid_trampoline<>(SB) + +TEXT libc_setgid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setgid(SB) + +GLOBL ·libc_setgid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setgid_trampoline_addr(SB)/4, $libc_setgid_trampoline<>(SB) + +TEXT libc_setlogin_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setlogin(SB) + +GLOBL ·libc_setlogin_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setlogin_trampoline_addr(SB)/4, $libc_setlogin_trampoline<>(SB) + +TEXT libc_setpgid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setpgid(SB) + +GLOBL ·libc_setpgid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setpgid_trampoline_addr(SB)/4, $libc_setpgid_trampoline<>(SB) + +TEXT libc_setpriority_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setpriority(SB) + +GLOBL ·libc_setpriority_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setpriority_trampoline_addr(SB)/4, $libc_setpriority_trampoline<>(SB) + +TEXT libc_setregid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setregid(SB) + +GLOBL ·libc_setregid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setregid_trampoline_addr(SB)/4, $libc_setregid_trampoline<>(SB) + +TEXT libc_setreuid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setreuid(SB) + +GLOBL ·libc_setreuid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setreuid_trampoline_addr(SB)/4, $libc_setreuid_trampoline<>(SB) + +TEXT libc_setresgid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setresgid(SB) + +GLOBL ·libc_setresgid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setresgid_trampoline_addr(SB)/4, $libc_setresgid_trampoline<>(SB) + +TEXT libc_setresuid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setresuid(SB) + +GLOBL ·libc_setresuid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setresuid_trampoline_addr(SB)/4, $libc_setresuid_trampoline<>(SB) + +TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setrlimit(SB) + +GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setrlimit_trampoline_addr(SB)/4, $libc_setrlimit_trampoline<>(SB) + +TEXT libc_setrtable_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setrtable(SB) + +GLOBL ·libc_setrtable_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setrtable_trampoline_addr(SB)/4, $libc_setrtable_trampoline<>(SB) + +TEXT libc_setsid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setsid(SB) + +GLOBL ·libc_setsid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setsid_trampoline_addr(SB)/4, $libc_setsid_trampoline<>(SB) + +TEXT libc_settimeofday_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_settimeofday(SB) + +GLOBL ·libc_settimeofday_trampoline_addr(SB), RODATA, $4 +DATA ·libc_settimeofday_trampoline_addr(SB)/4, $libc_settimeofday_trampoline<>(SB) + +TEXT libc_setuid_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_setuid(SB) + +GLOBL ·libc_setuid_trampoline_addr(SB), RODATA, $4 +DATA ·libc_setuid_trampoline_addr(SB)/4, $libc_setuid_trampoline<>(SB) + +TEXT libc_stat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_stat(SB) + +GLOBL ·libc_stat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_stat_trampoline_addr(SB)/4, $libc_stat_trampoline<>(SB) + +TEXT libc_statfs_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_statfs(SB) + +GLOBL ·libc_statfs_trampoline_addr(SB), RODATA, $4 +DATA ·libc_statfs_trampoline_addr(SB)/4, $libc_statfs_trampoline<>(SB) + +TEXT libc_symlink_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_symlink(SB) + +GLOBL ·libc_symlink_trampoline_addr(SB), RODATA, $4 +DATA ·libc_symlink_trampoline_addr(SB)/4, $libc_symlink_trampoline<>(SB) + +TEXT libc_symlinkat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_symlinkat(SB) + +GLOBL ·libc_symlinkat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_symlinkat_trampoline_addr(SB)/4, $libc_symlinkat_trampoline<>(SB) + +TEXT libc_sync_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sync(SB) + +GLOBL ·libc_sync_trampoline_addr(SB), RODATA, $4 +DATA ·libc_sync_trampoline_addr(SB)/4, $libc_sync_trampoline<>(SB) + +TEXT libc_truncate_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_truncate(SB) + +GLOBL ·libc_truncate_trampoline_addr(SB), RODATA, $4 +DATA ·libc_truncate_trampoline_addr(SB)/4, $libc_truncate_trampoline<>(SB) + +TEXT libc_umask_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_umask(SB) + +GLOBL ·libc_umask_trampoline_addr(SB), RODATA, $4 +DATA ·libc_umask_trampoline_addr(SB)/4, $libc_umask_trampoline<>(SB) + +TEXT libc_unlink_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_unlink(SB) + +GLOBL ·libc_unlink_trampoline_addr(SB), RODATA, $4 +DATA ·libc_unlink_trampoline_addr(SB)/4, $libc_unlink_trampoline<>(SB) + +TEXT libc_unlinkat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_unlinkat(SB) + +GLOBL ·libc_unlinkat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_unlinkat_trampoline_addr(SB)/4, $libc_unlinkat_trampoline<>(SB) + +TEXT libc_unmount_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_unmount(SB) + +GLOBL ·libc_unmount_trampoline_addr(SB), RODATA, $4 +DATA ·libc_unmount_trampoline_addr(SB)/4, $libc_unmount_trampoline<>(SB) + +TEXT libc_write_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_write(SB) + +GLOBL ·libc_write_trampoline_addr(SB), RODATA, $4 +DATA ·libc_write_trampoline_addr(SB)/4, $libc_write_trampoline<>(SB) + +TEXT libc_mmap_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mmap(SB) + +GLOBL ·libc_mmap_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mmap_trampoline_addr(SB)/4, $libc_mmap_trampoline<>(SB) + +TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_munmap(SB) + +GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $4 +DATA ·libc_munmap_trampoline_addr(SB)/4, $libc_munmap_trampoline<>(SB) + +TEXT libc_utimensat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_utimensat(SB) + +GLOBL ·libc_utimensat_trampoline_addr(SB), RODATA, $4 +DATA ·libc_utimensat_trampoline_addr(SB)/4, $libc_utimensat_trampoline<>(SB) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go index 467971eed..f59b18a97 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go @@ -6,6 +6,7 @@ package unix +// Deprecated: Use libc wrappers instead of direct syscalls. const ( SYS_EXIT = 1 // { void sys_exit(int rval); } SYS_FORK = 2 // { int sys_fork(void); } diff --git a/vendor/golang.org/x/sys/windows/setupapi_windows.go b/vendor/golang.org/x/sys/windows/setupapi_windows.go index 14027da3f..f8126482f 100644 --- a/vendor/golang.org/x/sys/windows/setupapi_windows.go +++ b/vendor/golang.org/x/sys/windows/setupapi_windows.go @@ -296,7 +296,7 @@ const ( // Flag to indicate that the sorting from the INF file should be used. DI_INF_IS_SORTED DI_FLAGS = 0x00008000 - // Flag to indicate that only the the INF specified by SP_DEVINSTALL_PARAMS.DriverPath should be searched. + // Flag to indicate that only the INF specified by SP_DEVINSTALL_PARAMS.DriverPath should be searched. DI_ENUMSINGLEINF DI_FLAGS = 0x00010000 // Flag that prevents ConfigMgr from removing/re-enumerating devices during device diff --git a/vendor/modules.txt b/vendor/modules.txt index 9cf63d41b..db7e9b5bb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -11,7 +11,7 @@ github.com/Microsoft/go-winio/backuptar github.com/Microsoft/go-winio/pkg/guid github.com/Microsoft/go-winio/pkg/security github.com/Microsoft/go-winio/vhd -# github.com/Microsoft/hcsshim v0.9.3 +# github.com/Microsoft/hcsshim v0.9.4 github.com/Microsoft/hcsshim github.com/Microsoft/hcsshim/computestorage github.com/Microsoft/hcsshim/internal/cow @@ -67,7 +67,7 @@ github.com/container-orchestrated-devices/container-device-interface/pkg/cdi github.com/container-orchestrated-devices/container-device-interface/specs-go # github.com/containerd/cgroups v1.0.3 github.com/containerd/cgroups/stats/v1 -# github.com/containerd/containerd v1.6.6 +# github.com/containerd/containerd v1.6.8 github.com/containerd/containerd/errdefs github.com/containerd/containerd/log github.com/containerd/containerd/pkg/userns @@ -114,7 +114,7 @@ github.com/containers/buildah/pkg/rusage github.com/containers/buildah/pkg/sshagent github.com/containers/buildah/pkg/util github.com/containers/buildah/util -# github.com/containers/common v0.49.2-0.20220809074359-b0ea008ba661 +# github.com/containers/common v0.49.2-0.20220823130605-72a7da3358ac ## explicit github.com/containers/common/libimage github.com/containers/common/libimage/define @@ -250,7 +250,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7 github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils/keyprovider -# github.com/containers/psgo v1.7.2 +# github.com/containers/psgo v1.7.3 ## explicit github.com/containers/psgo github.com/containers/psgo/internal/capabilities @@ -620,6 +620,7 @@ github.com/opencontainers/selinux/go-selinux/label github.com/opencontainers/selinux/pkg/pwalk github.com/opencontainers/selinux/pkg/pwalkdir # github.com/openshift/imagebuilder v1.2.4-0.20220711175835-4151e43600df +## explicit github.com/openshift/imagebuilder github.com/openshift/imagebuilder/dockerfile/command github.com/openshift/imagebuilder/dockerfile/parser @@ -719,7 +720,7 @@ github.com/ulikunitz/xz/lzma github.com/vbatts/tar-split/archive/tar github.com/vbatts/tar-split/tar/asm github.com/vbatts/tar-split/tar/storage -# github.com/vbauerster/mpb/v7 v7.4.2 +# github.com/vbauerster/mpb/v7 v7.5.2 ## explicit github.com/vbauerster/mpb/v7 github.com/vbauerster/mpb/v7/cwriter @@ -788,7 +789,7 @@ golang.org/x/net/trace ## explicit golang.org/x/sync/errgroup golang.org/x/sync/semaphore -# golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab +# golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 ## explicit golang.org/x/sys/cpu golang.org/x/sys/execabs diff --git a/version/version.go b/version/version.go index 0a84bb235..417f3a9b1 100644 --- a/version/version.go +++ b/version/version.go @@ -27,7 +27,7 @@ const ( // NOTE: remember to bump the version at the top // of the top-level README.md file when this is // bumped. -var Version = semver.MustParse("4.2.0-dev") +var Version = semver.MustParse("4.3.0-dev") // See https://docs.docker.com/engine/api/v1.40/ // libpod compat handlers are expected to honor docker API versions |