diff options
49 files changed, 309 insertions, 126 deletions
@@ -1900,7 +1900,7 @@ insecure [[]string](#[]string) blocked [[]string](#[]string) ### <a name="InfoStore"></a>type InfoStore -InfoStore describes the host's storage informatoin +InfoStore describes the host's storage information containers [int](https://godoc.org/builtin#int) @@ -1,20 +1,22 @@ approvers: - - mheon - baude + - edsantiago + - giuseppe + - jwhonce + - mheon - mrunalp - rhatdan - TomSweeneyRedHat - umohnani8 - - giuseppe - vrothberg - - jwhonce reviewers: - - mheon - baude + - edsantiago + - giuseppe + - jwhonce + - mheon - mrunalp - rhatdan - TomSweeneyRedHat - umohnani8 - - giuseppe - vrothberg - - jwhonce diff --git a/cmd/podman/auto-update.go b/cmd/podman/auto-update.go index 8e17b49e0..677266c83 100644 --- a/cmd/podman/auto-update.go +++ b/cmd/podman/auto-update.go @@ -41,7 +41,7 @@ func init() { func autoUpdate(cmd *cobra.Command, args []string) error { if len(args) > 0 { - // Backwards compat. System tests expext this error string. + // Backwards compat. System tests expect this error string. return errors.Errorf("`%s` takes no arguments", cmd.CommandPath()) } report, failures := registry.ContainerEngine().AutoUpdate(registry.GetContext(), autoUpdateOptions) diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index 5e48aa622..f9d33a223 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -235,7 +235,7 @@ func pullImage(imageName string) (string, error) { imageRef, err := alltransports.ParseImageName(imageName) switch { case err != nil: - // Assume we specified a local image withouth the explicit storage transport. + // Assume we specified a local image without the explicit storage transport. fallthrough case imageRef.Transport().Name() == storage.Transport.Name(): diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go index 2aa3b3a9b..a78b35c08 100644 --- a/cmd/podman/containers/ps.go +++ b/cmd/podman/containers/ps.go @@ -414,7 +414,7 @@ func portsToString(ports []ocicni.PortMapping) string { continue } } - // For each portMapKey, format group list and appned to output string. + // For each portMapKey, format group list and append to output string. for _, portKey := range groupKeyList { group := portGroupMap[portKey] portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last)) diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go index 923109b15..ff5c6ec09 100644 --- a/cmd/podman/images/build.go +++ b/cmd/podman/images/build.go @@ -386,6 +386,9 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil } containerConfig := registry.PodmanConfig() + for _, arg := range containerConfig.RuntimeFlags { + runtimeFlags = append(runtimeFlags, "--"+arg) + } if containerConfig.Engine.CgroupManager == config.SystemdCgroupsManager { runtimeFlags = append(runtimeFlags, "--systemd-cgroup") } diff --git a/cmd/podman/root.go b/cmd/podman/root.go index 6cf369f0a..60725b111 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -273,6 +273,7 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { pFlags.StringVar(&opts.RegistriesConf, "registries-conf", "", "Path to a registries.conf to use for image processing") pFlags.StringVar(&opts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored") pFlags.StringVar(&opts.RuntimePath, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc") + pFlags.StringArrayVar(&opts.RuntimeFlags, "runtime-flag", []string{}, "add global flags for the container runtime") // -s is deprecated due to conflict with -s on subcommands pFlags.StringVar(&opts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)") pFlags.StringArrayVar(&opts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver") diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md index f66560cc8..4056edb6a 100644 --- a/contrib/cirrus/README.md +++ b/contrib/cirrus/README.md @@ -116,7 +116,7 @@ gsutil cors get gs://libpod-master-releases To function properly (allow client "trust" of content from `storage.googleapis.com`) the followiing metadata JSON should be used. Following the JSON, is an example of the command used to set this metadata on the libpod-master-releases bucket. For additional information about configuring CORS -please referr to [the google-storage documentation](https://cloud.google.com/storage/docs/configuring-cors). +please refer to [the google-storage documentation](https://cloud.google.com/storage/docs/configuring-cors). ```JSON [ diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index f125dd76d..0dbb57ab3 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -235,7 +235,7 @@ setup_rootless() { useradd -g $ROOTLESS_GID -u $ROOTLESS_UID --no-user-group --create-home $ROOTLESS_USER chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOPATH" "$GOSRC" - echo "creating ssh keypair for $USER" + echo "creating ssh key pair for $USER" [[ -r "$HOME/.ssh/id_rsa" ]] || \ ssh-keygen -P "" -f "$HOME/.ssh/id_rsa" diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md index c38424a11..e30c2a5ef 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -422,16 +422,6 @@ commands specified by the **RUN** instruction. Note: You can also override the default runtime by setting the BUILDAH\_RUNTIME environment variable. `export BUILDAH_RUNTIME=/usr/local/bin/runc` -**--runtime-flag**=*flag* - -Adds global flags for the container runtime. To list the supported flags, please -consult the manpages of the selected container runtime (`runc` is the default -runtime, the manpage to consult is `runc(8)`. When the machine is configured -for cgroup V2, the default runtime is `crun`, the manpage to consult is `crun(8)`.). - -Note: Do not pass the leading `--` to the flag. To pass the runc flag `--log-format json` -to podman build, the option given would be `--runtime-flag log-format=json`. - **--security-opt**=*option* Security Options diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md index 2ee290f0f..af8ea3c39 100644 --- a/docs/source/markdown/podman-generate-systemd.1.md +++ b/docs/source/markdown/podman-generate-systemd.1.md @@ -51,7 +51,7 @@ Set the systemd unit name prefix for pods. The default is *pod*. **--separator**=*separator* -Set the systemd unit name seperator between the name/id of a container/pod and the prefix. The default is *-*. +Set the systemd unit name separator between the name/id of a container/pod and the prefix. The default is *-*. ## Examples diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index c53da6b5f..2dc6b13bf 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -99,6 +99,16 @@ Default state dir configured in `/etc/containers/storage.conf`. Name of the OCI runtime as specified in containers.conf or absolute path to the OCI compatible binary used to run containers. +**--runtime-flag**=*flag* + +Adds global flags for the container runtime. To list the supported flags, please +consult the manpages of the selected container runtime (`runc` is the default +runtime, the manpage to consult is `runc(8)`. When the machine is configured +for cgroup V2, the default runtime is `crun`, the manpage to consult is `crun(8)`.). + +Note: Do not pass the leading `--` to the flag. To pass the runc flag `--log-format json` +to podman build, the option given would be `--runtime-flag log-format=json`. + **--storage-driver**=*value* Storage driver. The default storage driver for UID 0 is configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode), and is *vfs* for non-root users when *fuse-overlayfs* is not available. The `STORAGE_DRIVER` environment variable overrides the default. The --storage-driver specified driver overrides all. @@ -285,7 +295,7 @@ The Network File System (NFS) and other distributed file systems (for example: L For more information, please refer to the [Podman Troubleshooting Page](https://github.com/containers/podman/blob/master/troubleshooting.md). ## SEE ALSO -`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `buildah(1)`, `containers.conf(5)`, `oci-hooks(5)`, `containers-policy.json(5)`, `subuid(5)`, `subgid(5)`, `slirp4netns(1)` +`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `buildah(1)`, `containers.conf(5)`, `oci-hooks(5)`, `containers-policy.json(5)`, `crun(8)`, `runc(8)`, `subuid(5)`, `subgid(5)`, `slirp4netns(1)` ## HISTORY Dec 2016, Originally compiled by Dan Walsh <dwalsh@redhat.com> diff --git a/hack/get_ci_vm.sh b/hack/get_ci_vm.sh index b37dba508..adf3b1bf2 100755 --- a/hack/get_ci_vm.sh +++ b/hack/get_ci_vm.sh @@ -27,7 +27,7 @@ LIBPODROOT=$(realpath "$(dirname $0)/../") # else: Assume $PWD is the root of the libpod repository [[ "$LIBPODROOT" != "/" ]] || LIBPODROOT=$PWD -# Command shortcuts save some typing (asumes $LIBPODROOT is subdir of $HOME) +# Command shortcuts save some typing (assumes $LIBPODROOT is subdir of $HOME) PGCLOUD="$GCLOUD_SUDO podman run -it --rm -e AS_ID=$UID -e AS_USER=$USER --security-opt label=disable -v $TMPDIR:$HOME -v $HOME/.config/gcloud:$HOME/.config/gcloud -v $HOME/.config/gcloud/ssh:$HOME/.ssh -v $LIBPODROOT:$LIBPODROOT $GCLOUD_IMAGE --configuration=libpod --project=$PROJECT" SCP_CMD="$PGCLOUD compute scp" diff --git a/libpod/container_exec.go b/libpod/container_exec.go index 2a852ab81..f5f54c7cc 100644 --- a/libpod/container_exec.go +++ b/libpod/container_exec.go @@ -629,7 +629,7 @@ func (c *Container) ExecRemove(sessionID string, force bool) error { logrus.Infof("Removing container %s exec session %s", c.ID(), session.ID()) - // Update status of exec session if running, so we cna check if it + // Update status of exec session if running, so we can check if it // stopped in the meantime. if session.State == define.ExecStateRunning { running, err := c.ociRuntime.ExecUpdateStatus(c, session.ID()) diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 5a0a0edfa..0514fb46f 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -1269,7 +1269,7 @@ func (c *Container) stop(timeout uint) error { c.state.StoppedByUser = true if !conmonAlive { - // Conmon is dead, so we can't epect an exit code. + // Conmon is dead, so we can't expect an exit code. c.state.ExitCode = -1 c.state.FinishedTime = time.Now() c.state.State = define.ContainerStateStopped diff --git a/libpod/define/errors.go b/libpod/define/errors.go index 7714ebbf0..b3f6483d1 100644 --- a/libpod/define/errors.go +++ b/libpod/define/errors.go @@ -163,6 +163,6 @@ var ( ErrNetworkOnPodContainer = errors.New("network cannot be configured when it is shared with a pod") // ErrStoreNotInitialized indicates that the container storage was never - // initilized. - ErrStoreNotInitialized = errors.New("the container storage was never initilized") + // initialized. + ErrStoreNotInitialized = errors.New("the container storage was never initialized") ) diff --git a/libpod/define/pod_inspect.go b/libpod/define/pod_inspect.go index 634cbb728..60e19fe05 100644 --- a/libpod/define/pod_inspect.go +++ b/libpod/define/pod_inspect.go @@ -87,7 +87,7 @@ type InspectPodInfraConfig struct { // HostAdd adds a number of hosts to the infra container's resolv.conf // which will be shared with the rest of the pod. HostAdd []string - // Networks is a list of CNI networks te pod will join. + // Networks is a list of CNI networks the pod will join. Networks []string } diff --git a/libpod/image/df.go b/libpod/image/df.go new file mode 100644 index 000000000..84cf7af9e --- /dev/null +++ b/libpod/image/df.go @@ -0,0 +1,126 @@ +package image + +import ( + "context" + "time" + + "github.com/containers/image/v5/docker/reference" +) + +// DiskUsageStat gives disk-usage statistics for a specific image. +type DiskUsageStat struct { + // ID of the image. + ID string + // Repository of the first recorded name of the image. + Repository string + // Tag of the first recorded name of the image. + Tag string + // Created is the creation time of the image. + Created time.Time + // SharedSize is the amount of space shared with another image. + SharedSize uint64 + // UniqueSize is the amount of space used only by this image. + UniqueSize uint64 + // Size is the total size of the image (i.e., the sum of the shared and + // unique size). + Size uint64 + // Number of containers using the image. + Containers int +} + +// DiskUsage returns disk-usage statistics for the specified slice of images. +func (ir *Runtime) DiskUsage(ctx context.Context, images []*Image) ([]DiskUsageStat, error) { + stats := make([]DiskUsageStat, len(images)) + + // Build a layerTree to quickly compute (and cache!) parent/child + // relations. + tree, err := ir.layerTree() + if err != nil { + return nil, err + } + + // Calculate the stats for each image. + for i, img := range images { + stat, err := diskUsageForImage(ctx, img, tree) + if err != nil { + return nil, err + } + stats[i] = *stat + } + + return stats, nil +} + +// diskUsageForImage returns the disk-usage statistics for the spcified image. +func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) (*DiskUsageStat, error) { + stat := DiskUsageStat{ + ID: image.ID(), + Created: image.Created(), + } + + // Repository and tag. + var name, repository, tag string + for _, n := range image.Names() { + if len(n) > 0 { + name = n + break + } + } + if len(name) > 0 { + named, err := reference.ParseNormalizedNamed(name) + if err != nil { + return nil, err + } + repository = named.Name() + if tagged, isTagged := named.(reference.NamedTagged); isTagged { + tag = tagged.Tag() + } + } else { + repository = "<none>" + tag = "<none>" + } + stat.Repository = repository + stat.Tag = tag + + // Shared, unique and total size. + parent, err := tree.parent(ctx, image) + if err != nil { + return nil, err + } + childIDs, err := tree.children(ctx, image, false) + if err != nil { + return nil, err + } + // Optimistically set unique size to the full size of the image. + size, err := image.Size(ctx) + if err != nil { + return nil, err + } + stat.UniqueSize = *size + + if len(childIDs) > 0 { + // If we have children, we share everything. + stat.SharedSize = stat.UniqueSize + stat.UniqueSize = 0 + } else if parent != nil { + // If we have no children but a parent, remove the parent + // (shared) size from the unique one. + size, err := parent.Size(ctx) + if err != nil { + return nil, err + } + stat.UniqueSize -= *size + stat.SharedSize = *size + } + + stat.Size = stat.SharedSize + stat.UniqueSize + + // Number of containers using the image. + containers, err := image.Containers() + if err != nil { + return nil, err + } + stat.Containers = len(containers) + + return &stat, nil +} diff --git a/libpod/info.go b/libpod/info.go index 050d792bc..153000b6f 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -162,7 +162,7 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) { return nil, errors.Wrapf(err, "error parsing system uptime") } - // TODO Isnt there a simple lib for this, something like humantime? + // TODO Isn't there a simple lib for this, something like humantime? hoursFound := false var timeBuffer bytes.Buffer var hoursBuffer bytes.Buffer diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index bb138ca14..5769e5580 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -64,6 +64,7 @@ type ConmonOCIRuntime struct { logSizeMax int64 noPivot bool reservePorts bool + runtimeFlags []string supportsJSON bool supportsKVM bool supportsNoCgroups bool @@ -76,7 +77,7 @@ type ConmonOCIRuntime struct { // 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, runtimeCfg *config.Config) (OCIRuntime, error) { +func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeFlags []string, runtimeCfg *config.Config) (OCIRuntime, error) { if name == "" { return nil, errors.Wrapf(define.ErrInvalidArg, "the OCI runtime must be provided a non-empty name") } @@ -98,6 +99,7 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime runtime := new(ConmonOCIRuntime) runtime.name = name runtime.conmonPath = conmonPath + runtime.runtimeFlags = runtimeFlags runtime.conmonEnv = runtimeCfg.Engine.ConmonEnvVars runtime.cgroupManager = runtimeCfg.Engine.CgroupManager @@ -378,7 +380,7 @@ func (r *ConmonOCIRuntime) StartContainer(ctr *Container) error { 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, "start", ctr.ID()); err != nil { + if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "start", ctr.ID())...); err != nil { return err } @@ -398,10 +400,11 @@ func (r *ConmonOCIRuntime) KillContainer(ctr *Container, signal uint, all bool) } env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} var args []string + args = append(args, r.runtimeFlags...) if all { - args = []string{"kill", "--all", ctr.ID(), fmt.Sprintf("%d", signal)} + args = append(args, "kill", "--all", ctr.ID(), fmt.Sprintf("%d", signal)) } else { - args = []string{"kill", ctr.ID(), fmt.Sprintf("%d", signal)} + 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 { return errors.Wrapf(err, "error sending signal to container %s", ctr.ID()) @@ -478,7 +481,7 @@ func (r *ConmonOCIRuntime) DeleteContainer(ctr *Container) error { return err } env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, "delete", "--force", ctr.ID()) + return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "delete", "--force", ctr.ID())...) } // PauseContainer pauses the given container. @@ -488,7 +491,7 @@ func (r *ConmonOCIRuntime) PauseContainer(ctr *Container) error { return err } env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, "pause", ctr.ID()) + return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, append(r.runtimeFlags, "pause", ctr.ID())...) } // UnpauseContainer unpauses the given container. @@ -498,7 +501,7 @@ func (r *ConmonOCIRuntime) UnpauseContainer(ctr *Container) error { return err } env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, "resume", ctr.ID()) + 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. @@ -765,6 +768,7 @@ func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options Container logrus.Debugf("Writing checkpoint to %s", imagePath) logrus.Debugf("Writing checkpoint logs to %s", workPath) args := []string{} + args = append(args, r.runtimeFlags...) args = append(args, "checkpoint") args = append(args, "--image-path") args = append(args, imagePath) @@ -1310,6 +1314,13 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p "--exit-dir", exitDir, "--socket-dir-path", r.socketsDir, } + if len(r.runtimeFlags) > 0 { + rFlags := []string{} + for _, arg := range r.runtimeFlags { + rFlags = append(rFlags, "--runtime-arg", arg) + } + args = append(args, rFlags...) + } if r.cgroupManager == config.SystemdCgroupsManager && !ctr.config.NoCgroups && ctr.config.CgroupsMode != cgroupSplit { args = append(args, "-s") diff --git a/libpod/oci_conmon_unsupported.go b/libpod/oci_conmon_unsupported.go index 28d6ef12f..2504c31f0 100644 --- a/libpod/oci_conmon_unsupported.go +++ b/libpod/oci_conmon_unsupported.go @@ -17,7 +17,7 @@ type ConmonOCIRuntime struct { } // newConmonOCIRuntime is not supported on this OS. -func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeCfg *config.Config) (OCIRuntime, error) { +func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeFlags []string, runtimeCfg *config.Config) (OCIRuntime, error) { return nil, define.ErrNotImplemented } diff --git a/libpod/options.go b/libpod/options.go index 7eec530ea..d592124bc 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -530,6 +530,17 @@ func WithEnableSDNotify() RuntimeOption { } } +// WithRuntimeFlags adds the global runtime flags to the container config +func WithRuntimeFlags(runtimeFlags []string) RuntimeOption { + return func(rt *Runtime) error { + if rt.valid { + return define.ErrRuntimeFinalized + } + rt.runtimeFlags = runtimeFlags + return nil + } +} + // Container Creation Options // WithShmDir sets the directory that should be mounted on /dev/shm. @@ -608,7 +619,7 @@ func WithSecLabels(labelOpts []string) CtrCreateOption { } } -// WithUser sets the user identity field in configutation. +// WithUser sets the user identity field in configuration. // Valid uses [user | user:group | uid | uid:gid | user:gid | uid:group ]. func WithUser(user string) CtrCreateOption { return func(ctr *Container) error { diff --git a/libpod/runtime.go b/libpod/runtime.go index 1d2e624d8..fdd9ebcc8 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -53,6 +53,7 @@ type Runtime struct { imageContext *types.SystemContext defaultOCIRuntime OCIRuntime ociRuntimes map[string]OCIRuntime + runtimeFlags []string netPlugin ocicni.CNIPlugin conmonPath string imageRuntime *image.Runtime @@ -365,7 +366,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { // Initialize remaining OCI runtimes for name, paths := range runtime.config.Engine.OCIRuntimes { - ociRuntime, err := newConmonOCIRuntime(name, paths, runtime.conmonPath, runtime.config) + ociRuntime, err := newConmonOCIRuntime(name, paths, runtime.conmonPath, runtime.runtimeFlags, runtime.config) if err != nil { // Don't fatally error. // This will allow us to ship configs including optional @@ -385,7 +386,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { if strings.HasPrefix(runtime.config.Engine.OCIRuntime, "/") { name := filepath.Base(runtime.config.Engine.OCIRuntime) - ociRuntime, err := newConmonOCIRuntime(name, []string{runtime.config.Engine.OCIRuntime}, runtime.conmonPath, runtime.config) + ociRuntime, err := newConmonOCIRuntime(name, []string{runtime.config.Engine.OCIRuntime}, runtime.conmonPath, runtime.runtimeFlags, runtime.config) if err != nil { return err } diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go index 61f895c29..289bf4a2d 100644 --- a/pkg/api/handlers/compat/events.go +++ b/pkg/api/handlers/compat/events.go @@ -17,7 +17,7 @@ import ( ) // filtersFromRequests extracts the "filters" parameter from the specified -// http.Request. The paramater can either be a `map[string][]string` as done +// http.Request. The parameter can either be a `map[string][]string` as done // in new versions of Docker and libpod, or a `map[string]map[string]bool` as // done in older versions of Docker. We have to do a bit of Yoga to support // both - just as Docker does as well. diff --git a/pkg/api/server/register_play.go b/pkg/api/server/register_play.go index a96f61099..9b27f36e4 100644 --- a/pkg/api/server/register_play.go +++ b/pkg/api/server/register_play.go @@ -24,7 +24,7 @@ func (s *APIServer) registerPlayHandlers(r *mux.Router) error { // name: tlsVerify // type: boolean // default: true - // description: Require HTTPS and verify signatures when contating registries. + // description: Require HTTPS and verify signatures when contacting registries. // - in: body // name: request // description: Kubernetes YAML file. diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index ffa65f7e5..69a7da869 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -126,7 +126,7 @@ func encodeMultiAuthConfigs(authConfigs map[string]types.DockerAuthConfig) (stri // one or more container registries. If tmpDir is empty, the system's default // TMPDIR will be used. func authConfigsToAuthFile(authConfigs map[string]types.DockerAuthConfig) (string, error) { - // Intitialize an empty temporary JSON file. + // Initialize an empty temporary JSON file. tmpFile, err := ioutil.TempFile("", "auth.json.") if err != nil { return "", err diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go index 2b2fa9b7c..82e5c7541 100644 --- a/pkg/bindings/test/system_test.go +++ b/pkg/bindings/test/system_test.go @@ -119,7 +119,7 @@ var _ = Describe("Podman system", func() { // Alpine image should not be pruned as used by running container Expect(systemPruneResponse.ImagePruneReport.Report.Id). ToNot(ContainElement("docker.io/library/alpine:latest")) - // Though unsed volume is available it should not be pruned as flag set to false. + // Though unused volume is available it should not be pruned as flag set to false. Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0)) }) diff --git a/pkg/domain/entities/engine.go b/pkg/domain/entities/engine.go index 6776d09e9..f23d964e5 100644 --- a/pkg/domain/entities/engine.go +++ b/pkg/domain/entities/engine.go @@ -46,6 +46,7 @@ type PodmanConfig struct { RegistriesConf string // allows for specifying a custom registries.conf Remote bool // Connection to Podman API Service will use RESTful API RuntimePath string // --runtime flag will set Engine.RuntimePath + RuntimeFlags []string // global flags for the container runtime Span opentracing.Span // tracing object SpanCloser io.Closer // Close() for tracing object SpanCtx context.Context // context to use when tracing diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index 0823bc64e..2ba369b83 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -32,7 +32,7 @@ type PlayKubePod struct { ID string // Containers - the IDs of the containers running in the created pod. Containers []string - // Logs - non-fatal erros and log messages while processing. + // Logs - non-fatal errors and log messages while processing. Logs []string } diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go index 55f73bf65..672d0a69f 100644 --- a/pkg/domain/infra/abi/manifest.go +++ b/pkg/domain/infra/abi/manifest.go @@ -130,7 +130,7 @@ func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAd func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opts entities.ManifestAnnotateOptions) (string, error) { listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0]) if err != nil { - return "", errors.Wrapf(err, "error retreiving local image from image name %s", names[0]) + return "", errors.Wrapf(err, "error retrieving local image from image name %s", names[0]) } digest, err := digest.Parse(names[1]) if err != nil { diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 914a7681d..57c098166 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -17,7 +17,6 @@ import ( "github.com/containers/podman/v2/pkg/rootless" "github.com/containers/podman/v2/pkg/util" "github.com/containers/podman/v2/utils" - "github.com/docker/distribution/reference" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -199,71 +198,32 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System dfImages = []*entities.SystemDfImageReport{} ) - // Get Images and iterate them + // Compute disk-usage stats for all local images. imgs, err := ic.Libpod.ImageRuntime().GetImages() if err != nil { return nil, err } - for _, i := range imgs { - var sharedSize uint64 - cons, err := i.Containers() - if err != nil { - return nil, err - } - imageSize, err := i.Size(ctx) - if err != nil { - return nil, err - } - uniqueSize := *imageSize - parent, err := i.GetParent(ctx) - if err != nil { - return nil, err - } - if parent != nil { - parentSize, err := parent.Size(ctx) - if err != nil { - return nil, err - } - uniqueSize = *parentSize - *imageSize - sharedSize = *imageSize - uniqueSize - } - var name, repository, tag string - for _, n := range i.Names() { - if len(n) > 0 { - name = n - break - } - } - - if len(name) > 0 { - named, err := reference.ParseNormalizedNamed(name) - if err != nil { - return nil, err - } - repository = named.Name() - if tagged, isTagged := named.(reference.NamedTagged); isTagged { - tag = tagged.Tag() - } - } else { - repository = "<none>" - tag = "<none>" - } + imageStats, err := ic.Libpod.ImageRuntime().DiskUsage(ctx, imgs) + if err != nil { + return nil, err + } + for _, stat := range imageStats { report := entities.SystemDfImageReport{ - Repository: repository, - Tag: tag, - ImageID: i.ID(), - Created: i.Created(), - Size: int64(*imageSize), - SharedSize: int64(sharedSize), - UniqueSize: int64(uniqueSize), - Containers: len(cons), + Repository: stat.Repository, + Tag: stat.Tag, + ImageID: stat.ID, + Created: stat.Created, + Size: int64(stat.Size), + SharedSize: int64(stat.SharedSize), + UniqueSize: int64(stat.UniqueSize), + Containers: stat.Containers, } dfImages = append(dfImages, &report) } - // GetContainers and iterate them + // Get Containers and iterate them cons, err := ic.Libpod.GetAllContainers() if err != nil { return nil, err diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go index a88347e24..f9b8106ef 100644 --- a/pkg/domain/infra/runtime_libpod.go +++ b/pkg/domain/infra/runtime_libpod.go @@ -156,6 +156,14 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo options = append(options, libpod.WithRenumber()) } + if len(cfg.RuntimeFlags) > 0 { + runtimeFlags := []string{} + for _, arg := range cfg.RuntimeFlags { + runtimeFlags = append(runtimeFlags, "--"+arg) + } + options = append(options, libpod.WithRuntimeFlags(runtimeFlags)) + } + // Only set this if the user changes storage config on the command line if storageSet { options = append(options, libpod.WithStorageConfig(storageOpts)) diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 062b38a70..35550b9be 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -19,6 +19,7 @@ import ( "github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/bindings/containers" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/errorhandling" "github.com/containers/podman/v2/pkg/specgen" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -537,8 +538,8 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta // de-spaghetti the code. defer func() { if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr || - errors.Cause(err) == define.ErrCtrRemoved { + if errorhandling.Contains(err, define.ErrNoSuchCtr) || + errorhandling.Contains(err, define.ErrCtrRemoved) { logrus.Warnf("Container %s does not exist: %v", con.ID, err) } else { logrus.Errorf("Error removing container %s: %v", con.ID, err) @@ -556,7 +557,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta // Determine why the wait failed. If the container doesn't exist, // consult the events. - if !strings.Contains(waitErr.Error(), define.ErrNoSuchCtr.Error()) { + if !errorhandling.Contains(waitErr, define.ErrNoSuchCtr) { return &report, waitErr } diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go index 3117b0ca4..ca6b60bc5 100644 --- a/pkg/errorhandling/errorhandling.go +++ b/pkg/errorhandling/errorhandling.go @@ -57,3 +57,11 @@ func CloseQuiet(f *os.File) { logrus.Errorf("unable to close file %s: %q", f.Name(), err) } } + +// Contains checks if err's message contains sub's message. Contains should be +// used iff either err or sub has lost type information (e.g., due to +// marshaling). For typed errors, please use `errors.Contains(...)` or `Is()` +// in recent version of Go. +func Contains(err error, sub error) bool { + return strings.Contains(err.Error(), sub.Error()) +} diff --git a/pkg/network/netconflist_test.go b/pkg/network/netconflist_test.go index a82a0140a..5893bf985 100644 --- a/pkg/network/netconflist_test.go +++ b/pkg/network/netconflist_test.go @@ -28,7 +28,7 @@ func TestNewIPAMDefaultRoute(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got, err := NewIPAMDefaultRoute(tt.isIPv6) if err != nil { - t.Errorf("no errorr expected: %v", err) + t.Errorf("no error expected: %v", err) } if !reflect.DeepEqual(got, tt.want) { t.Errorf("NewIPAMDefaultRoute() = %v, want %v", got, tt.want) diff --git a/pkg/network/network.go b/pkg/network/network.go index db625da56..c4c1ff67f 100644 --- a/pkg/network/network.go +++ b/pkg/network/network.go @@ -206,7 +206,7 @@ func InspectNetwork(config *config.Config, name string) (map[string]interface{}, } // Exists says whether a given network exists or not; it meant -// specifically for restful reponses so 404s can be used +// specifically for restful responses so 404s can be used func Exists(config *config.Config, name string) (bool, error) { _, err := ReadRawCNIConfByName(config, name) if err != nil { diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index 5e97620cc..42228540c 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -334,7 +334,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM } else { defaultEnv, err = env.ParseSlice(runtimeConfig.Containers.Env) if err != nil { - return nil, errors.Wrap(err, "Env fields in containers.conf failed ot parse") + return nil, errors.Wrap(err, "Env fields in containers.conf failed to parse") } defaultEnv = env.Join(env.DefaultEnvVariables(), defaultEnv) } diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go index 182ae74a7..7f55317ff 100644 --- a/pkg/specgen/generate/storage.go +++ b/pkg/specgen/generate/storage.go @@ -46,7 +46,7 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru return nil, nil, err } - // Supercede from --volumes-from. + // Supersede from --volumes-from. for dest, mount := range volFromMounts { baseMounts[dest] = mount } diff --git a/pkg/util/utils_linux_test.go b/pkg/util/utils_linux_test.go index 38e6dbef9..aa193bbef 100644 --- a/pkg/util/utils_linux_test.go +++ b/pkg/util/utils_linux_test.go @@ -8,7 +8,7 @@ import ( ) func TestGetImageConfigStopSignal(t *testing.T) { - // Linux-only beause parsing signal names is not supported on non-Linux systems by + // Linux-only because parsing signal names is not supported on non-Linux systems by // pkg/signal. stopSignalValidInt, err := GetImageConfig([]string{"STOPSIGNAL 9"}) require.Nil(t, err) diff --git a/pkg/varlink/io.podman.varlink b/pkg/varlink/io.podman.varlink index 6240936d0..cd6316011 100644 --- a/pkg/varlink/io.podman.varlink +++ b/pkg/varlink/io.podman.varlink @@ -257,7 +257,7 @@ type InfoRegistry ( blocked: []string ) -# InfoStore describes the host's storage informatoin +# InfoStore describes the host's storage information type InfoStore ( containers: int, images: int, diff --git a/pkg/varlinkapi/container.go b/pkg/varlinkapi/container.go index bf3ed0022..c4e8c1feb 100644 --- a/pkg/varlinkapi/container.go +++ b/pkg/varlinkapi/container.go @@ -750,7 +750,7 @@ func portsToString(ports []ocicni.PortMapping) string { continue } } - // For each portMapKey, format group list and appned to output string. + // For each portMapKey, format group list and append to output string. for _, portKey := range groupKeyList { group := portGroupMap[portKey] portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last)) @@ -794,7 +794,7 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim return runLabel, imageName, err } -// GenerateRunlabelCommand generates the command that will eventually be execucted by Podman. +// GenerateRunlabelCommand generates the command that will eventually be executed by Podman. func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]string, extraArgs []string, globalOpts string) ([]string, []string, error) { // If no name is provided, we use the image's basename instead. if name == "" { diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go index 1054f55f6..8339b7732 100644 --- a/test/e2e/containers_conf_test.go +++ b/test/e2e/containers_conf_test.go @@ -93,7 +93,7 @@ var _ = Describe("Podman run", func() { Expect(session.OutputToString()).ToNot(Equal(cap.OutputToString())) }) - It("podman Regular capabilties", func() { + It("podman Regular capabilities", func() { SkipIfRootless() os.Setenv("CONTAINERS_CONF", "config/containers.conf") setup := podmanTest.RunTopContainer("test1") @@ -105,7 +105,7 @@ var _ = Describe("Podman run", func() { Expect(result.OutputToString()).To(ContainSubstring("NET_RAW")) }) - It("podman drop capabilties", func() { + It("podman drop capabilities", func() { os.Setenv("CONTAINERS_CONF", "config/containers-caps.conf") setup := podmanTest.RunTopContainer("test1") setup.WaitWithDefaultTimeout() diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go index 1d592a42d..9c9d85194 100644 --- a/test/e2e/prune_test.go +++ b/test/e2e/prune_test.go @@ -261,7 +261,7 @@ var _ = Describe("Podman prune", func() { // Two as pods infra container and one newly created. Expect(podmanTest.NumberOfContainers()).To(Equal(3)) - // image list current count should not be pruned if all flag isnt enabled + // image list current count should not be pruned if all flag isn't enabled session = podmanTest.Podman([]string{"images"}) session.WaitWithDefaultTimeout() numberOfImages := len(session.OutputToStringArray()) diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go index a2338c924..66233412c 100644 --- a/test/e2e/ps_test.go +++ b/test/e2e/ps_test.go @@ -484,7 +484,7 @@ var _ = Describe("Podman ps", func() { Expect(ps.OutputToString()).To(ContainSubstring("0.0.0.0:8080->80/tcp")) }) - It("podman ps truncate long create commad", func() { + It("podman ps truncate long create command", func() { session := podmanTest.Podman([]string{"run", ALPINE, "echo", "very", "long", "create", "command"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/python/dockerpy/tests/test_images.py b/test/python/dockerpy/tests/test_images.py index 5eae61c2f..602a86de2 100644 --- a/test/python/dockerpy/tests/test_images.py +++ b/test/python/dockerpy/tests/test_images.py @@ -59,7 +59,7 @@ class TestImages(unittest.TestCase): self.assertFalse # Validates if name updates when the image is retagged. - @unittest.skip("dosent work now") + @unittest.skip("doesn't work now") def test_retag_valid_image(self): client.tag(constant.ALPINE_SHORTNAME, "demo", "rename") alpine_image = client.inspect_image(constant.ALPINE) diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 4e518c571..518d902a7 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -61,6 +61,12 @@ echo $rand | 0 | $rand is "$tests_run" "$(grep . <<<$tests | wc -l)" "Ran the full set of tests" } +@test "podman run - globle runtime option" { + skip_if_remote "runtime flag is not passing over remote" + run_podman 126 --runtime-flag invalidflag run --rm $IMAGE + is "$output" ".*invalidflag" "failed when passing undefined flags to the runtime" +} + # 'run --preserve-fds' passes a number of additional file descriptors into the container @test "podman run --preserve-fds" { skip_if_remote "preserve-fds is meaningless over remote" diff --git a/test/system/070-build.bats b/test/system/070-build.bats index 997699ecb..66f6610ea 100644 --- a/test/system/070-build.bats +++ b/test/system/070-build.bats @@ -30,9 +30,26 @@ EOF run_podman rmi -f build_test } +@test "podman build - global runtime flags test" { + skip_if_remote "FIXME: pending #7136" + + rand_content=$(random_string 50) + + tmpdir=$PODMAN_TMPDIR/build-test + run mkdir -p $tmpdir + containerfile=$tmpdir/Containerfile + cat >$containerfile <<EOF +FROM $IMAGE +RUN echo $rand_content +EOF + + run_podman 125 --runtime-flag invalidflag build -t build_test $tmpdir + is "$output" ".*invalidflag" "failed when passing undefined flags to the runtime" +} + # Regression from v1.5.0. This test passes fine in v1.5.0, fails in 1.6 @test "podman build - cache (#3920)" { - skip_if_remote "FIXME: pending #7136" + skip_if_remote "FIXME: pending #7136, runtime flag is not passing over remote" if is_remote && is_rootless; then skip "unreliable with podman-remote and rootless; #2972" fi @@ -128,7 +145,7 @@ echo "\$1" printenv | grep MYENV | sort | sed -e 's/^MYENV.=//' EOF - # For overridding with --env-file + # For overriding with --env-file cat >$PODMAN_TMPDIR/env-file <<EOF MYENV3=$s_env3 http_proxy=http-proxy-in-env-file diff --git a/test/utils/common_function_test.go b/test/utils/common_function_test.go index 26bb8b473..0bbc31d5b 100644 --- a/test/utils/common_function_test.go +++ b/test/utils/common_function_test.go @@ -75,10 +75,10 @@ var _ = Describe("Common functions test", func() { Expect(newer).To(Equal(expect), "Version compare results is not as expect.") Expect(err == nil).To(Equal(isNil), "Error is not as expect.") }, - Entry("Invlid kernel version: 0", "0", false, false), + Entry("Invalid kernel version: 0", "0", false, false), Entry("Older kernel version:0.0", "0.0", true, true), Entry("Newer kernel version: 100.17.14", "100.17.14", false, true), - Entry("Invlid kernel version: I am not a kernel version", "I am not a kernel version", false, false), + Entry("Invalid kernel version: I am not a kernel version", "I am not a kernel version", false, false), ) DescribeTable("Test TestIsCommandAvailable", diff --git a/troubleshooting.md b/troubleshooting.md index 9677b1821..4b0f2e1e4 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -42,7 +42,7 @@ $ podman run -v ~/mycontent:/content:Z fedora touch /content/file Make sure the content is private for the container. Do not relabel system directories and content. Relabeling system content might cause other confined services on your machine to fail. For these -types of containers we recommmend that disable SELinux separation. The option `--security-opt label=disable` +types of containers we recommend that disable SELinux separation. The option `--security-opt label=disable` will disable SELinux separation for the container. $ podman run --security-opt label=disable -v ~:/home/user fedora touch /home/user/file @@ -533,7 +533,7 @@ With the default detach key combo ctrl-p,ctrl-q, shell history navigation display this previous command. Or anything else. Conmon is waiting for an additional character to see if the user wants to detach from the container. Adding additional characters to the command will cause it to be displayed along -with the additonal character. If the user types ctrl-p a second time the shell +with the additional character. If the user types ctrl-p a second time the shell display the 2nd to last command. #### Solution @@ -546,7 +546,7 @@ podman run -ti --detach-keys ctrl-q,ctrl-q fedora sh ``` To make this change the default for all containers, users can modify the -containers.conf file. This can be done simply in your homedir, but adding the +containers.conf file. This can be done simply in your home directory, but adding the following lines to users containers.conf ``` @@ -617,3 +617,30 @@ If you encounter a `fuse: device not found` error when running the container ima the fuse kernel module has not been loaded on your host system. Use the command `modprobe fuse` to load the module and then run the container image afterwards. To enable this automatically at boot time, you can add a configuration file to `/etc/modules.load.d`. See `man modules-load.d` for more details. + +### 25) podman run --rootfs link/to//read/only/dir does not work + +An error such as "OCI runtime error" on a read-only filesystem or the error "{image} is not an absolute path or is a symlink" are often times indicators for this issue. For more details, review this [issue]( +https://github.com/containers/podman/issues/5895). + +#### Symptom + +Rootless Podman requires certain files to exist in a file system in order to run. +Podman will create /etc/resolv.conf, /etc/hosts and other file descriptors on the rootfs in order +to mount volumes on them. + +#### Solution + +Run the container once in read/write mode, Podman will generate all of the FDs on the rootfs, and +from that point forward you can run with a read-only rootfs. + +$ podman run --rm --rootfs /path/to/rootfs true + +The command above will create all the missing directories needed to run the container. + +After that, it can be used in read only mode, by multiple containers at the same time: + +$ podman run --read-only --rootfs /path/to/rootfs .... + +Another option would be to create an overlay file system on the directory as a lower and then +then allow podman to create the files on the upper. |