aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml35
-rw-r--r--cmd/podman/containers/restart.go67
-rw-r--r--cmd/podman/containers/stats.go5
-rw-r--r--cmd/podman/kube/generate.go29
-rw-r--r--cmd/podman/manifest/add.go12
-rw-r--r--cmd/podman/manifest/create.go32
-rw-r--r--cmd/podman/manifest/push.go15
-rwxr-xr-xcontrib/cirrus/cirrus_yaml_test.py2
-rw-r--r--docs/source/markdown/podman-manifest-create.1.md12
-rw-r--r--docs/source/markdown/podman-restart.1.md38
-rw-r--r--docs/source/markdown/podman-stats.1.md10
-rw-r--r--libpod/boltdb_state_unsupported.go19
-rw-r--r--libpod/container_copy_unsupported.go17
-rw-r--r--libpod/container_internal.go20
-rw-r--r--libpod/container_internal_linux.go25
-rw-r--r--libpod/container_internal_unsupported.go99
-rw-r--r--libpod/container_stat_unsupported.go14
-rw-r--r--libpod/container_top_unsupported.go14
-rw-r--r--libpod/container_unsupported.go7
-rw-r--r--libpod/healthcheck_unsupported.go25
-rw-r--r--libpod/info.go3
-rw-r--r--libpod/info_unsupported.go14
-rw-r--r--libpod/networking_unsupported.go79
-rw-r--r--libpod/oci_conmon_unsupported.go24
-rw-r--r--libpod/pod_top_unsupported.go20
-rw-r--r--libpod/runtime_migrate_unsupported.go16
-rw-r--r--libpod/runtime_pod_unsupported.go30
-rw-r--r--libpod/runtime_volume_unsupported.go42
-rw-r--r--libpod/stats_unsupported.go17
-rw-r--r--libpod/util_unsupported.go27
-rw-r--r--libpod/volume_internal_unsupported.go32
-rw-r--r--pkg/api/handlers/libpod/manifests.go3
-rw-r--r--pkg/api/server/register_manifest.go4
-rw-r--r--pkg/bindings/manifests/types.go3
-rw-r--r--pkg/bindings/manifests/types_create_options.go15
-rw-r--r--pkg/domain/entities/containers.go6
-rw-r--r--pkg/domain/entities/manifest.go5
-rw-r--r--pkg/domain/infra/abi/containers.go27
-rw-r--r--pkg/domain/infra/abi/manifest.go10
-rw-r--r--pkg/domain/infra/tunnel/containers.go11
-rw-r--r--pkg/domain/infra/tunnel/manifest.go2
-rw-r--r--pkg/machine/e2e/basic_test.go8
-rw-r--r--test/e2e/manifest_test.go20
-rw-r--r--test/e2e/restart_test.go135
-rw-r--r--test/e2e/stats_test.go3
-rw-r--r--test/system/200-pod.bats2
-rw-r--r--test/system/710-kube.bats15
-rw-r--r--utils/utils_freebsd.go22
48 files changed, 990 insertions, 102 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index f94ee2f3b..e3ddc4933 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -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
@@ -1003,9 +1023,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/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/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(&notrunc, "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/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/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..fd67769b8 100644
--- a/cmd/podman/manifest/push.go
+++ b/cmd/podman/manifest/push.go
@@ -1,6 +1,7 @@
package manifest
import (
+ "errors"
"fmt"
"io/ioutil"
@@ -20,9 +21,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 +83,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)
@@ -130,6 +133,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/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/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-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-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/libpod/boltdb_state_unsupported.go b/libpod/boltdb_state_unsupported.go
new file mode 100644
index 000000000..97d59614e
--- /dev/null
+++ b/libpod/boltdb_state_unsupported.go
@@ -0,0 +1,19 @@
+//go:build !linux
+// +build !linux
+
+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_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..de92ff260
--- /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("unspported (*Container) getHostsEntries")
+}
+
+// Fix ownership and permissions of the specified volume if necessary.
+func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error {
+ return errors.New("unspported (*Container) fixVolumePermissions")
+}
+
+func (c *Container) expectPodCgroup() (bool, error) {
+ return false, errors.New("unspported (*Container) expectPodCgroup")
+}
+
+// Get cgroup path in a format suitable for the OCI spec
+func (c *Container) getOCICgroupPath() (string, error) {
+ return "", errors.New("unspported (*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..5a46c163c
--- /dev/null
+++ b/libpod/container_unsupported.go
@@ -0,0 +1,7 @@
+//go:build !linux
+// +build !linux
+
+package libpod
+
+type containerPlatformState struct {
+}
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..8db6df8cc 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -1,3 +1,6 @@
+//go:build linux
+// +build linux
+
package libpod
import (
diff --git a/libpod/info_unsupported.go b/libpod/info_unsupported.go
new file mode 100644
index 000000000..53ee4b32f
--- /dev/null
+++ b/libpod/info_unsupported.go
@@ -0,0 +1,14 @@
+//go:build !linux
+// +build !linux
+
+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/networking_unsupported.go b/libpod/networking_unsupported.go
new file mode 100644
index 000000000..227b512cd
--- /dev/null
+++ b/libpod/networking_unsupported.go
@@ -0,0 +1,79 @@
+//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")
+}
diff --git a/libpod/oci_conmon_unsupported.go b/libpod/oci_conmon_unsupported.go
new file mode 100644
index 000000000..c72dc0f0d
--- /dev/null
+++ b/libpod/oci_conmon_unsupported.go
@@ -0,0 +1,24 @@
+//go:build !linux
+// +build !linux
+
+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/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_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_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_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/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go
index b0c93f3b9..fa83bbfe1 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)
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/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/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/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/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 5b5bc665e..08d845d70 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
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/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index d49f029d5..046509140 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
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/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/test/e2e/manifest_test.go b/test/e2e/manifest_test.go
index ee954a1a4..1c4aad710 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() {
diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go
index b3052623b..dd0070f54 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 stoped 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/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/system/200-pod.bats b/test/system/200-pod.bats
index b1b9ee5e1..b9063ad1b 100644
--- a/test/system/200-pod.bats
+++ b/test/system/200-pod.bats
@@ -478,7 +478,7 @@ spec:
}
@test "pod resource limits" {
- # FIXME: #15074 - possible flake on aarch64
+ skip_if_aarch64 "FIXME: #15074 - flakes on aarch64 non-remote"
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"
diff --git a/test/system/710-kube.bats b/test/system/710-kube.bats
new file mode 100644
index 000000000..2608ad34e
--- /dev/null
+++ b/test/system/710-kube.bats
@@ -0,0 +1,15 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# Test podman kube generate
+#
+
+load helpers
+
+@test "podman kube generate - basic" {
+ 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...}"
+}
+
+# vim: filetype=sh
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")
+}