diff options
183 files changed, 3414 insertions, 3053 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index a97a22efd..4156e3082 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -30,7 +30,7 @@ env: PRIOR_UBUNTU_NAME: "ubuntu-19" # Google-cloud VM Images - IMAGE_SUFFIX: "c6323493627232256" + IMAGE_SUFFIX: "c5402398833246208" FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}" PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}" UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${IMAGE_SUFFIX}" @@ -148,7 +148,6 @@ smoke_task: build_task: alias: 'build' name: 'Build for $DISTRO_NV' - only_if: ¬_docs $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' gce_instance: &standardvm image_project: libpod-218412 zone: "us-central1-a" @@ -210,7 +209,6 @@ build_task: validate_task: name: "Validate $DISTRO_NV Build" alias: validate - only_if: *not_docs depends_on: - ext_svc_check - automation @@ -238,7 +236,7 @@ validate_task: bindings_task: name: "Test Bindings" alias: bindings - only_if: *not_docs + only_if: ¬_docs $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' skip: *branch depends_on: - build @@ -358,6 +358,7 @@ remotesystem: localapiv2: env PODMAN=./bin/podman ./test/apiv2/test-apiv2 env PODMAN=./bin/podman ${PYTHON} -m unittest discover -v ./test/apiv2/rest_api/ + env PODMAN=./bin/podman ${PYTHON} -m unittest discover -v ./test/python/docker .PHONY: remoteapiv2 remoteapiv2: @@ -391,10 +392,6 @@ docdir: .PHONY: docs docs: $(MANPAGES) ## Generate documentation -.PHONE: xref_helpmsgs_manpages -xref_helpmsgs_manpages: - ./hack/xref-helpmsgs-manpages - install-podman-remote-%-docs: podman-remote docs $(MANPAGES) rm -rf docs/build/remote mkdir -p docs/build/remote @@ -404,6 +401,7 @@ install-podman-remote-%-docs: podman-remote docs $(MANPAGES) .PHONY: man-page-check man-page-check: hack/man-page-checker + hack/xref-helpmsgs-manpages .PHONY: swagger-check swagger-check: diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index 8b2efc988..4b52663c3 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -133,6 +133,7 @@ func stringMaptoArray(m map[string]string) []string { // a specgen spec. func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroupsManager string) (*ContainerCLIOpts, []string, error) { var ( + aliases []string capAdd []string cappDrop []string entrypoint string @@ -242,8 +243,11 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup // network names endpointsConfig := cc.NetworkingConfig.EndpointsConfig cniNetworks := make([]string, 0, len(endpointsConfig)) - for netName := range endpointsConfig { + for netName, endpoint := range endpointsConfig { cniNetworks = append(cniNetworks, netName) + if len(endpoint.Aliases) > 0 { + aliases = append(aliases, endpoint.Aliases...) + } } // netMode @@ -262,6 +266,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup // defined when there is only one network. netInfo := entities.NetOptions{ AddHosts: cc.HostConfig.ExtraHosts, + Aliases: aliases, CNINetworks: cniNetworks, DNSOptions: cc.HostConfig.DNSOptions, DNSSearch: cc.HostConfig.DNSSearch, diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go index 1b8297c36..935a5f7b9 100644 --- a/cmd/podman/common/netflags.go +++ b/cmd/podman/common/netflags.go @@ -43,6 +43,10 @@ func GetNetFlags() *pflag.FlagSet { "network", containerConfig.NetNS(), "Connect a container to a network", ) + netFlags.StringSlice( + "network-alias", []string{}, + "Add network-scoped alias for the container", + ) netFlags.StringSliceP( "publish", "p", []string{}, "Publish a container's port, or a range of ports, to the host (default [])", @@ -158,6 +162,9 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) { } opts.NoHosts, err = cmd.Flags().GetBool("no-hosts") + if err != nil { + return nil, err + } if cmd.Flags().Changed("network") { network, err := cmd.Flags().GetString("network") @@ -181,5 +188,12 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) { opts.CNINetworks = cniNets } + aliases, err := cmd.Flags().GetStringSlice("network-alias") + if err != nil { + return nil, err + } + if len(aliases) > 0 { + opts.Aliases = aliases + } return &opts, err } diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index ca1e25be1..39ff02857 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -396,6 +396,17 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string s.ShmSize = &shmSize } s.CNINetworks = c.Net.CNINetworks + + // Network aliases + if len(c.Net.Aliases) > 0 { + // build a map of aliases where key=cniName + aliases := make(map[string][]string, len(s.CNINetworks)) + for _, cniNetwork := range s.CNINetworks { + aliases[cniNetwork] = c.Net.Aliases + } + s.Aliases = aliases + } + s.HostAdd = c.Net.AddHosts s.UseImageResolvConf = c.Net.UseImageResolvConf s.DNSServers = c.Net.DNSServers diff --git a/cmd/podman/images/search.go b/cmd/podman/images/search.go index 774b39d3a..7de6a7316 100644 --- a/cmd/podman/images/search.go +++ b/cmd/podman/images/search.go @@ -1,6 +1,7 @@ package images import ( + "fmt" "os" "text/tabwriter" "text/template" @@ -81,7 +82,7 @@ func init() { // searchFlags set the flags for the pull command. func searchFlags(flags *pflag.FlagSet) { flags.StringSliceVarP(&searchOptions.Filters, "filter", "f", []string{}, "Filter output based on conditions provided (default [])") - flags.StringVar(&searchOptions.Format, "format", "", "Change the output format to a Go template") + flags.StringVar(&searchOptions.Format, "format", "", "Change the output format to JSON or a Go template") flags.IntVar(&searchOptions.Limit, "limit", 0, "Limit the number of results") flags.BoolVar(&searchOptions.NoTrunc, "no-trunc", false, "Do not truncate the output") flags.StringVar(&searchOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") @@ -135,6 +136,13 @@ func imageSearch(cmd *cobra.Command, args []string) error { return errors.Errorf("filters are not applicable to list tags result") } row = "{{.Name}}\t{{.Tag}}\n" + case report.IsJSON(searchOptions.Format): + prettyJSON, err := json.MarshalIndent(searchReport, "", " ") + if err != nil { + return err + } + fmt.Println(string(prettyJSON)) + return nil case cmd.Flags().Changed("format"): renderHeaders = parse.HasTable(searchOptions.Format) row = report.NormalizeFormat(searchOptions.Format) diff --git a/cmd/podman/networks/create.go b/cmd/podman/networks/create.go index 74646090d..c06011ce9 100644 --- a/cmd/podman/networks/create.go +++ b/cmd/podman/networks/create.go @@ -35,8 +35,7 @@ func networkCreateFlags(flags *pflag.FlagSet) { flags.StringVar(&networkCreateOptions.MacVLAN, "macvlan", "", "create a Macvlan connection based on this device") // TODO not supported yet // flags.StringVar(&networkCreateOptions.IPamDriver, "ipam-driver", "", "IP Address Management Driver") - // TODO enable when IPv6 is working - // flags.BoolVar(&networkCreateOptions.IPV6, "IPv6", false, "enable IPv6 networking") + flags.BoolVar(&networkCreateOptions.IPv6, "ipv6", false, "enable IPv6 networking") flags.IPNetVar(&networkCreateOptions.Subnet, "subnet", net.IPNet{}, "subnet in CIDR format") flags.BoolVar(&networkCreateOptions.DisableDNS, "disable-dns", false, "disable dns plugin") } diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go index feb112ad7..4f34b2b76 100644 --- a/cmd/podman/play/kube.go +++ b/cmd/podman/play/kube.go @@ -52,6 +52,7 @@ func init() { flags.SetNormalizeFunc(utils.AliasFlags) flags.StringVar(&kubeOptions.CredentialsCLI, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") flags.StringVar(&kubeOptions.Network, "network", "", "Connect pod to CNI network(s)") + flags.StringVar(&kubeOptions.LogDriver, "log-driver", "", "Logging driver for the container") flags.BoolVarP(&kubeOptions.Quiet, "quiet", "q", false, "Suppress output information when pulling images") flags.BoolVar(&kubeOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") flags.StringVar(&kubeOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh index 1d05dfa71..bf2b1a52b 100755 --- a/contrib/cirrus/runner.sh +++ b/contrib/cirrus/runner.sh @@ -50,6 +50,7 @@ function _run_validate() { # Confirm compile via prior task + cache bin/podman --version bin/podman-remote --version + make validate # Some items require a build } @@ -63,6 +64,12 @@ function _run_unit() { } function _run_apiv2() { + # TODO Remove once VM's with dependency + if [[ "$OS_RELEASE_ID" == "fedora" ]]; then + dnf install -y python3-docker + else + apt-get -qq -y install python3-docker + fi make localapiv2 |& logformatter } diff --git a/docs/source/Commands.rst b/docs/source/Commands.rst index 096bdbedf..881dcb4b6 100644 --- a/docs/source/Commands.rst +++ b/docs/source/Commands.rst @@ -3,6 +3,7 @@ Commands ======== +:doc:`Podman <markdown/podman.1>` (Pod Manager) Global Options :doc:`attach <markdown/podman-attach.1>` Attach to a running container diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css new file mode 100644 index 000000000..6974d8514 --- /dev/null +++ b/docs/source/_static/custom.css @@ -0,0 +1,7 @@ +h2,h3,h4,h5,h6{ + /* Sphinx doesn't respect using a h4 header without using h1,h2,h3. + The flag names will be rendered as h2 and by default way to big + so make the font size for all headers except h1 smaller. + */ + font-size: 120% !important; +} diff --git a/docs/source/conf.py b/docs/source/conf.py index d95290f72..6adaf4308 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -53,5 +53,8 @@ html_theme = 'alabaster' # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] +html_css_files = [ + 'custom.css', +] # -- Extension configuration ------------------------------------------------- diff --git a/docs/source/markdown/podman-attach.1.md b/docs/source/markdown/podman-attach.1.md index cb3ffa92e..06d3c205d 100644 --- a/docs/source/markdown/podman-attach.1.md +++ b/docs/source/markdown/podman-attach.1.md @@ -18,22 +18,22 @@ Configure the keys sequence using the **--detach-keys** option, or specifying it in the **containers.conf** file: see **containers.conf(5)** for more information. ## OPTIONS -**--detach-keys**=*sequence* +#### **--detach-keys**=*sequence* Specify the key sequence for detaching a container. Format is a single character `[a-Z]` or one or more `ctrl-<value>` characters where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. Specifying "" will disable this feature. The default is *ctrl-p,ctrl-q*. -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**--no-stdin** +#### **--no-stdin** Do not attach STDIN. The default is false. -**--sig-proxy**=*true*|*false* +#### **--sig-proxy**=*true*|*false* Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is *true*. diff --git a/docs/source/markdown/podman-auto-update.1.md b/docs/source/markdown/podman-auto-update.1.md index 3ab097388..76dc85180 100644 --- a/docs/source/markdown/podman-auto-update.1.md +++ b/docs/source/markdown/podman-auto-update.1.md @@ -28,7 +28,7 @@ Systemd units that start and stop a container cannot run a new image. ## OPTIONS -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md index 1e1e1d27e..a411d32ab 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -9,67 +9,93 @@ podman\-build - Build a container image using a Containerfile **podman image build** [*options*] [*context*] ## DESCRIPTION -**podman build** Builds an image using instructions from one or more Containerfiles or Dockerfiles and a specified build context directory. A Containerfile uses the same syntax as a Dockerfile internally. For this document, a file referred to as a Containerfile can be a file named either 'Containerfile' or 'Dockerfile'. +**podman build** Builds an image using instructions from one or more +Containerfiles or Dockerfiles and a specified build context directory. A +Containerfile uses the same syntax as a Dockerfile internally. For this +document, a file referred to as a Containerfile can be a file named either +'Containerfile' or 'Dockerfile'. -The build context directory can be specified as the http(s) URL of an archive, git repository or Containerfile. +The build context directory can be specified as the http(s) URL of an archive, +git repository or Containerfile. -If no context directory is specified, then Podman will assume the current working directory as the build context, which should contain the Containerfile. +If no context directory is specified, then Podman will assume the current +working directory as the build context, which should contain the Containerfile. -Containerfiles ending with a ".in" suffix will be preprocessed via CPP(1). This can be useful to decompose Containerfiles into several reusable parts that can be used via CPP's **#include** directive. Notice, a Containerfile.in file can still be used by other tools when manually preprocessing them via `cpp -E`. +Containerfiles ending with a ".in" suffix will be preprocessed via CPP(1). This +can be useful to decompose Containerfiles into several reusable parts that can +be used via CPP's **#include** directive. Notice, a Containerfile.in file can +still be used by other tools when manually preprocessing them via `cpp -E`. -When the URL is an archive, the contents of the URL is downloaded to a temporary location and extracted before execution. +When the URL is an archive, the contents of the URL is downloaded to a temporary +location and extracted before execution. -When the URL is an Containerfile, the Containerfile is downloaded to a temporary location. +When the URL is an Containerfile, the Containerfile is downloaded to a temporary +location. -When a Git repository is set as the URL, the repository is cloned locally and then set as the context. +When a Git repository is set as the URL, the repository is cloned locally and +then set as the context. -NOTE: `podman build` uses code sourced from the `buildah` project to build container images. This `buildah` code creates `buildah` containers for the `RUN` options in container storage. In certain situations, when the `podman build` crashes or users kill the `podman build` process, these external containers can be left in container storage. Use the `podman ps --all --storage` command to see these contaienrs. External containers can be removed with the `podman rm --storage` command. +NOTE: `podman build` uses code sourced from the `buildah` project to build +container images. This `buildah` code creates `buildah` containers for the +`RUN` options in container storage. In certain situations, when the +`podman build` crashes or users kill the `podman build` process, these external +containers can be left in container storage. Use the `podman ps --all --storage` +command to see these contaienrs. External containers can be removed with the +`podman rm --storage` command. ## OPTIONS -**--add-host**=*host* +#### **--add-host**=*host* Add a custom host-to-IP mapping (host:ip) -Add a line to /etc/hosts. The format is hostname:ip. The **--add-host** option can be set multiple times. +Add a line to /etc/hosts. The format is hostname:ip. The **--add-host** option +can be set multiple times. -**--annotation**=*annotation* +#### **--annotation**=*annotation* -Add an image *annotation* (e.g. annotation=*value*) to the image metadata. Can be used multiple times. +Add an image *annotation* (e.g. annotation=*value*) to the image metadata. Can +be used multiple times. -Note: this information is not present in Docker image formats, so it is discarded when writing images in Docker formats. +Note: this information is not present in Docker image formats, so it is +discarded when writing images in Docker formats. -**--arch**=*arch* +#### **--arch**=*arch* -Set the ARCH of the image to the provided value instead of the architecture of the host. +Set the ARCH of the image to the provided value instead of the architecture of +the host. -**--authfile**=*path* +#### **--authfile**=*path* -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. -If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. +Path of the authentication file. Default is +${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. +If the authorization state is not found there, $HOME/.docker/config.json is +checked, which is set using `docker login`. -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` +Note: You can also override the default path of the authentication file by +setting the REGISTRY\_AUTH\_FILE environment variable. +`export REGISTRY_AUTH_FILE=path` -**--build-arg**=*arg=value* +#### **--build-arg**=*arg=value* Specifies a build argument and its value, which will be interpolated in instructions read from the Containerfiles in the same way that environment variables are, but which will not be added to environment variable list in the resulting image's configuration. -**--cache-from** +#### **--cache-from** -Images to utilize as potential cache sources. Podman does not currently support caching so this is a NOOP. +Images to utilize as potential cache sources. Podman does not currently support +caching so this is a NOOP. -**--cap-add**=*CAP\_xxx* +#### **--cap-add**=*CAP\_xxx* When executing RUN instructions, run the command specified in the instruction with the specified capability added to its capability set. Certain capabilities are granted by default; this option can be used to add more. -**--cap-drop**=*CAP\_xxx* +#### **--cap-drop**=*CAP\_xxx* When executing RUN instructions, run the command specified in the instruction with the specified capability removed from its capability set. @@ -82,34 +108,37 @@ If a capability is specified to both the **--cap-add** and **--cap-drop** options, it will be dropped, regardless of the order in which the options were given. -**--cert-dir**=*path* +#### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. -Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) +Default certificates directory is _/etc/containers/certs.d_. (Not available for +remote commands) -**--cgroup-parent**=*path* +#### **--cgroup-parent**=*path* -Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist. +Path to cgroups under which the cgroup for the container will be created. If the +path is not absolute, the path is considered to be relative to the cgroups path +of the init process. Cgroups will be created if they do not already exist. -**--compress** +#### **--compress** This option is added to be aligned with other containers CLIs. Podman doesn't communicate with a daemon or a remote server. Thus, compressing the data before sending it is irrelevant to Podman. -**--cni-config-dir**=*directory* +#### **--cni-config-dir**=*directory* Location of CNI configuration files which will dictate which plugins will be used to configure network interfaces and routing for containers created for handling `RUN` instructions, if those containers will be run in their own network namespaces, and networking is not disabled. -**--cni-plugin-path**=*directory[:directory[:directory[...]]]* +#### **--cni-plugin-path**=*directory[:directory[:directory[...]]]* List of directories in which the CNI plugins which will be used for configuring network namespaces can be found. -**--cpu-period**=*limit* +#### **--cpu-period**=*limit* Set the CPU period for the Completely Fair Scheduler (CFS), which is a duration in microseconds. Once the container's CPU quota is used up, it will @@ -120,7 +149,7 @@ On some systems, changing the CPU limits may not be allowed for non-root users. For more details, see https://github.com/containers/podman/blob/master/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error -**--cpu-quota**=*limit* +#### **--cpu-quota**=*limit* Limit the CPU Completely Fair Scheduler (CFS) quota. @@ -133,13 +162,13 @@ On some systems, changing the CPU limits may not be allowed for non-root users. For more details, see https://github.com/containers/podman/blob/master/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error -**--cpu-shares**, **-c**=*shares* +#### **--cpu-shares**, **-c**=*shares* CPU shares (relative weight) -By default, all containers get the same proportion of CPU cycles. This proportion -can be modified by changing the container's CPU share weighting relative -to the weighting of all other running containers. +By default, all containers get the same proportion of CPU cycles. This +proportion can be modified by changing the container's CPU share weighting +relative to the weighting of all other running containers. To modify the proportion from the default of 1024, use the **--cpu-shares** flag to set the weighting to 2 or higher. @@ -162,7 +191,8 @@ use 100% of each individual CPU core. For example, consider a system with more than three cores. If you start one container **{C0}** with **-c=512** running one process, and another container -**{C1}** with **-c=1024** running two processes, this can result in the following +**{C1}** with **-c=1024** running two processes, this can result in the +following division of CPU shares: PID container CPU CPU share @@ -170,25 +200,26 @@ division of CPU shares: 101 {C1} 1 100% of CPU1 102 {C1} 2 100% of CPU2 -**--cpuset-cpus**=*num* +#### **--cpuset-cpus**=*num* CPUs in which to allow execution (0-3, 0,1) -**--cpuset-mems**=*nodes* +#### **--cpuset-mems**=*nodes* -Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems. +Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on +NUMA systems. If you have four memory nodes on your system (0-3), use `--cpuset-mems=0,1` then processes in your container will only use memory from the first two memory nodes. -**--creds**=*creds* +#### **--creds**=*creds* The [username[:password]] to use to authenticate with the registry if required. -If one or both values are not supplied, a command line prompt will appear and the -value can be entered. The password is entered without echo. +If one or both values are not supplied, a command line prompt will appear and +the value can be entered. The password is entered without echo. -**--device**=_host-device_[**:**_container-device_][**:**_permissions_] +#### **--device**=_host-device_[**:**_container-device_][**:**_permissions_] Add a host device to the container. Optional *permissions* parameter can be used to specify device permissions, it is combination of @@ -201,9 +232,10 @@ The container will only store the major and minor numbers of the host device. Note: if the user only has access rights via a group, accessing the device from inside a rootless container will fail. The **crun**(1) runtime offers a -workaround for this by adding the option **--annotation run.oci.keep_original_groups=1**. +workaround for this by adding the option +#### **--annotation run.oci.keep_original_groups=1**. -**--disable-compression**, **-D** +#### **--disable-compression**, **-D** Don't compress filesystem layers when building the image unless it is required by the location where the image is being written. This is the default setting, @@ -212,29 +244,34 @@ registries, and images being written to local storage would only need to be decompressed again to be stored. Compression can be forced in all cases by specifying **--disable-compression=false**. -**--disable-content-trust** +#### **--disable-content-trust** This is a Docker specific option to disable image verification to a Docker registry and is not supported by Podman. This flag is a NOOP and provided solely for scripting compatibility. -**--dns**=*dns* +#### **--dns**=*dns* Set custom DNS servers -This option can be used to override the DNS configuration passed to the container. Typically this is necessary when the host DNS configuration is invalid for the container (e.g., 127.0.0.1). When this is the case the `--dns` flag is necessary for every run. +This option can be used to override the DNS configuration passed to the +container. Typically this is necessary when the host DNS configuration is +invalid for the container (e.g., 127.0.0.1). When this is the case the `--dns` +flag is necessary for every run. -The special value **none** can be specified to disable creation of /etc/resolv.conf in the container by Podman. The /etc/resolv.conf file in the image will be used without changes. +The special value **none** can be specified to disable creation of +/etc/resolv.conf in the container by Podman. The /etc/resolv.conf file in the +image will be used without changes. -**--dns-option**=*option* +#### **--dns-option**=*option* Set custom DNS options -**--dns-search**=*domain* +#### **--dns-search**=*domain* Set custom DNS search domains -**--file**, **-f**=*Containerfile* +#### **--file**, **-f**=*Containerfile* Specifies a Containerfile which contains instructions for building the image, either a local file or an **http** or **https** URL. If more than one @@ -247,11 +284,12 @@ context. If you specify `-f -`, the Containerfile contents will be read from stdin. -**--force-rm**=*true|false* +#### **--force-rm**=*true|false* -Always remove intermediate containers after a build, even if the build fails (default false). +Always remove intermediate containers after a build, even if the build fails +(default false). -**--format** +#### **--format** Control the format for the built image's manifest and configuration data. Recognized formats include *oci* (OCI image-spec v1.0, the default) and @@ -264,15 +302,15 @@ environment variable. `export BUILDAH_FORMAT=docker` Print usage statement -**--http-proxy** +#### **--http-proxy** Pass through HTTP Proxy environment variables. -**--iidfile**=*ImageIDfile* +#### **--iidfile**=*ImageIDfile* Write the image ID to the file. -**--ipc**=*how* +#### **--ipc**=*how* Sets the configuration for IPC namespaces when handling `RUN` instructions. The configured value can be "" (the empty string) or "container" to indicate @@ -281,7 +319,7 @@ that the IPC namespace in which `podman` itself is being run should be reused, or it can be the path to an IPC namespace which is already in use by another process. -**--isolation**=*type* +#### **--isolation**=*type* Controls what type of isolation is used for running processes as part of `RUN` instructions. Recognized types include *oci* (OCI-compatible runtime, the @@ -295,12 +333,16 @@ chroot(1) than container technology). Note: You can also override the default isolation type by setting the BUILDAH\_ISOLATION environment variable. `export BUILDAH_ISOLATION=oci` -**--jobs**=*number* -How many stages to run in parallel (default 1) +#### **--jobs**=*number* -**--label**=*label* +Run up to N concurrent stages in parallel. If the number of jobs is greater +than 1, stdin will be read from /dev/null. If 0 is specified, then there is +no limit in the number of jobs that run in parallel. -Add an image *label* (e.g. label=*value*) to the image metadata. Can be used multiple times. +#### **--label**=*label* + +Add an image *label* (e.g. label=*value*) to the image metadata. Can be used +multiple times. Users can set a special LABEL **io.containers.capabilities=CAP1,CAP2,CAP3** in a Containerfile that specified the list of Linux capabilities required for the @@ -312,34 +354,36 @@ capabilities is a subset of the default list. If the specified capabilities are not in the default set, Podman will print an error message and will run the container with the default capabilities. -**--layers** +#### **--layers** Cache intermediate images during the build process (Default is `true`). -Note: You can also override the default value of layers by setting the BUILDAH\_LAYERS -environment variable. `export BUILDAH_LAYERS=true` +Note: You can also override the default value of layers by setting the +BUILDAH\_LAYERS environment variable. `export BUILDAH_LAYERS=true` -**--logfile**=*filename* +#### **--logfile**=*filename* Log output which would be sent to standard output and standard error to the specified file instead of to standard output and standard error. -**--loglevel**=*number* +#### **--loglevel**=*number* Adjust the logging level up or down. Valid option values range from -2 to 3, with 3 being roughly equivalent to using the global *--debug* option, and values below 0 omitting even error messages which accompany fatal errors. -**--memory**, **-m**=*LIMIT* -Memory limit (format: <number>[<unit>], where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) +#### **--memory**, **-m**=*LIMIT* +Memory limit (format: <number>[<unit>], where unit = b (bytes), k (kilobytes), +m (megabytes), or g (gigabytes)) Allows you to constrain the memory available to a container. If the host supports swap memory, then the **-m** memory setting can be larger than physical RAM. If a limit of 0 is specified (not using **-m**), the container's memory is not limited. The actual limit may be rounded up to a multiple of the operating -system's page size (the value would be very large, that's millions of trillions). +system's page size (the value would be very large, that's millions of +trillions). -**--memory-swap**=*LIMIT* +#### **--memory-swap**=*LIMIT* A limit value equal to memory plus swap. Must be used with the **-m** (**--memory**) flag. The swap `LIMIT` should always be larger than **-m** @@ -350,24 +394,30 @@ The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you don't specify a unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap. -**--net**, **--network**=*string* +#### **--net**, **--network**=*string* Sets the configuration for network namespaces when handling `RUN` instructions. -The configured value can be "" (the empty string) or "container" to indicate -that a new network namespace should be created, or it can be "host" to indicate -that the network namespace in which `podman` itself is being run should be -reused, or it can be the path to a network namespace which is already in use by -another process. -**--no-cache** +Valid _mode_ values are: -Do not use existing cached images for the container build. Build from the start with a new set of cached layers. +- **none**: no networking. +- **host**: use the Podman host network stack. Note: the host mode gives the +container full access to local system services such as D-bus and is therefore +considered insecure. +- **ns:**_path_: path to a network namespace to join. +- `private`: create a new namespace for the container (default). -**--os**=*string* +#### **--no-cache** -Set the OS to the provided value instead of the current operating system of the host. +Do not use existing cached images for the container build. Build from the start +with a new set of cached layers. -**--pid**=*pid* +#### **--os**=*string* + +Set the OS to the provided value instead of the current operating system of the +host. + +#### **--pid**=*pid* Sets the configuration for PID namespaces when handling `RUN` instructions. The configured value can be "" (the empty string) or "container" to indicate @@ -376,43 +426,44 @@ that the PID namespace in which `podman` itself is being run should be reused, or it can be the path to a PID namespace which is already in use by another process. -**--platform**="Linux" +#### **--platform**="Linux" This option has no effect on the build. Other container engines use this option to control the execution platform for the build (e.g., Windows, Linux) which is not required for Buildah as it supports only Linux. -**--pull** +#### **--pull** -When the option is specified or set to "true", pull the image from the first registry -it is found in as listed in registries.conf. Raise an error if not found in the -registries, even if the image is present locally. +When the option is specified or set to "true", pull the image from the first +registry it is found in as listed in registries.conf. Raise an error if not +found in the registries, even if the image is present locally. -If the option is disabled (with *--pull=false*), or not specified, pull the image -from the registry only if the image is not present locally. Raise an error if the image -is not found in the registries. +If the option is disabled (with *--pull=false*), or not specified, pull the +image from the registry only if the image is not present locally. Raise an +error if the image is not found in the registries. -**--pull-always** +#### **--pull-always** -Pull the image from the first registry it is found in as listed in registries.conf. -Raise an error if not found in the registries, even if the image is present locally. +Pull the image from the first registry it is found in as listed in +registries.conf. Raise an error if not found in the registries, even if the +image is present locally. -**--pull-never** +#### **--pull-never** -Do not pull the image from the registry, use only the local version. Raise an error -if the image is not present locally. +Do not pull the image from the registry, use only the local version. Raise an +error if the image is not present locally. -**--quiet**, **-q** +#### **--quiet**, **-q** Suppress output messages which indicate which instruction is being processed, and of progress when pulling images from a registry, and when writing the output image. -**--rm**=*true|false* +#### **--rm**=*true|false* Remove intermediate containers after a successful build (default true). -**--runtime**=*path* +#### **--runtime**=*path* The *path* to an alternate OCI-compatible runtime, which will be used to run commands specified by the **RUN** instruction. @@ -420,12 +471,13 @@ 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` -**--security-opt**=*option* +#### **--security-opt**=*option* Security Options - `apparmor=unconfined` : Turn off apparmor confinement for the container -- `apparmor=your-profile` : Set the apparmor confinement profile for the container +- `apparmor=your-profile` : Set the apparmor confinement profile for the +container - `label=user:USER` : Set the label user for the container processes - `label=role:ROLE` : Set the label role for the container processes @@ -433,57 +485,68 @@ Security Options - `label=level:LEVEL` : Set the label level for the container processes - `label=filetype:TYPE` : Set the label file type for the container files - `label=disable` : Turn off label separation for the container +- `no-new-privileges` : Not supported - `seccomp=unconfined` : Turn off seccomp confinement for the container -- `seccomp=profile.json` : White listed syscalls seccomp Json file to be used as a seccomp filter +- `seccomp=profile.json` : White listed syscalls seccomp Json file to be used +as a seccomp filter -**--shm-size**=*size* +#### **--shm-size**=*size* -Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. -Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`(megabytes), or `g` (gigabytes). -If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. +Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater +than `0`. +Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`(megabytes), or +`g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the +size entirely, the system uses `64m`. -**--sign-by**=*fingerprint* +#### **--sign-by**=*fingerprint* Sign the image using a GPG key with the specified FINGERPRINT. -**--squash** +#### **--squash** -Squash all of the image's new layers into a single new layer; any preexisting layers -are not squashed. +Squash all of the image's new layers into a single new layer; any preexisting +layers are not squashed. -**--squash-all** +#### **--squash-all** -Squash all of the new image's layers (including those inherited from a base image) into a single new layer. +Squash all of the new image's layers (including those inherited from a base +image) into a single new layer. -**--tag**, **-t**=*imageName* +#### **--tag**, **-t**=*imageName* Specifies the name which will be assigned to the resulting image if the build process completes successfully. -If _imageName_ does not include a registry name, the registry name *localhost* will be prepended to the image name. +If _imageName_ does not include a registry name, the registry name *localhost* +will be prepended to the image name. -**--target**=*stageName* +#### **--target**=*stageName* -Set the target build stage to build. When building a Containerfile with multiple build stages, --target -can be used to specify an intermediate build stage by name as the final stage for the resulting image. -Commands after the target stage will be skipped. +Set the target build stage to build. When building a Containerfile with +multiple build stages, --target can be used to specify an intermediate build +stage by name as the final stage for the resulting image. Commands after the target stage will be skipped. -**--timestamp** *seconds* +#### **--timestamp** *seconds* -Set the create timestamp to seconds since epoch to allow for deterministic builds (defaults to current time). -By default, the created timestamp is changed and written into the image manifest with every commit, -causing the image's sha256 hash to be different even if the sources are exactly the same otherwise. -When --timestamp is set, the created timestamp is always set to the time specified and therefore not changed, allowing the image's sha256 to remain the same. All files committed to the layers of the image will be created with the timestamp. +Set the create timestamp to seconds since epoch to allow for deterministic +builds (defaults to current time). By default, the created timestamp is changed +and written into the image manifest with every commit, causing the image's +sha256 hash to be different even if the sources are exactly the same otherwise. +When --timestamp is set, the created timestamp is always set to the time +specified and therefore not changed, allowing the image's sha256 hash to remain the +same. All files committed to the layers of the image will be created with the +timestamp. -**--tls-verify**=*true|false* +#### **--tls-verify**=*true|false* -Require HTTPS and verify certificates when talking to container registries (defaults to true). +Require HTTPS and verify certificates when talking to container registries +(defaults to true). -**--ulimit**=*type*=*soft-limit*[:*hard-limit*] +#### **--ulimit**=*type*=*soft-limit*[:*hard-limit*] -Specifies resource limits to apply to processes launched when processing `RUN` instructions. -This option can be specified multiple times. Recognized resource types -include: +Specifies resource limits to apply to processes launched when processing `RUN` +instructions. This option can be specified multiple times. Recognized resource +types include: "core": maximum core dump size (ulimit -c) "cpu": maximum CPU time (ulimit -t) "data": maximum size of a process's data segment (ulimit -d) @@ -500,7 +563,7 @@ include: "sigpending": maximum number of pending signals (ulimit -i) "stack": maximum stack size (ulimit -s) -**--userns**=*how* +#### **--userns**=*how* Sets the configuration for user namespaces when handling `RUN` instructions. The configured value can be "" (the empty string) or "container" to indicate @@ -509,7 +572,7 @@ the user namespace in which `podman` itself is being run should be reused, or it can be the path to an user namespace which is already in use by another process. -**--userns-uid-map**=*mapping* +#### **--userns-uid-map**=*mapping* Directly specifies a UID mapping which should be used to set ownership, at the filesystem level, on the working container's contents. @@ -530,7 +593,7 @@ If none of --userns-uid-map-user, --userns-gid-map-group, or --userns-uid-map are specified, but --userns-gid-map is specified, the UID map will be set to use the same numeric values as the GID map. -**--userns-gid-map**=*mapping* +#### **--userns-gid-map**=*mapping* Directly specifies a GID mapping which should be used to set ownership, at the filesystem level, on the working container's contents. @@ -551,7 +614,7 @@ If none of --userns-uid-map-user, --userns-gid-map-group, or --userns-gid-map are specified, but --userns-uid-map is specified, the GID map will be set to use the same numeric values as the UID map. -**--userns-uid-map-user**=*user* +#### **--userns-uid-map-user**=*user* Specifies that a UID mapping which should be used to set ownership, at the filesystem level, on the working container's contents, can be found in entries @@ -562,7 +625,7 @@ If --userns-gid-map-group is specified, but --userns-uid-map-user is not specified, `podman` will assume that the specified group name is also a suitable user name to use as the default setting for this option. -**--userns-gid-map-group**=*group* +#### **--userns-gid-map-group**=*group* Specifies that a GID mapping which should be used to set ownership, at the filesystem level, on the working container's contents, can be found in entries @@ -573,7 +636,7 @@ If --userns-uid-map-user is specified, but --userns-gid-map-group is not specified, `podman` will assume that the specified user name is also a suitable group name to use as the default setting for this option. -**--uts**=*how* +#### **--uts**=*how* Sets the configuration for UTS namespaces when the handling `RUN` instructions. The configured value can be "" (the empty string) or "container" to indicate @@ -582,7 +645,7 @@ that the UTS namespace in which `podman` itself is being run should be reused, or it can be the path to a UTS namespace which is already in use by another process. -**--volume**, **-v**[=*[HOST-DIR:CONTAINER-DIR[:OPTIONS]]*] +#### **--volume**, **-v**[=*[HOST-DIR:CONTAINER-DIR[:OPTIONS]]*] Create a bind mount. If you specify, ` -v /HOST-DIR:/CONTAINER-DIR`, Podman bind mounts `/HOST-DIR` in the host to `/CONTAINER-DIR` in the Podman @@ -622,49 +685,65 @@ Only the current container can use a private volume. `Overlay Volume Mounts` - The `:O` flag tells Podman to mount the directory from the host as a temporary storage using the Overlay file system. The `RUN` command containers are allowed to modify contents within the mountpoint and are stored in the container storage in a separate directory. In Overlay FS terms the source directory will be the lower, and the container storage directory will be the upper. Modifications to the mount point are destroyed when the `RUN` command finishes executing, similar to a tmpfs mount point. + The `:O` flag tells Podman to mount the directory from the host as a +temporary storage using the Overlay file system. The `RUN` command containers +are allowed to modify contents within the mountpoint and are stored in the +container storage in a separate directory. In Overlay FS terms the source +directory will be the lower, and the container storage directory will be the +upper. Modifications to the mount point are destroyed when the `RUN` command +finishes executing, similar to a tmpfs mount point. - Any subsequent execution of `RUN` commands sees the original source directory content, any changes from previous RUN commands no longer exists. + Any subsequent execution of `RUN` commands sees the original source directory +content, any changes from previous RUN commands no longer exists. - One use case of the `overlay` mount is sharing the package cache from the host into the container to allow speeding up builds. + One use case of the `overlay` mount is sharing the package cache from the +host into the container to allow speeding up builds. Note: - Overlay mounts are not currently supported in rootless mode. - - The `O` flag is not allowed to be specified with the `Z` or `z` flags. Content mounted into the container is labeled with the private label. - On SELinux systems, labels in the source directory needs to be readable by the container label. If not, SELinux container separation must be disabled for the container to work. - - Modification of the directory volume mounted into the container with an overlay mount can cause unexpected failures. It is recommended that you do not modify the directory until the container finishes running. + - The `O` flag is not allowed to be specified with the `Z` or `z` flags. +Content mounted into the container is labeled with the private label. + On SELinux systems, labels in the source directory needs to be readable +by the container label. If not, SELinux container separation must be disabled +for the container to work. + - Modification of the directory volume mounted into the container with an +overlay mount can cause unexpected failures. It is recommended that you do not +modify the directory until the container finishes running. By default bind mounted volumes are `private`. That means any mounts done -inside container will not be visible on the host and vice versa. This behavior can -be changed by specifying a volume mount propagation property. - -When the mount propagation policy is set to `shared`, any mounts completed inside -the container on that volume will be visible to both the host and container. When -the mount propagation policy is set to `slave`, one way mount propagation is enabled -and any mounts completed on the host for that volume will be visible only inside of the container. -To control the mount propagation property of volume use the `:[r]shared`, -`:[r]slave` or `:[r]private` propagation flag. The propagation property can -be specified only for bind mounted volumes and not for internal volumes or -named volumes. For mount propagation to work on the source mount point (mount point -where source dir is mounted on) has to have the right propagation properties. For -shared volumes, the source mount point has to be shared. And for slave volumes, -the source mount has to be either shared or slave. <sup>[[1]](#Footnote1)</sup> +inside containers will not be visible on the host and vice versa. This behavior +can be changed by specifying a volume mount propagation property. + +When the mount propagation policy is set to `shared`, any mounts completed +inside the container on that volume will be visible to both the host and +container. When the mount propagation policy is set to `slave`, one way mount +propagation is enabled and any mounts completed on the host for that volume will +be visible only inside of the container. To control the mount propagation +property of volume use the `:[r]shared`, `:[r]slave` or `:[r]private` +propagation flag. The propagation property canbe specified only for bind mounted +volumes and not for internal volumes or named volumes. For mount propagation to +work on the source mount point (mount point where source dir is mounted on) has +to have the right propagation properties. For shared volumes, the source mount +point has to be shared. And for slave volumes, the source mount has to be either +shared or slave. <sup>[[1]](#Footnote1)</sup> Use `df <source-dir>` to determine the source mount and then use `findmnt -o TARGET,PROPAGATION <source-mount-dir>` to determine propagation -properties of source mount, if `findmnt` utility is not available, the source mount point -can be determined by looking at the mount entry in `/proc/self/mountinfo`. Look -at `optional fields` and see if any propagation properties are specified. -`shared:X` means the mount is `shared`, `master:X` means the mount is `slave` and if -nothing is there that means the mount is `private`. <sup>[[1]](#Footnote1)</sup> +properties of source mount, if `findmnt` utility is not available, the source +mount point can be determined by looking at the mount entry in +`/proc/self/mountinfo`. Look at `optional fields` and see if any propagation +properties are specified. +`shared:X` means the mount is `shared`, `master:X` means the mount is `slave` +and if nothing is there that means the mount is `private`. <sup>[[1]](#Footnote1)</sup> To change propagation properties of a mount point use the `mount` command. For example, to bind mount the source directory `/foo` do `mount --bind /foo /foo` and `mount --make-private --make-shared /foo`. This -will convert /foo into a `shared` mount point. The propagation properties of the source -mount can be changed directly. For instance if `/` is the source mount for -`/foo`, then use `mount --make-shared /` to convert `/` into a `shared` mount. +will convert /foo into a `shared` mount point. The propagation properties of +the source mount can be changed directly. For instance if `/` is the source +mount for `/foo`, then use `mount --make-shared /` to convert `/` into a +`shared` mount. ## EXAMPLES @@ -712,11 +791,18 @@ $ podman build --no-cache --rm=false -t imageName . ### Building an image using a URL, Git repo, or archive - The build context directory can be specified as a URL to a Containerfile, a Git repository, or URL to an archive. If the URL is a Containerfile, it is downloaded to a temporary location and used as the context. When a Git repository is set as the URL, the repository is cloned locally to a temporary location and then used as the context. Lastly, if the URL is an archive, it is downloaded to a temporary location and extracted before being used as the context. + The build context directory can be specified as a URL to a Containerfile, a +Git repository, or URL to an archive. If the URL is a Containerfile, it is +downloaded to a temporary location and used as the context. When a Git +repository is set as the URL, the repository is cloned locally to a temporary +location and then used as the context. Lastly, if the URL is an archive, it is +downloaded to a temporary location and extracted before being used as the +context. #### Building an image using a URL to a Containerfile - Podman will download the Containerfile to a temporary location and then use it as the build context. + Podman will download the Containerfile to a temporary location and then use +it as the build context. ``` $ podman build https://10.10.10.1/podman/Containerfile @@ -724,7 +810,9 @@ $ podman build https://10.10.10.1/podman/Containerfile #### Building an image using a Git repository - Podman will clone the specified GitHub repository to a temporary location and use it as the context. The Containerfile at the root of the repository will be used and it only works if the GitHub repository is a dedicated repository. + Podman will clone the specified GitHub repository to a temporary location and +use it as the context. The Containerfile at the root of the repository will be +used and it only works if the GitHub repository is a dedicated repository. ``` $ podman build git://github.com/scollier/purpletest @@ -732,13 +820,18 @@ $ podman build git://github.com/scollier/purpletest #### Building an image using a URL to an archive - Podman will fetch the archive file, decompress it, and use its contents as the build context. The Containerfile at the root of the archive and the rest of the archive will get used as the context of the build. If you pass `-f PATH/Containerfile` option as well, the system will look for that file inside the contents of the archive. + Podman will fetch the archive file, decompress it, and use its contents as the +build context. The Containerfile at the root of the archive and the rest of the +archive will get used as the context of the build. If you pass +`-f PATH/Containerfile` option as well, the system will look for that file +inside the contents of the archive. ``` $ podman build -f dev/Containerfile https://10.10.10.1/podman/context.tar.gz ``` - Note: supported compression formats are 'xz', 'bzip2', 'gzip' and 'identity' (no compression). + Note: supported compression formats are 'xz', 'bzip2', 'gzip' and 'identity' +(no compression). ## Files @@ -766,7 +859,8 @@ src ``` `*/*.c` -Excludes files and directories whose names ends with .c in any top level subdirectory. For example, the source file include/rootless.c. +Excludes files and directories whose names ends with .c in any top level +subdirectory. For example, the source file include/rootless.c. `**/output*` Excludes files and directories starting with `output` from any directory. @@ -784,21 +878,29 @@ mechanism: Exclude all doc files except Help.doc from the image. -This functionality is compatible with the handling of .dockerignore files described here: +This functionality is compatible with the handling of .dockerignore files +described here: https://docs.docker.com/engine/reference/builder/#dockerignore-file **registries.conf** (`/etc/containers/registries.conf`) -registries.conf is the configuration file which specifies which container registries should be consulted when completing image names which do not include a registry or domain portion. +registries.conf is the configuration file which specifies which container +registries should be consulted when completing image names which do not include +a registry or domain portion. ## Troubleshooting ### lastlog sparse file -If you are using a useradd command within a Containerfile with a large UID/GID, it will create a large sparse file `/var/log/lastlog`. This can cause the build to hang forever. Go language does not support sparse files correctly, which can lead to some huge files being created in your container image. +If you are using a useradd command within a Containerfile with a large UID/GID, +it will create a large sparse file `/var/log/lastlog`. This can cause the +build to hang forever. Go language does not support sparse files correctly, +which can lead to some huge files being created in your container image. -If you are using `useradd` within your build script, you should pass the `--no-log-init or -l` option to the `useradd` command. This option tells useradd to stop creating the lastlog file. +If you are using `useradd` within your build script, you should pass the +`--no-log-init or -l` option to the `useradd` command. This option tells +useradd to stop creating the lastlog file. ## SEE ALSO podman(1), buildah(1), containers-registries.conf(5), crun(8), runc(8), useradd(8), podman-ps(1), podman-rm(1) @@ -811,4 +913,9 @@ May 2018, Minor revisions added by Joe Doss <joe@solidadmin.com> December 2017, Originally compiled by Tom Sweeney <tsweeney@redhat.com> ## FOOTNOTES -<a name="Footnote1">1</a>: The Podman project is committed to inclusivity, a core value of open source. The `master` and `slave` mount propagation terminology used here is problematic and divisive, and should be changed. However, these terms are currently used within the Linux kernel and must be used as-is at this time. When the kernel maintainers rectify this usage, Podman will follow suit immediately. +<a name="Footnote1">1</a>: The Podman project is committed to inclusivity, a +core value of open source. The `master` and `slave` mount propagation +terminology used here is problematic and divisive, and should be changed. +However, these terms are currently used within the Linux kernel and must be +used as-is at this time. When the kernel maintainers rectify this usage, +Podman will follow suit immediately. diff --git a/docs/source/markdown/podman-commit.1.md b/docs/source/markdown/podman-commit.1.md index 13e46a899..7485e9bd9 100644 --- a/docs/source/markdown/podman-commit.1.md +++ b/docs/source/markdown/podman-commit.1.md @@ -22,39 +22,39 @@ If *image* is not provided, the values for the `REPOSITORY` and `TAG` values of ## OPTIONS -**--author**, **-a**=*author* +#### **--author**, **-a**=*author* Set the author for the committed image -**--change**, **-c**=*instruction* +#### **--change**, **-c**=*instruction* Apply the following possible instructions to the created image: **CMD** | **ENTRYPOINT** | **ENV** | **EXPOSE** | **LABEL** | **ONBUILD** | **STOPSIGNAL** | **USER** | **VOLUME** | **WORKDIR** Can be set multiple times -**--format**, **-f**=*format* +#### **--format**, **-f**=*format* Set the format of the image manifest and metadata. The currently supported formats are _oci_ and _docker_. If not specifically set, the default format used is _oci_. -**--iidfile**=*ImageIDfile* +#### **--iidfile**=*ImageIDfile* Write the image ID to the file. -**--include-volumes** +#### **--include-volumes** Include in the committed image any volumes added to the container by the `--volume` or `--mount` options to the `podman create` and `podman run` commands. -**--message**, **-m**=*message* +#### **--message**, **-m**=*message* Set commit message for committed image. The message field is not supported in _oci_ format. -**--pause**, **-p** +#### **--pause**, **-p** Pause the container when creating an image -**--quiet**, **-q** +#### **--quiet**, **-q** Suppress output diff --git a/docs/source/markdown/podman-container-checkpoint.1.md b/docs/source/markdown/podman-container-checkpoint.1.md index 1bac477c8..bfda782c5 100644 --- a/docs/source/markdown/podman-container-checkpoint.1.md +++ b/docs/source/markdown/podman-container-checkpoint.1.md @@ -10,42 +10,42 @@ podman\-container\-checkpoint - Checkpoints one or more running containers Checkpoints all the processes in one or more containers. You may use container IDs or names as input. ## OPTIONS -**--keep**, **-k** +#### **--keep**, **-k** Keep all temporary log and statistics files created by CRIU during checkpointing. These files are not deleted if checkpointing fails for further debugging. If checkpointing succeeds these files are theoretically not needed, but if these files are needed Podman can keep the files for further analysis. -**--all**, **-a** +#### **--all**, **-a** Checkpoint all running containers. -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the container name or ID, checkpoint the last created container. The latest option is not supported on the remote client. -**--leave-running**, **-R** +#### **--leave-running**, **-R** Leave the container running after checkpointing instead of stopping it. -**--tcp-established** +#### **--tcp-established** Checkpoint a container with established TCP connections. If the checkpoint image contains established TCP connections, this options is required during restore. Defaults to not checkpointing containers with established TCP connections. -**--export**, **-e** +#### **--export**, **-e** Export the checkpoint to a tar.gz file. The exported checkpoint can be used to import the container on another system and thus enabling container live migration. This checkpoint archive also includes all changes to the container's root file-system, if not explicitly disabled using **--ignore-rootfs** -**--ignore-rootfs** +#### **--ignore-rootfs** This only works in combination with **--export, -e**. If a checkpoint is exported to a tar.gz file it is possible with the help of **--ignore-rootfs** diff --git a/docs/source/markdown/podman-container-cleanup.1.md b/docs/source/markdown/podman-container-cleanup.1.md index a200c2c36..eabb462e8 100644 --- a/docs/source/markdown/podman-container-cleanup.1.md +++ b/docs/source/markdown/podman-container-cleanup.1.md @@ -12,28 +12,28 @@ Sometimes container's mount points and network stacks can remain if the podman c ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Cleanup all containers. -**--exec**=_session_ +#### **--exec**=_session_ Clean up an exec session for a single container. Can only be specified if a single container is being cleaned up (conflicts with **--all** as such). If **--rm** is not specified, temporary files for the exec session will be cleaned up; if it is, the exec session will be removed from the container. Conflicts with **--rmi** as the container is not being cleaned up so the image cannot be removed. -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**--rm** +#### **--rm** After cleanup, remove the container entirely. -**--rmi** +#### **--rmi** After cleanup, remove the image entirely. diff --git a/docs/source/markdown/podman-container-exists.1.md b/docs/source/markdown/podman-container-exists.1.md index d81a38515..381d968ab 100644 --- a/docs/source/markdown/podman-container-exists.1.md +++ b/docs/source/markdown/podman-container-exists.1.md @@ -14,7 +14,7 @@ was an issue accessing the local storage. ## OPTIONS -**--external**=*true|false* +#### **--external**=*true|false* Check for external containers as well as Podman containers. These external containers are generally created via other container technology such as Buildah or CRI-O. **-h**, **--help** diff --git a/docs/source/markdown/podman-container-prune.1.md b/docs/source/markdown/podman-container-prune.1.md index d56a1e7f5..4b4effb0b 100644 --- a/docs/source/markdown/podman-container-prune.1.md +++ b/docs/source/markdown/podman-container-prune.1.md @@ -11,11 +11,11 @@ podman-container-prune - Remove all stopped containers from local storage ## OPTIONS -**--filter**=*filters* +#### **--filter**=*filters* Provide filter values. -**--force**, **-f** +#### **--force**, **-f** Do not provide an interactive prompt for container removal. diff --git a/docs/source/markdown/podman-container-restore.1.md b/docs/source/markdown/podman-container-restore.1.md index a7b0f199b..494e7db1e 100644 --- a/docs/source/markdown/podman-container-restore.1.md +++ b/docs/source/markdown/podman-container-restore.1.md @@ -10,7 +10,7 @@ podman\-container\-restore - Restores one or more containers from a checkpoint Restores a container from a checkpoint. You may use container IDs or names as input. ## OPTIONS -**--keep**, **-k** +#### **--keep**, **-k** Keep all temporary log and statistics files created by CRIU during checkpointing as well as restoring. These files are not deleted if restoring @@ -24,17 +24,17 @@ processes in the checkpointed container. Without the **-k**, **--keep** option the checkpoint will be consumed and cannot be used again. -**--all**, **-a** +#### **--all**, **-a** Restore all checkpointed containers. -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the container name or ID, restore the last created container. The latest option is not supported on the remote client. -**--tcp-established** +#### **--tcp-established** Restore a container with established TCP connections. If the checkpoint image contains established TCP connections, this option is required during restore. @@ -42,13 +42,13 @@ If the checkpoint image does not contain established TCP connections this option is ignored. Defaults to not restoring containers with established TCP connections. -**--import**, **-i** +#### **--import**, **-i** Import a checkpoint tar.gz file, which was exported by Podman. This can be used to import a checkpointed container from another host. Do not specify a *container* argument when using this option. -**--name**, **-n** +#### **--name**, **-n** This is only available in combination with **--import, -i**. If a container is restored from a checkpoint tar.gz file it is possible to rename it with **--name, -n**. This @@ -60,14 +60,14 @@ address to the container it was using before checkpointing as each IP address ca be used once and the restored container will have another IP address. This also means that **--name, -n** cannot be used in combination with **--tcp-established**. -**--ignore-rootfs** +#### **--ignore-rootfs** This is only available in combination with **--import, -i**. If a container is restored from a checkpoint tar.gz file it is possible that it also contains all root file-system changes. With **--ignore-rootfs** it is possible to explicitly disable applying these root file-system changes to the restored container. -**--ignore-static-ip** +#### **--ignore-static-ip** If the container was started with **--ip** the restored container also tries to use that IP address and restore fails if that IP address is already in use. This can happen, if @@ -76,7 +76,7 @@ a container is restored multiple times from an exported checkpoint with **--name Using **--ignore-static-ip** tells Podman to ignore the IP address if it was configured with **--ip** during container creation. -**--ignore-static-mac** +#### **--ignore-static-mac** If the container was started with **--mac-address** the restored container also tries to use that MAC address and restore fails if that MAC address is already diff --git a/docs/source/markdown/podman-container-runlabel.1.md b/docs/source/markdown/podman-container-runlabel.1.md index 676ad12d0..54d675705 100644 --- a/docs/source/markdown/podman-container-runlabel.1.md +++ b/docs/source/markdown/podman-container-runlabel.1.md @@ -41,7 +41,7 @@ is used. Any additional arguments will be appended to the command. ## OPTIONS -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. @@ -49,39 +49,39 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--display** +#### **--display** Display the label's value of the image having populated its environment variables. The runlabel command will not execute if --display is specified. -**--cert-dir**=*path* +#### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) -**--creds**=*[username[:password]]* +#### **--creds**=*[username[:password]]* The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--name**, **-n**=*name* +#### **--name**, **-n**=*name* Use this name for creating content for the container. NAME will default to the IMAGENAME if it is not specified. -**--quiet**, **-q** +#### **--quiet**, **-q** Suppress output information when pulling images -**--replace** +#### **--replace** If a container exists of the default or given name, as needed it will be stopped, deleted and a new container will be created from this image. -**--tls-verify** +#### **--tls-verify** Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified, diff --git a/docs/source/markdown/podman-cp.1.md b/docs/source/markdown/podman-cp.1.md index 0f54b2e8b..8f63c00ee 100644 --- a/docs/source/markdown/podman-cp.1.md +++ b/docs/source/markdown/podman-cp.1.md @@ -59,11 +59,11 @@ If you use a : in a local machine path, you must be explicit with a relative or ## OPTIONS -**--extract** +#### **--extract** Extract the tar file into the destination directory. If the destination directory is not provided, extract the tar file into the root directory. -**--pause** +#### **--pause** Pause the container while copying into it to avoid potential security issues around symlinks. Defaults to *true*. On rootless containers with cgroups V1, defaults to false. diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index e243a5842..5922e0675 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -19,19 +19,19 @@ any point. The initial status of the container created with **podman create** is 'created'. ## OPTIONS -**--add-host**=*host* +#### **--add-host**=*host* Add a custom host-to-IP mapping (host:ip) Add a line to /etc/hosts. The format is hostname:ip. The **--add-host** option can be set multiple times. -**--annotation**=*key=value* +#### **--annotation**=*key=value* Add an annotation to the container. The format is key=value. The **--annotation** option can be set multiple times. -**--attach**, **-a**=*location* +#### **--attach**, **-a**=*location* Attach to STDIN, STDOUT or STDERR. @@ -42,30 +42,30 @@ error. It can even pretend to be a TTY (this is what most commandline executables expect) and pass along signals. The **-a** option can be set for each of stdin, stdout, and stderr. -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--blkio-weight**=*weight* +#### **--blkio-weight**=*weight* Block IO weight (relative weight) accepts a weight value between 10 and 1000. -**--blkio-weight-device**=*weight* +#### **--blkio-weight-device**=*weight* Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`). -**--cap-add**=*capability* +#### **--cap-add**=*capability* Add Linux capabilities -**--cap-drop**=*capability* +#### **--cap-drop**=*capability* Drop Linux capabilities -**--cgroupns**=*mode* +#### **--cgroupns**=*mode* Set the cgroup namespace mode for the container. **host**: use the host's cgroup namespace inside the container. @@ -75,7 +75,7 @@ Set the cgroup namespace mode for the container. If the host uses cgroups v1, the default is set to **host**. On cgroups v2 the default is **private**. -**--cgroups**=*mode* +#### **--cgroups**=*mode* Determines whether the container will create CGroups. Valid values are *enabled*, *disabled*, *no-conmon*, *split*, which the default being *enabled*. @@ -85,23 +85,23 @@ The *disabled* option will force the container to not create CGroups, and thus c The *no-conmon* option disables a new CGroup only for the conmon process. The *split* option splits the current cgroup in two sub-cgroups: one for conmon and one for the container payload. It is not possible to set *--cgroup-parent* with *split*. -**--cgroup-parent**=*path* +#### **--cgroup-parent**=*path* Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist. -**--cgroup-conf**=*KEY=VALUE* +#### **--cgroup-conf**=*KEY=VALUE* When running on cgroup v2, specify the cgroup file to write to and its value. For example **--cgroup-conf=memory.high=1073741824** sets the memory.high limit to 1GB. -**--cidfile**=*id* +#### **--cidfile**=*id* Write the container ID to the file -**--conmon-pidfile**=*path* +#### **--conmon-pidfile**=*path* Write the pid of the `conmon` process to a file. `conmon` runs in a separate process than Podman, so this is necessary when using systemd to restart Podman containers. -**--cpu-period**=*limit* +#### **--cpu-period**=*limit* Set the CPU period for the Completely Fair Scheduler (CFS), which is a duration in microseconds. Once the container's CPU quota is used up, it will @@ -112,7 +112,7 @@ On some systems, changing the CPU limits may not be allowed for non-root users. For more details, see https://github.com/containers/podman/blob/master/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error -**--cpu-quota**=*limit* +#### **--cpu-quota**=*limit* Limit the CPU Completely Fair Scheduler (CFS) quota. @@ -125,13 +125,13 @@ On some systems, changing the CPU limits may not be allowed for non-root users. For more details, see https://github.com/containers/podman/blob/master/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error -**--cpu-rt-period**=*microseconds* +#### **--cpu-rt-period**=*microseconds* Limit the CPU real-time period in microseconds Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify. -**--cpu-rt-runtime**=*microseconds* +#### **--cpu-rt-runtime**=*microseconds* Limit the CPU real-time runtime in microseconds @@ -140,7 +140,7 @@ Period of 1,000,000us and Runtime of 950,000us means that this container could c The sum of all runtimes across containers cannot exceed the amount allotted to the parent cgroup. -**--cpu-shares**=*shares* +#### **--cpu-shares**=*shares* CPU shares (relative weight) @@ -177,21 +177,21 @@ PID container CPU CPU share 101 {C1} 1 100% of CPU1 102 {C1} 2 100% of CPU2 -**--cpus**=*number* +#### **--cpus**=*number* Number of CPUs. The default is *0.0* which means no limit. This is shorthand for **--cpu-period** and **--cpu-quota**, so you may only set either -**--cpus** or **--cpu-period** and **--cpu-quota**. +#### **--cpus** or **--cpu-period** and **--cpu-quota**. On some systems, changing the CPU limits may not be allowed for non-root users. For more details, see https://github.com/containers/podman/blob/master/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error -**--cpuset-cpus**=*cpus* +#### **--cpuset-cpus**=*cpus* CPUs in which to allow execution (0-3, 0,1) -**--cpuset-mems**=*nodes* +#### **--cpuset-mems**=*nodes* Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems. @@ -199,7 +199,7 @@ If you have four memory nodes on your system (0-3), use `--cpuset-mems=0,1` then processes in your container will only use memory from the first two memory nodes. -**--device**=_host-device_[**:**_container-device_][**:**_permissions_] +#### **--device**=_host-device_[**:**_container-device_][**:**_permissions_] Add a host device to the container. Optional *permissions* parameter can be used to specify device permissions, it is combination of @@ -218,36 +218,36 @@ Podman may load kernel modules required for using the specified device. The devices that podman will load modules when necessary are: /dev/fuse. -**--device-cgroup-rule**="type major:minor mode" +#### **--device-cgroup-rule**="type major:minor mode" Add a rule to the cgroup allowed devices list. The rule is expected to be in the format specified in the Linux kernel documentation (Documentation/cgroup-v1/devices.txt): - type: a (all), c (char), or b (block); - major and minor: either a number, or * for all; - mode: a composition of r (read), w (write), and m (mknod(2)). -**--device-read-bps**=*path* +#### **--device-read-bps**=*path* Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb) -**--device-read-iops**=*path* +#### **--device-read-iops**=*path* Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000) -**--device-write-bps**=*path* +#### **--device-write-bps**=*path* Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb) -**--device-write-iops**=*path* +#### **--device-write-iops**=*path* Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000) -**--disable-content-trust** +#### **--disable-content-trust** This is a Docker specific option to disable image verification to a Docker registry and is not supported by Podman. This flag is a NOOP and provided solely for scripting compatibility. -**--dns**=*dns* +#### **--dns**=*dns* Set custom DNS servers. Invalid if using **--dns** and **--network** that is set to 'none' or 'container:<name|id>'. @@ -259,15 +259,15 @@ is the case the **--dns** flags is necessary for every run. The special value **none** can be specified to disable creation of **/etc/resolv.conf** in the container by Podman. The **/etc/resolv.conf** file in the image will be used without changes. -**--dns-opt**=*option* +#### **--dns-opt**=*option* Set custom DNS options. Invalid if using **--dns-opt** and **--network** that is set to 'none' or 'container:<name|id>'. -**--dns-search**=*domain* +#### **--dns-search**=*domain* Set custom DNS search domains. Invalid if using **--dns-search** and **--network** that is set to 'none' or 'container:<name|id>'. (Use --dns-search=. if you don't wish to set the search domain) -**--entrypoint**=*"command"* | *'["command", "arg1", ...]'* +#### **--entrypoint**=*"command"* | *'["command", "arg1", ...]'* Overwrite the default ENTRYPOINT of the image @@ -284,7 +284,7 @@ ENTRYPOINT. You need to specify multi option commands in the form of a json string. -**--env**, **-e**=*env* +#### **--env**, **-e**=*env* Set environment variables @@ -292,30 +292,30 @@ This option allows arbitrary environment variables that are available for the pr See [**Environment**](#environment) note below for precedence and examples. -**--env-host**=*true|false* +#### **--env-host**=*true|false* Use host environment inside of the container. See **Environment** note below for precedence. (Not available for remote commands) -**--env-file**=*file* +#### **--env-file**=*file* Read in a line delimited file of environment variables. See **Environment** note below for precedence. -**--expose**=*port* +#### **--expose**=*port* Expose a port, or a range of ports (e.g. --expose=3300-3310) to set up port redirection on the host system. -**--gidmap**=*container_gid:host_gid:amount* +#### **--gidmap**=*container_gid:host_gid:amount* GID map for the user namespace. Using this flag will run the container with user namespace enabled. It conflicts with the `--userns` and `--subgidname` flags. The following example maps uids 0-2000 in the container to the uids 30000-31999 on the host and gids 0-2000 in the container to the gids 30000-31999 on the host. `--gidmap=0:30000:2000` -**--group-add**=*group* +#### **--group-add**=*group* Add additional groups to run as -**--health-cmd**=*"command"* | *'["command", "arg1", ...]'* +#### **--health-cmd**=*"command"* | *'["command", "arg1", ...]'* Set or alter a healthcheck command for a container. The command is a command to be executed inside your container that determines your container health. The command is required for other healthcheck options @@ -324,35 +324,35 @@ to be applied. A value of `none` disables existing healthchecks. Multiple options can be passed in the form of a JSON array; otherwise, the command will be interpreted as an argument to `/bin/sh -c`. -**--health-interval**=*interval* +#### **--health-interval**=*interval* Set an interval for the healthchecks (a value of `disable` results in no automatic timer setup) (default "30s") -**--health-retries**=*retries* +#### **--health-retries**=*retries* The number of retries allowed before a healthcheck is considered to be unhealthy. The default value is `3`. -**--health-start-period**=*period* +#### **--health-start-period**=*period* The initialization time needed for a container to bootstrap. The value can be expressed in time format like `2m3s`. The default value is `0s` -**--health-timeout**=*timeout* +#### **--health-timeout**=*timeout* The maximum time allowed to complete the healthcheck before an interval is considered failed. Like start-period, the value can be expressed in a time format such as `1m22s`. The default value is `30s`. -**-h**, **--hostname**=*name* +#### **-h**, **--hostname**=*name* Container host name Sets the container host name that is available inside the container. Can only be used with a private UTS namespace `--uts=private` (default). If `--pod` is specified and the pod shares the UTS namespace (default) the pods hostname will be used. -**--help** +#### **--help** Print usage statement -**--http-proxy**=*true|false* +#### **--http-proxy**=*true|false* By default proxy environment variables are passed into the container if set for the Podman process. This can be disabled by setting the `--http-proxy` @@ -372,7 +372,7 @@ container: Defaults to `true` -**--image-volume**, **builtin-volume**=*bind|tmpfs|ignore* +#### **--image-volume**, **builtin-volume**=*bind|tmpfs|ignore* Tells Podman how to handle the builtin image volumes. Default is **bind**. @@ -381,37 +381,37 @@ Tells Podman how to handle the builtin image volumes. Default is **bind**. content that disappears when the container is stopped. - **ignore**: All volumes are just ignored and no action is taken. -**--init** +#### **--init** Run an init inside the container that forwards signals and reaps processes. -**--init-path**=*path* +#### **--init-path**=*path* Path to the container-init binary. -**--interactive**, **-i**=*true|false* +#### **--interactive**, **-i**=*true|false* Keep STDIN open even if not attached. The default is *false*. -**--ip6**=*ip* +#### **--ip6**=*ip* Not implemented -**--ip**=*ip* +#### **--ip**=*ip* Specify a static IP address for the container, for example **10.88.64.128**. This option can only be used if the container is joined to only a single network - i.e., `--network=_network-name_` is used at most once - and if the container is not joining another container's network namespace via `--network=container:_id_`. The address must be within the CNI network's IP address pool (default **10.88.0.0/16**). -**--ipc**=*ipc* +#### **--ipc**=*ipc* Default is to create a private IPC namespace (POSIX SysV IPC) for the container 'container:<name|id>': reuses another container shared memory, semaphores and message queues 'host': use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. 'ns:<path>' path to an IPC namespace to join. -**--kernel-memory**=*number[unit]* +#### **--kernel-memory**=*number[unit]* Kernel memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) @@ -421,23 +421,23 @@ is not limited. If you specify a limit, it may be rounded up to a multiple of the operating system's page size and the value can be very large, millions of trillions. -**--label**, **-l**=*label* +#### **--label**, **-l**=*label* Add metadata to a container (e.g., --label com.example.key=value) -**--label-file**=*file* +#### **--label-file**=*file* Read in a line delimited file of labels -**--link-local-ip**=*ip* +#### **--link-local-ip**=*ip* Not implemented -**--log-driver**="*k8s-file*" +#### **--log-driver**="*k8s-file*" Logging driver for the container. Currently available options are *k8s-file*, *journald*, and *none*, with *json-file* aliased to *k8s-file* for scripting compatibility. -**--log-opt**=*name*=*value* +#### **--log-opt**=*name*=*value* Set custom logging configuration. The following *name*s are supported: @@ -460,7 +460,7 @@ It supports the same keys as `podman inspect --format`. It is currently supported only by the journald log driver. -**--mac-address**=*address* +#### **--mac-address**=*address* Container MAC address (e.g. 92:d0:c6:0a:29:33) @@ -468,7 +468,7 @@ Remember that the MAC address in an Ethernet network must be unique. The IPv6 link-local address will be based on the device's MAC address according to RFC4862. -**--memory**, **-m**=*limit* +#### **--memory**, **-m**=*limit* Memory limit (format: <number>[<unit>], where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) @@ -478,7 +478,7 @@ RAM. If a limit of 0 is specified (not using **-m**), the container's memory is not limited. The actual limit may be rounded up to a multiple of the operating system's page size (the value would be very large, that's millions of trillions). -**--memory-reservation**=*limit* +#### **--memory-reservation**=*limit* Memory soft limit (format: <number>[<unit>], where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) @@ -488,7 +488,7 @@ reservation. So you should always set the value below **--memory**, otherwise th hard limit will take precedence. By default, memory reservation will be the same as memory limit. -**--memory-swap**=*limit* +#### **--memory-swap**=*limit* A limit value equal to memory plus swap. Must be used with the **-m** (**--memory**) flag. The swap `LIMIT` should always be larger than **-m** @@ -499,11 +499,11 @@ The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you don't specify a unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap. -**--memory-swappiness**=*number* +#### **--memory-swappiness**=*number* Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100. -**--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]* +#### **--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]* Attach a filesystem mount to the container @@ -560,7 +560,7 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · notmpcopyup: Disable copying files from the image to the tmpfs. -**--name**=*name* +#### **--name**=*name* Assign a name to the container @@ -574,7 +574,7 @@ to the container with **--name** then it will generate a random string name. The name is useful any place you need to identify a container. This works for both background and foreground containers. -**--network**, **--net**="*bridge*" +#### **--network**, **--net**="*bridge*" Set the Network mode for the container. Invalid if using **--dns**, **--dns-opt**, or **--dns-search** with **--network** that is set to 'none' or 'container:<name|id>'. @@ -598,39 +598,39 @@ Valid values are: - **port_handler=rootlesskit**: Use rootlesskit for port forwarding. Default. - **port_handler=slirp4netns**: Use the slirp4netns port forwarding. -**--network-alias**=*alias* +#### **--network-alias**=*alias* -Not implemented +Add network-scoped alias for the container -**--no-healthcheck**=*true|false* +#### **--no-healthcheck**=*true|false* Disable any defined healthchecks for container. -**--no-hosts**=*true|false* +#### **--no-hosts**=*true|false* Do not create /etc/hosts for the container. By default, Podman will manage /etc/hosts, adding the container's own IP address and any hosts from **--add-host**. -**--no-hosts** disables this, and the image's **/etc/host** will be preserved unmodified. +#### **--no-hosts** disables this, and the image's **/etc/host** will be preserved unmodified. This option conflicts with **--add-host**. -**--oom-kill-disable**=*true|false* +#### **--oom-kill-disable**=*true|false* Whether to disable OOM Killer for the container or not. -**--oom-score-adj**=*num* +#### **--oom-score-adj**=*num* Tune the host's OOM preferences for containers (accepts -1000 to 1000) -**--override-arch**=*ARCH* +#### **--override-arch**=*ARCH* Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. -**--override-os**=*OS* +#### **--override-os**=*OS* Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. -**--override-variant**=*VARIANT* +#### **--override-variant**=*VARIANT* Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. -**--pid**=*pid* +#### **--pid**=*pid* Set the PID mode for the container Default is to create a private PID namespace for the container @@ -639,20 +639,20 @@ Default is to create a private PID namespace for the container - `ns`: join the specified PID namespace - `private`: create a new namespace for the container (default) -**--pids-limit**=*limit* +#### **--pids-limit**=*limit* Tune the container's pids limit. Set `0` to have unlimited pids for the container. (default "4096" on systems that support PIDS cgroups). -**--pod**=*name* +#### **--pod**=*name* Run container in an existing pod. If you want Podman to make the pod for you, preference the pod name with `new:`. To make a pod with more granular options, use the `podman pod create` command before creating a container. -**--pod-id-file**=*path* +#### **--pod-id-file**=*path* Run container in an existing pod and read the pod's ID from the specified file. If a container is run within a pod, and the pod has an infra-container, the infra-container will be started before the container is. -**--privileged**=*true|false* +#### **--privileged**=*true|false* Give extended privileges to this container. The default is *false*. @@ -668,7 +668,7 @@ container. Rootless containers cannot have more privileges than the account that launched them. -**--publish**, **-p**=*port* +#### **--publish**, **-p**=*port* Publish a container's port, or range of ports, to the host @@ -691,7 +691,7 @@ associated ports. If one container binds to a port, no other container can use t within the pod while it is in use. Containers in the pod can also communicate over localhost by having one container bind to localhost in the pod, and another connect to that port. -**--publish-all**, **-P**=*true|false* +#### **--publish-all**, **-P**=*true|false* Publish all exposed ports to random ports on the host interfaces. The default is *false*. @@ -703,7 +703,7 @@ port to a random port on the host within an *ephemeral port range* defined by `/proc/sys/net/ipv4/ip_local_port_range`. To find the mapping between the host ports and the exposed ports, use `podman port`. -**--pull**=*missing* +#### **--pull**=*missing* Pull image before creating ("always"|"missing"|"never") (default "missing"). 'missing': default value, attempt to pull the latest image from the registries listed in registries.conf if a local image does not exist.Raise an error if the image is not in any listed registry and is not present locally. @@ -712,11 +712,11 @@ Pull image before creating ("always"|"missing"|"never") (default "missing"). Defaults to *missing*. -**--quiet**, **-q** +#### **--quiet**, **-q** Suppress output information when pulling images -**--read-only**=*true|false* +#### **--read-only**=*true|false* Mount the container's root filesystem as read only. @@ -724,15 +724,15 @@ By default a container will have its root filesystem writable allowing processes to write files anywhere. By specifying the `--read-only` flag the container will have its root filesystem mounted as read only prohibiting any writes. -**--read-only-tmpfs**=*true|false* +#### **--read-only-tmpfs**=*true|false* If container is running in --read-only mode, then mount a read-write tmpfs on /run, /tmp, and /var/tmp. The default is *true* -**--replace**=**true**|**false** +#### **--replace**=**true**|**false** If another container with the same name already exists, replace and remove it. The default is **false**. -**--restart**=*policy* +#### **--restart**=*policy* Restart policy to follow when containers exit. Restart policy will not take effect if a container is stopped via the `podman kill` or `podman stop` commands. @@ -748,7 +748,7 @@ Please note that restart will not restart containers after a system reboot. If this functionality is required in your environment, you can invoke Podman from a systemd unit file, or create an init script for whichever init system is in use. To generate systemd unit files, please see *podman generate systemd* -**--rm**=*true|false* +#### **--rm**=*true|false* Automatically remove the container when it exits. The default is *false*. @@ -756,14 +756,14 @@ Note that the container will not be removed when it could not be created or started successfully. This allows the user to inspect the container after failure. -**--rootfs** +#### **--rootfs** If specified, the first argument refers to an exploded container on the file system. This is useful to run a container without requiring any image management, the rootfs of the container is assumed to be managed externally. -**--sdnotify**=**container**|**conmon**|**ignore** +#### **--sdnotify**=**container**|**conmon**|**ignore** Determines how to use the NOTIFY_SOCKET, as passed with systemd and Type=notify. @@ -774,13 +774,13 @@ has started. The socket is never passed to the runtime or the container. The **ignore** option removes NOTIFY_SOCKET from the environment for itself and child processes, for the case where some other process above Podman uses NOTIFY_SOCKET and Podman should not use it. -**--seccomp-policy**=*policy* +#### **--seccomp-policy**=*policy* Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below. Note that this feature is experimental and may change in the future. -**--security-opt**=*option* +#### **--security-opt**=*option* Security Options @@ -804,29 +804,29 @@ Security Options Note: Labeling can be disabled for all containers by setting label=false in the **containers.conf** (`/etc/containers/containers.conf` or `$HOME/.config/containers/containers.conf`) file. -**--shm-size**=*size* +#### **--shm-size**=*size* Size of `/dev/shm` (format: <number>[<unit>], where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. When size is `0`, there is no limit on the amount of memory used for IPC by the container. -**--stop-signal**=*SIGTERM* +#### **--stop-signal**=*SIGTERM* Signal to stop a container. Default is SIGTERM. -**--stop-timeout**=*seconds* +#### **--stop-timeout**=*seconds* Timeout (in seconds) to stop a container. Default is 10. -**--subgidname**=*name* +#### **--subgidname**=*name* Name for GID map from the `/etc/subgid` file. Using this flag will run the container with user namespace enabled. This flag conflicts with `--userns` and `--gidmap`. -**--subuidname**=*name* +#### **--subuidname**=*name* Name for UID map from the `/etc/subuid` file. Using this flag will run the container with user namespace enabled. This flag conflicts with `--userns` and `--uidmap`. -**--sysctl**=*SYSCTL* +#### **--sysctl**=*SYSCTL* Configure namespaced kernel parameters at runtime @@ -842,7 +842,7 @@ Network Namespace - current sysctls allowed: Note: if you use the --network=host option these sysctls will not be allowed. -**--systemd**=*true|false|always* +#### **--systemd**=*true|false|always* Run container in systemd mode. The default is *true*. @@ -866,7 +866,7 @@ The `container_manage_cgroup` boolean must be enabled for this to be allowed on `setsebool -P container_manage_cgroup true` -**--tmpfs**=*fs* +#### **--tmpfs**=*fs* Create a tmpfs mount @@ -879,7 +879,7 @@ options are the same as the Linux default `mount` flags. If you do not specify any options, the systems uses the following options: `rw,noexec,nosuid,nodev`. -**--tty**, **-t**=*true|false* +#### **--tty**, **-t**=*true|false* Allocate a pseudo-TTY. The default is *false*. @@ -890,27 +890,27 @@ interactive shell. The default is false. Note: The **-t** option is incompatible with a redirection of the Podman client standard input. -**--tz**=*timezone* +#### **--tz**=*timezone* Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones. -**--umask**=*umask* +#### **--umask**=*umask* Set the umask inside the container. Defaults to `0022`. -**--uidmap**=*container_uid:host_uid:amount* +#### **--uidmap**=*container_uid:host_uid:amount* UID map for the user namespace. Using this flag will run the container with user namespace enabled. It conflicts with the `--userns` and `--subuidname` flags. The following example maps uids 0-2000 in the container to the uids 30000-31999 on the host and gids 0-2000 in the container to the gids 30000-31999 on the host. `--uidmap=0:30000:2000` -**--ulimit**=*option* +#### **--ulimit**=*option* Ulimit options You can pass `host` to copy the current configuration from the host. -**--user**, **-u**=*user* +#### **--user**, **-u**=*user* Sets the username or UID used and optionally the groupname or GID for the specified command. @@ -919,12 +919,12 @@ The following examples are all valid: Without this argument the command will be run as root in the container. -**--userns**=*auto*[:OPTIONS] -**--userns**=*host* -**--userns**=*keep-id* -**--userns**=container:container -**--userns**=private -**--userns**=*ns:my_namespace* +#### **--userns**=*auto*[:OPTIONS] +#### **--userns**=*host* +#### **--userns**=*keep-id* +#### **--userns**=container:container +#### **--userns**=private +#### **--userns**=*ns:my_namespace* Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value means user namespaces are disabled. @@ -941,7 +941,7 @@ Set the user namespace mode for the container. It defaults to the **PODMAN_USER This option is incompatible with --gidmap, --uidmap, --subuid and --subgid -**--uts**=*mode* +#### **--uts**=*mode* Set the UTS namespace mode for the container. The following values are supported: @@ -950,7 +950,7 @@ Set the UTS namespace mode for the container. The following values are supported - **ns:[path]**: run the container in the given existing UTS namespace. - **container:[container]**: join the UTS namespace of the specified container. -**--volume**, **-v**[=*[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]*] +#### **--volume**, **-v**[=*[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]*] Create a bind mount. If you specify, ` -v /HOST-DIR:/CONTAINER-DIR`, podman bind mounts `/HOST-DIR` in the host to `/CONTAINER-DIR` in the podman @@ -1091,7 +1091,7 @@ will convert /foo into a `shared` mount point. Alternatively one can directly change propagation properties of source mount. Say `/` is source mount for `/foo`, then use `mount --make-shared /` to convert `/` into a `shared` mount. -**--volumes-from**[=*CONTAINER*[:*OPTIONS*]] +#### **--volumes-from**[=*CONTAINER*[:*OPTIONS*]] Mount volumes from the specified container(s). Used to share volumes between containers. The *options* is a comma delimited list with the following available elements: @@ -1124,7 +1124,7 @@ If the location of the volume from the source container overlaps with data residing on a target container, then the volume hides that data on the target. -**--workdir**, **-w**=*dir* +#### **--workdir**, **-w**=*dir* Working directory inside the container diff --git a/docs/source/markdown/podman-diff.1.md b/docs/source/markdown/podman-diff.1.md index 5b0434a07..227da4864 100644 --- a/docs/source/markdown/podman-diff.1.md +++ b/docs/source/markdown/podman-diff.1.md @@ -13,11 +13,11 @@ Displays changes on a container or image's filesystem. The container or image w ## OPTIONS -**--format** +#### **--format** Alter the output into a different format. The only valid format for diff is `json`. -**--latest**, **-l** +#### **--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. diff --git a/docs/source/markdown/podman-events.1.md b/docs/source/markdown/podman-events.1.md index d0bc3cef8..4f9e9418f 100644 --- a/docs/source/markdown/podman-events.1.md +++ b/docs/source/markdown/podman-events.1.md @@ -70,16 +70,16 @@ The *volume* type will report the following statuses: ## OPTIONS -**--help** +#### **--help** Print usage statement. -**--format** +#### **--format** Format the output to JSON Lines or using the given Go template. -**--filter**=*filter* +#### **--filter**=*filter* Filter events that are displayed. They must be in the format of "filter=value". The following filters are supported: @@ -93,12 +93,12 @@ filters are supported: In the case where an ID is used, the ID may be in its full or shortened form. -**--since**=*timestamp* +#### **--since**=*timestamp* Show all events created since the given timestamp -**--until**=*timestamp* +#### **--until**=*timestamp* Show all events created until the given timestamp diff --git a/docs/source/markdown/podman-exec.1.md b/docs/source/markdown/podman-exec.1.md index f44a3d3d9..17d620cf8 100644 --- a/docs/source/markdown/podman-exec.1.md +++ b/docs/source/markdown/podman-exec.1.md @@ -13,39 +13,39 @@ podman\-exec - Execute a command in a running container ## OPTIONS -**--detach**, **-d** +#### **--detach**, **-d** Start the exec session, but do not attach to it. The command will run in the background and the exec session will be automatically removed when it completes. The **podman exec** command will print the ID of the exec session and exit immediately after it starts. -**--detach-keys**=*sequence* +#### **--detach-keys**=*sequence* Specify the key sequence for detaching a container. Format is a single character `[a-Z]` or one or more `ctrl-<value>` characters where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. Specifying "" will disable this feature. The default is *ctrl-p,ctrl-q*. -**--env**, **-e** +#### **--env**, **-e** You may specify arbitrary environment variables that are available for the command to be executed. -**--env-file**=*file* +#### **--env-file**=*file* Read in a line delimited file of environment variables. -**--interactive**, **-i**=*true|false* +#### **--interactive**, **-i**=*true|false* When set to true, keep stdin open even if not attached. The default is *false*. -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**--preserve-fds**=*N* +#### **--preserve-fds**=*N* Pass down to the process N additional file descriptors (in addition to 0, 1, 2). The total FDs will be 3+N. -**--privileged** +#### **--privileged** Give extended privileges to this container. The default is *false*. @@ -61,17 +61,17 @@ points, Apparmor/SELinux separation, and Seccomp filters are all disabled. Rootless containers cannot have more privileges than the account that launched them. -**--tty**, **-t** +#### **--tty**, **-t** Allocate a pseudo-TTY. -**--user**, **-u** +#### **--user**, **-u** Sets the username or UID used and optionally the groupname or GID for the specified command. The following examples are all valid: --user [user | user:group | uid | uid:gid | user:gid | uid:group ] -**--workdir**, **-w**=*path* +#### **--workdir**, **-w**=*path* Working directory inside the container diff --git a/docs/source/markdown/podman-export.1.md b/docs/source/markdown/podman-export.1.md index 4286d0e2f..647c25770 100644 --- a/docs/source/markdown/podman-export.1.md +++ b/docs/source/markdown/podman-export.1.md @@ -22,11 +22,11 @@ Note: `:` is a restricted character and cannot be part of the file name. ## OPTIONS -**--output**, **-o** +#### **--output**, **-o** Write to a file, default is STDOUT -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-generate-kube.1.md b/docs/source/markdown/podman-generate-kube.1.md index 47d6e0445..6fad89b1f 100644 --- a/docs/source/markdown/podman-generate-kube.1.md +++ b/docs/source/markdown/podman-generate-kube.1.md @@ -14,11 +14,11 @@ Note that the generated Kubernetes YAML file can be used to re-run the deploymen ## OPTIONS -**--filename**, **-f**=**filename** +#### **--filename**, **-f**=**filename** Output to the given file, instead of STDOUT. If the file already exists, `generate kube` will refuse to replace it and return an error. -**--service**, **-s** +#### **--service**, **-s** Generate a Kubernetes service object in addition to the Pods. Used to generate a Service specification for the corresponding Pod output. In particular, if the object has portmap bindings, the service specification will include a NodePort declaration to expose the service. A random port is assigned by Podman in the specification. diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md index f95c57399..445888d30 100644 --- a/docs/source/markdown/podman-generate-systemd.1.md +++ b/docs/source/markdown/podman-generate-systemd.1.md @@ -14,42 +14,42 @@ _Note: If you use this command with the remote client, you would still have to p ## OPTIONS -**--files**, **-f** +#### **--files**, **-f** Generate files instead of printing to stdout. The generated files are named {container,pod}-{ID,name}.service and will be placed in the current working directory. Note: On a system with SELinux enabled, the generated files will inherit contexts from the current working directory. Depending on the SELinux setup, changes to the generated files using `restorecon`, `chcon`, or `semanage` may be required to allow systemd to access these files. Alternatively, use the `-Z` option when running `mv` or `cp`. -**--format**=*format* +#### **--format**=*format* Print the created units in specified format (json). If `--files` is specified the paths to the created files will be printed instead of the unit content. -**--name**, **-n** +#### **--name**, **-n** Use the name of the container for the start, stop, and description in the unit file -**--new** +#### **--new** Using this flag will yield unit files that do not expect containers and pods to exist. Instead, new containers and pods are created based on their configuration files. The unit files are created best effort and may need to be further edited; please review the generated files carefully before using them in production. -**--time**, **-t**=*value* +#### **--time**, **-t**=*value* Override the default stop timeout for the container with the given value. -**--restart-policy**=*policy* +#### **--restart-policy**=*policy* Set the systemd restart policy. The restart-policy must be one of: "no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", or "always". The default policy is *on-failure*. -**--container-prefix**=*prefix* +#### **--container-prefix**=*prefix* Set the systemd unit name prefix for containers. The default is *container*. -**--pod-prefix**=*prefix* +#### **--pod-prefix**=*prefix* Set the systemd unit name prefix for pods. The default is *pod*. -**--separator**=*separator* +#### **--separator**=*separator* Set the systemd unit name separator between the name/id of a container/pod and the prefix. The default is *-*. diff --git a/docs/source/markdown/podman-healthcheck-run.1.md b/docs/source/markdown/podman-healthcheck-run.1.md index 546d847eb..fa10d5dca 100644 --- a/docs/source/markdown/podman-healthcheck-run.1.md +++ b/docs/source/markdown/podman-healthcheck-run.1.md @@ -21,7 +21,7 @@ Possible errors that can occur during the healthcheck are: * container is not running ## OPTIONS -**--help** +#### **--help** Print usage statement diff --git a/docs/source/markdown/podman-history.1.md b/docs/source/markdown/podman-history.1.md index 26b213af9..2dd41e9f5 100644 --- a/docs/source/markdown/podman-history.1.md +++ b/docs/source/markdown/podman-history.1.md @@ -29,26 +29,26 @@ Valid placeholders for the Go template are listed below: ## OPTIONS -**--human**, **-H**=*true|false* +#### **--human**, **-H**=*true|false* Display sizes and dates in human readable format (default *true*). -**--no-trunc**=*true|false* +#### **--no-trunc**=*true|false* Do not truncate the output (default *false*). -**--notruncate** +#### **--notruncate** Do not truncate the output -**--quiet**, **-q**=*true|false* +#### **--quiet**, **-q**=*true|false* Print the numeric IDs only (default *false*). -**--format**=*format* +#### **--format**=*format* Alter the output for a format like 'json' or a Go template. -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-image-diff.1.md b/docs/source/markdown/podman-image-diff.1.md index 1e7397cd8..9b1dfa45a 100644 --- a/docs/source/markdown/podman-image-diff.1.md +++ b/docs/source/markdown/podman-image-diff.1.md @@ -11,7 +11,7 @@ Displays changes on a container or image's filesystem. The container or image w ## OPTIONS -**--format** +#### **--format** Alter the output into a different format. The only valid format for diff is `json`. diff --git a/docs/source/markdown/podman-image-exists.1.md b/docs/source/markdown/podman-image-exists.1.md index 877324cd1..5d5cb1647 100644 --- a/docs/source/markdown/podman-image-exists.1.md +++ b/docs/source/markdown/podman-image-exists.1.md @@ -14,7 +14,7 @@ was an issue accessing the local storage. ## OPTIONS -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-image-mount.1.md b/docs/source/markdown/podman-image-mount.1.md index f98b46571..8cb9684a7 100644 --- a/docs/source/markdown/podman-image-mount.1.md +++ b/docs/source/markdown/podman-image-mount.1.md @@ -22,11 +22,11 @@ returned. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Mount all images. -**--format**=*format* +#### **--format**=*format* Print the mounted images in specified format (json). diff --git a/docs/source/markdown/podman-image-prune.1.md b/docs/source/markdown/podman-image-prune.1.md index d4fbe45c3..d8558d244 100644 --- a/docs/source/markdown/podman-image-prune.1.md +++ b/docs/source/markdown/podman-image-prune.1.md @@ -14,19 +14,19 @@ does not have any containers based on it. The image prune command does not prune cache images that only use layers that are necessary for other images. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Remove dangling images and images that have no associated containers. -**--filter**=*filters* +#### **--filter**=*filters* Provide filter values. -**--force**, **-f** +#### **--force**, **-f** Do not provide an interactive prompt for container removal. -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-image-sign.1.md b/docs/source/markdown/podman-image-sign.1.md index fa75691bc..1bd6e5b9d 100644 --- a/docs/source/markdown/podman-image-sign.1.md +++ b/docs/source/markdown/podman-image-sign.1.md @@ -13,20 +13,20 @@ derived from the registry configuration files in /etc/containers/registries.d. B ## OPTIONS -**--help**, **-h** +#### **--help**, **-h** Print usage statement. -**--cert-dir**=*path* +#### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) -**--directory**, **-d**=*dir* +#### **--directory**, **-d**=*dir* Store the signatures in the specified directory. Default: /var/lib/containers/sigstore -**--sign-by**=*identity* +#### **--sign-by**=*identity* Override the default identity of the signature. diff --git a/docs/source/markdown/podman-image-tree.1.md b/docs/source/markdown/podman-image-tree.1.md index c4624e05c..9a52e8444 100644 --- a/docs/source/markdown/podman-image-tree.1.md +++ b/docs/source/markdown/podman-image-tree.1.md @@ -13,11 +13,11 @@ If you do not provide a *tag*, Podman will default to `latest` for the *image*. Layers are indicated with image tags as `Top Layer of`, when the tag is known locally. ## OPTIONS -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--whatrequires** +#### **--whatrequires** Show all child images and layers of the specified image diff --git a/docs/source/markdown/podman-image-trust.1.md b/docs/source/markdown/podman-image-trust.1.md index 8b80ca602..29dfee87e 100644 --- a/docs/source/markdown/podman-image-trust.1.md +++ b/docs/source/markdown/podman-image-trust.1.md @@ -37,15 +37,15 @@ Require signature (“signedBy”). Trust may be updated using the command **podman image trust set** for an existing trust scope. ## OPTIONS -**-h**, **--help** +#### **-h**, **--help** Print usage statement. -**-f**, **--pubkeysfile**=*KEY1* +#### **-f**, **--pubkeysfile**=*KEY1* A path to an exported public key on the local system. Key paths will be referenced in policy.json. Any path to a file may be used but locating the file in **/etc/pki/containers** is recommended. Options may be used multiple times to require an image be signed by multiple keys. The **--pubkeysfile** option is required for the **signedBy** type. -**-t**, **--type**=*value* +#### **-t**, **--type**=*value* The trust type for this policy entry. Accepted values: **signedBy** (default): Require signatures with corresponding list of @@ -56,10 +56,10 @@ Trust may be updated using the command **podman image trust set** for an existin ## show OPTIONS -**--raw** +#### **--raw** Output trust policy file as raw JSON -**-j**, **--json** +#### **-j**, **--json** Output trust as JSON for machine parsing ## EXAMPLES diff --git a/docs/source/markdown/podman-image-unmount.1.md b/docs/source/markdown/podman-image-unmount.1.md index c026c49ac..62e879fa1 100644 --- a/docs/source/markdown/podman-image-unmount.1.md +++ b/docs/source/markdown/podman-image-unmount.1.md @@ -19,11 +19,11 @@ counter reaches zero indicating no other processes are using the mount. An unmount can be forced with the --force flag. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** All of the currently mounted images will be unmounted. -**--force**, **-f** +#### **--force**, **-f** Force the unmounting of specified images' root file system, even if other processes have mounted it. diff --git a/docs/source/markdown/podman-images.1.md b/docs/source/markdown/podman-images.1.md index 379f7573e..531570666 100644 --- a/docs/source/markdown/podman-images.1.md +++ b/docs/source/markdown/podman-images.1.md @@ -15,15 +15,15 @@ Displays locally stored images, their names, and their IDs. ## OPTIONS -**-a**, **--all** +#### **-a**, **--all** Show all images (by default filter out the intermediate image layers). The default is false. -**--digests** +#### **--digests** Show image digests -**-f**, **--filter**=*filter* +#### **-f**, **--filter**=*filter* Filter output based on conditions provided @@ -47,7 +47,7 @@ Filter output based on conditions provided **reference=** Filter by image name, specified as regular expressions. -**--format**=*format* +#### **--format**=*format* Change the default output format. This can be of a supported type like 'json' or a Go template. @@ -64,23 +64,23 @@ Valid placeholders for the Go template are listed below: | .Size | Size of layer on disk | | .History | History of the image layer | -**--history** +#### **--history** Display the history of image names. If an image gets re-tagged or untagged, then the image name history gets prepended (latest image first). This is especially useful when undoing a tag operation or an image does not contain any name because it has been untagged. -**--noheading**, **-n** +#### **--noheading**, **-n** Omit the table headings from the listing of images. -**--no-trunc** +#### **--no-trunc** Do not truncate output. -**--quiet**, **-q** +#### **--quiet**, **-q** Lists only the image IDs. -**--sort**=*sort* +#### **--sort**=*sort* Sort by created, id, repository, size or tag (default: created) diff --git a/docs/source/markdown/podman-import.1.md b/docs/source/markdown/podman-import.1.md index 946b680dd..ba512ca12 100644 --- a/docs/source/markdown/podman-import.1.md +++ b/docs/source/markdown/podman-import.1.md @@ -18,17 +18,18 @@ Note: `:` is a restricted character and cannot be part of the file name. ## OPTIONS -**-c**, **--change**=*instruction* +#### **-c**, **--change**=*instruction* Apply the following possible instructions to the created image: **CMD** | **ENTRYPOINT** | **ENV** | **EXPOSE** | **LABEL** | **STOPSIGNAL** | **USER** | **VOLUME** | **WORKDIR** + Can be set multiple times -**--message**, **-m**=*message* +#### **--message**, **-m**=*message* Set commit message for imported image -**--quiet**, **-q** +#### **--quiet**, **-q** Shows progress on the import @@ -36,7 +37,7 @@ Shows progress on the import Print additional debugging information -**--help**, **-h** +#### **--help**, **-h** Print usage statement @@ -55,7 +56,7 @@ db65d991f3bbf7f31ed1064db9a6ced7652e3f8166c4736aa9133dadd3c7acb3 ``` ``` -$ podman import --change "ENTRYPOINT ["/bin/sh","-c","test-image"]" --change LABEL=blue=image test-image.tar image-imported +$ podman import --change 'ENTRYPOINT ["/bin/sh","-c","test-image"]' --change LABEL=blue=image test-image.tar image-imported Getting image source signatures Copying blob e3b0c44298fc skipped: already exists Copying config 1105523502 done diff --git a/docs/source/markdown/podman-info.1.md b/docs/source/markdown/podman-info.1.md index 19dd61c15..78895fa15 100644 --- a/docs/source/markdown/podman-info.1.md +++ b/docs/source/markdown/podman-info.1.md @@ -15,11 +15,11 @@ Displays information pertinent to the host, current storage stats, configured co ## OPTIONS -**-D**, **--debug** +#### **-D**, **--debug** Show additional information -**-f**, **--format**=*format* +#### **-f**, **--format**=*format* Change output format to "json" or a Go template. diff --git a/docs/source/markdown/podman-init.1.md b/docs/source/markdown/podman-init.1.md index 3b49cfb99..e37902e13 100644 --- a/docs/source/markdown/podman-init.1.md +++ b/docs/source/markdown/podman-init.1.md @@ -18,11 +18,11 @@ This can be used to inspect the container before it runs, or debug why a contain ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Initialize all containers. Containers that have already initialized (including containers that have been started and are running) are ignored. -**--latest**, **-l** +#### **--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. diff --git a/docs/source/markdown/podman-inspect.1.md b/docs/source/markdown/podman-inspect.1.md index eb7cf74c6..d0e2fbc99 100644 --- a/docs/source/markdown/podman-inspect.1.md +++ b/docs/source/markdown/podman-inspect.1.md @@ -24,17 +24,17 @@ For more inspection options, see: ## OPTIONS -**--type**, **-t**=*type* +#### **--type**, **-t**=*type* Return JSON for the specified type. Type can be 'container', 'image', 'volume', 'network', 'pod', or 'all' (default: all) (Only meaningful when invoked as *podman inspect*) -**--format**, **-f**=*format* +#### **--format**, **-f**=*format* Format the output using the given Go template. The keys of the returned JSON can be used as the values for the --format flag (see examples below). -**--latest**, **-l** +#### **--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. @@ -43,7 +43,7 @@ This option can be used to inspect the latest pod created when used with --type The latest option is not supported on the remote client or when invoked as *podman image inspect*. -**--size**, **-s** +#### **--size**, **-s** In addition to normal output, display the total file size if the type is a container. diff --git a/docs/source/markdown/podman-kill.1.md b/docs/source/markdown/podman-kill.1.md index 010c04edc..5956c03da 100644 --- a/docs/source/markdown/podman-kill.1.md +++ b/docs/source/markdown/podman-kill.1.md @@ -12,18 +12,18 @@ podman\-kill - Kill the main process in one or more containers The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Signal all running containers. This does not include paused containers. -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**--signal**, **-s** +#### **--signal**, **-s** Signal to send to the container. For more information on Linux signals, refer to *man signal(7)*. diff --git a/docs/source/markdown/podman-load.1.md b/docs/source/markdown/podman-load.1.md index 308a3493b..cdc99fbf2 100644 --- a/docs/source/markdown/podman-load.1.md +++ b/docs/source/markdown/podman-load.1.md @@ -26,7 +26,7 @@ Note: `:` is a restricted character and cannot be part of the file name. ## OPTIONS -**--input**, **-i**=*input* +#### **--input**, **-i**=*input* Read from archive file, default is STDIN. @@ -34,11 +34,11 @@ The remote client requires the use of this option. NOTE: Use the environment variable `TMPDIR` to change the temporary storage location of container images. Podman defaults to use `/var/tmp`. -**--quiet**, **-q** +#### **--quiet**, **-q** Suppress the progress output -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-login.1.md b/docs/source/markdown/podman-login.1.md index 7c09d99fe..89ef289e3 100644 --- a/docs/source/markdown/podman-login.1.md +++ b/docs/source/markdown/podman-login.1.md @@ -28,41 +28,41 @@ For more details about format and configurations of the auth.json file, please r ## OPTIONS -**--password**, **-p**=*password* +#### **--password**, **-p**=*password* Password for registry -**--password-stdin** +#### **--password-stdin** Take the password from stdin -**--username**, **-u**=*username* +#### **--username**, **-u**=*username* Username for registry -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json. Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--get-login** +#### **--get-login** Return the logged-in user for the registry. Return error if no login is found. -**--cert-dir**=*path* +#### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) -**--tls-verify**=*true|false* +#### **--tls-verify**=*true|false* Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified, TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf. -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-logout.1.md b/docs/source/markdown/podman-logout.1.md index 25f6d97b1..c35c4856b 100644 --- a/docs/source/markdown/podman-logout.1.md +++ b/docs/source/markdown/podman-logout.1.md @@ -21,18 +21,18 @@ All the cached credentials can be removed by setting the **all** flag. ## OPTIONS -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json. Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--all**, **-a** +#### **--all**, **-a** Remove the cached credentials for all registries in the auth file -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-logs.1.md b/docs/source/markdown/podman-logs.1.md index bcfc0bae8..c93e4c9d7 100644 --- a/docs/source/markdown/podman-logs.1.md +++ b/docs/source/markdown/podman-logs.1.md @@ -15,7 +15,7 @@ any logs at the time you execute podman logs). ## OPTIONS -**--follow**, **-f** +#### **--follow**, **-f** Follow log output. Default is false. @@ -23,30 +23,30 @@ Note: If you are following a container which is removed `podman container rm` or removed on exit `podman run --rm ...`, then there is a chance the the log file will be removed before `podman logs` reads the final content. -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**-n**, **--names** +#### **-n**, **--names** Output the container name in the log -**--since**=*TIMESTAMP* +#### **--since**=*TIMESTAMP* Show logs since TIMESTAMP. The --since option can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Supported formats for date formatted time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00, and 2006-01-02. -**--tail**=*LINES* +#### **--tail**=*LINES* Output the specified number of LINES at the end of the logs. LINES must be an integer. Defaults to -1, which prints all lines -**--timestamps**, **-t** +#### **--timestamps**, **-t** Show timestamps in the log outputs. The default is false diff --git a/docs/source/markdown/podman-manifest-add.1.md b/docs/source/markdown/podman-manifest-add.1.md index 4c0bad2ae..6e6409765 100644 --- a/docs/source/markdown/podman-manifest-add.1.md +++ b/docs/source/markdown/podman-manifest-add.1.md @@ -15,25 +15,25 @@ The list image's ID. ## OPTIONS -**--all** +#### **--all** If the image which should be added to the list or index is itself a list or index, add all of the contents to the local list. By default, only one image from such a list or index will be added to the list or index. Combining *--all* with any of the other options described below is NOT recommended. -**--annotation** *annotation=value* +#### **--annotation** *annotation=value* Set an annotation on the entry for the newly-added image. -**--arch** +#### **--arch** Override the architecture which the list or index records as a requirement for the image. If *imageName* refers to a manifest list or image index, the architecture information will be retrieved from it. Otherwise, it will be retrieved from the image's configuration information. -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. @@ -41,39 +41,39 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--cert-dir**=*path* +#### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) -**--creds**=*creds* +#### **--creds**=*creds* The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. -**--features** +#### **--features** Specify the features list which the list or index records as requirements for the image. This option is rarely used. -**--os** +#### **--os** Override the OS which the list or index records as a requirement for the image. If *imagename* refers to a manifest list or image index, the OS information will be retrieved from it. Otherwise, it will be retrieved from the image's configuration information. -**--os-version** +#### **--os-version** Specify the OS version which the list or index records as a requirement for the image. This option is rarely used. -**--tls-verify** +#### **--tls-verify** Require HTTPS and verify certificates when talking to container registries (defaults to true). -**--variant** +#### **--variant** Specify the variant which the list or index records for the image. This option is typically used to distinguish between multiple entries which share the same diff --git a/docs/source/markdown/podman-manifest-annotate.1.md b/docs/source/markdown/podman-manifest-annotate.1.md index 25ad4642e..2126b71ec 100644 --- a/docs/source/markdown/podman-manifest-annotate.1.md +++ b/docs/source/markdown/podman-manifest-annotate.1.md @@ -12,39 +12,39 @@ Adds or updates information about an image included in a manifest list or image ## OPTIONS -**--annotation** *annotation=value* +#### **--annotation** *annotation=value* Set an annotation on the entry for the specified image. -**--arch** +#### **--arch** Override the architecture which the list or index records as a requirement for the image. This is usually automatically retrieved from the image's configuration information, so it is rarely necessary to use this option. -**--features** +#### **--features** Specify the features list which the list or index records as requirements for the image. This option is rarely used. -**--os** +#### **--os** Override the OS which the list or index records as a requirement for the image. This is usually automatically retrieved from the image's configuration information, so it is rarely necessary to use this option. -**--os-features** +#### **--os-features** Specify the OS features list which the list or index records as requirements for the image. This option is rarely used. -**--os-version** +#### **--os-version** Specify the OS version which the list or index records as a requirement for the image. This option is rarely used. -**--variant** +#### **--variant** Specify the variant which the list or index records for the image. This option is typically used to distinguish between multiple entries which share the same diff --git a/docs/source/markdown/podman-manifest-create.1.md b/docs/source/markdown/podman-manifest-create.1.md index 537a641f2..3a3d5e4b0 100644 --- a/docs/source/markdown/podman-manifest-create.1.md +++ b/docs/source/markdown/podman-manifest-create.1.md @@ -16,7 +16,7 @@ index. ## OPTIONS -**--all** +#### **--all** 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 diff --git a/docs/source/markdown/podman-manifest-push.1.md b/docs/source/markdown/podman-manifest-push.1.md index 9cf0b159c..0c1e5ea04 100644 --- a/docs/source/markdown/podman-manifest-push.1.md +++ b/docs/source/markdown/podman-manifest-push.1.md @@ -14,12 +14,12 @@ The list image's ID and the digest of the image's manifest. ## OPTIONS -**--all** +#### **--all** Push the images mentioned in the manifest list or image index, in addition to the list or index itself. -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. @@ -27,42 +27,42 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--cert-dir**=*path* +#### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) -**--creds**=*creds* +#### **--creds**=*creds* The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. -**--digestfile**=*Digestfile* +#### **--digestfile**=*Digestfile* After copying the image, write the digest of the resulting image to the file. -**--format**, **-f**=*format* +#### **--format**, **-f**=*format* Manifest list type (oci or v2s2) to use when pushing the list (default is oci). -**--purge** +#### **--purge** Delete the manifest list or image index from local storage if pushing succeeds. -**--quiet**, **-q** +#### **--quiet**, **-q** When writing the manifest, suppress progress output -**--remove-signatures** +#### **--remove-signatures** Don't copy signatures when pushing images. -**--sign-by**=*fingerprint* +#### **--sign-by**=*fingerprint* Sign the pushed images using the GPG key that matches the specified fingerprint. -**--tls-verify** +#### **--tls-verify** Require HTTPS and verify certificates when talking to container registries. (defaults to true) diff --git a/docs/source/markdown/podman-mount.1.md b/docs/source/markdown/podman-mount.1.md index a6ed3f10d..3e7aeaa32 100644 --- a/docs/source/markdown/podman-mount.1.md +++ b/docs/source/markdown/podman-mount.1.md @@ -26,15 +26,15 @@ returned. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Mount all podman containers. (External containers will not be mounted) -**--format**=*format* +#### **--format**=*format* Print the mounted containers in specified format (json). -**--latest**, **-l** +#### **--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 @@ -42,7 +42,7 @@ started container could be from either of those methods. The latest option is not supported on the remote client. -**--notruncate** +#### **--notruncate** Do not truncate IDs in output. diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md index 45d9d9b0b..8b8399c3e 100644 --- a/docs/source/markdown/podman-network-create.1.md +++ b/docs/source/markdown/podman-network-create.1.md @@ -17,38 +17,42 @@ If no options are provided, Podman will assign a free subnet and name for your n Upon completion of creating the network, Podman will display the path to the newly added network file. ## OPTIONS -**--disable-dns** +#### **--disable-dns** Disables the DNS plugin for this network which if enabled, can perform container to container name resolution. -**-d**, **--driver** +#### **-d**, **--driver** Driver to manage the network (default "bridge"). Currently only `bridge` is supported. -**--gateway** +#### **--gateway** Define a gateway for the subnet. If you want to provide a gateway address, you must also provide a *subnet* option. -**--internal** +#### **--internal** Restrict external access of this network -**--ip-range** +#### **--ip-range** Allocate container IP from a range. The range must be a complete subnet and in CIDR notation. The *ip-range* option must be used with a *subnet* option. -**--macvlan** +#### **--macvlan** Create a *Macvlan* based connection rather than a classic bridge. You must pass an interface name from the host for the Macvlan connection. -**--subnet** +#### **--subnet** The subnet in CIDR notation. +#### **--ipv6** + +Enable IPv6 (Dual Stack) networking. You must pass a IPv6 subnet. The *subnet* option must be used with the *ipv6* option. + ## EXAMPLE Create a network with no options @@ -63,6 +67,13 @@ Create a network named *newnet* that uses *192.5.0.0/16* for its subnet. /etc/cni/net.d/newnet.conflist ``` +Create an IPv6 network named *newnetv6*, you must specify the subnet for this network, otherwise the command will fail. +For this example, we use *2001:db8::/64* for its subnet. +``` +# podman network create --subnet 2001:db8::/64 --ipv6 newnetv6 +/etc/cni/net.d/newnetv6.conflist +``` + Create a network named *newnet* that uses *192.168.33.0/24* and defines a gateway as *192.168.133.3* ``` # podman network create --subnet 192.168.33.0/24 --gateway 192.168.33.3 newnet diff --git a/docs/source/markdown/podman-network-inspect.1.md b/docs/source/markdown/podman-network-inspect.1.md index c75c6788a..47d647b3f 100644 --- a/docs/source/markdown/podman-network-inspect.1.md +++ b/docs/source/markdown/podman-network-inspect.1.md @@ -10,7 +10,7 @@ podman\-network\-inspect - Displays the raw CNI network configuration for one or Display the raw (JSON format) network configuration. This command is not available for rootless users. ## OPTIONS -**--format**, **-f** +#### **--format**, **-f** Pretty-print networks to JSON or using a Go template. diff --git a/docs/source/markdown/podman-network-ls.1.md b/docs/source/markdown/podman-network-ls.1.md index 7b20cf5e0..34b40b3ae 100644 --- a/docs/source/markdown/podman-network-ls.1.md +++ b/docs/source/markdown/podman-network-ls.1.md @@ -10,15 +10,15 @@ podman\-network\-ls - Display a summary of CNI networks Displays a list of existing podman networks. This command is not available for rootless users. ## OPTIONS -**--quiet**, **-q** +#### **--quiet**, **-q** The `quiet` option will restrict the output to only the network names. -**--format**, **-f** +#### **--format**, **-f** Pretty-print networks to JSON or using a Go template. -**--filter** +#### **--filter** Provide filter values (e.g. 'name=podman'). diff --git a/docs/source/markdown/podman-network-rm.1.md b/docs/source/markdown/podman-network-rm.1.md index 616bb2514..ad4bc11e2 100644 --- a/docs/source/markdown/podman-network-rm.1.md +++ b/docs/source/markdown/podman-network-rm.1.md @@ -10,7 +10,7 @@ podman\-network\-rm - Remove one or more CNI networks Delete one or more Podman networks. ## OPTIONS -**--force**, **-f** +#### **--force**, **-f** The `force` option will remove all containers that use the named network. If the container is running, the container will be stopped and removed. diff --git a/docs/source/markdown/podman-pause.1.md b/docs/source/markdown/podman-pause.1.md index dfd4da416..123362822 100644 --- a/docs/source/markdown/podman-pause.1.md +++ b/docs/source/markdown/podman-pause.1.md @@ -13,7 +13,7 @@ Pauses all the processes in one or more containers. You may use container IDs o ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Pause all running containers. diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md index 97b0dc09a..c8391861d 100644 --- a/docs/source/markdown/podman-play-kube.1.md +++ b/docs/source/markdown/podman-play-kube.1.md @@ -17,7 +17,7 @@ Note: HostPath volume types created by play kube will be given an SELinux privat ## OPTIONS -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. @@ -25,42 +25,46 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--cert-dir**=*path* +#### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) -**--configmap**=*path* +#### **--configmap**=*path* Use Kubernetes configmap YAML at path to provide a source for environment variable values within the containers of the pod. Note: The *--configmap* option can be used multiple times or a comma-separated list of paths can be used to pass multiple Kubernetes configmap YAMLs. -**--creds** +#### **--creds** The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. -**--network**=*cni networks* +#### **--log-driver**=driver + +Set logging driver for all created containers. + +#### **--network**=*cni networks* A comma-separated list of the names of CNI networks the pod should join. -**--quiet**, **-q** +#### **--quiet**, **-q** Suppress output information when pulling images -**--seccomp-profile-root**=*path* +#### **--seccomp-profile-root**=*path* Directory path for seccomp profiles (default: "/var/lib/kubelet/seccomp"). (Not available for remote commands) -**--tls-verify**=*true|false* +#### **--tls-verify**=*true|false* Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified, TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf. -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-pod-create.1.md b/docs/source/markdown/podman-pod-create.1.md index 7b0902c19..6fd42f800 100644 --- a/docs/source/markdown/podman-pod-create.1.md +++ b/docs/source/markdown/podman-pod-create.1.md @@ -15,71 +15,71 @@ containers added to it. The pod id is printed to STDOUT. You can then use ## OPTIONS -**--add-host**=_host_:_ip_ +#### **--add-host**=_host_:_ip_ Add a host to the /etc/hosts file shared between all containers in the pod. -**--cgroup-parent**=*path* +#### **--cgroup-parent**=*path* Path to cgroups under which the cgroup for the pod will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist. -**--dns**=*ipaddr* +#### **--dns**=*ipaddr* Set custom DNS servers in the /etc/resolv.conf file that will be shared between all containers in the pod. A special option, "none" is allowed which disables creation of /etc/resolv.conf for the pod. -**--dns-opt**=*option* +#### **--dns-opt**=*option* Set custom DNS options in the /etc/resolv.conf file that will be shared between all containers in the pod. -**--dns-search**=*domain* +#### **--dns-search**=*domain* Set custom DNS search domains in the /etc/resolv.conf file that will be shared between all containers in the pod. -**--help** +#### **--help** Print usage statement. -**--hostname**=name +#### **--hostname**=name Set a hostname to the pod -**--infra**=**true**|**false** +#### **--infra**=**true**|**false** Create an infra container and associate it with the pod. An infra container is a lightweight container used to coordinate the shared kernel namespace of a pod. Default: true. -**--infra-conmon-pidfile**=*file* +#### **--infra-conmon-pidfile**=*file* Write the pid of the infra container's **conmon** process to a file. As **conmon** runs in a separate process than Podman, this is necessary when using systemd to manage Podman containers and pods. -**--infra-command**=*command* +#### **--infra-command**=*command* The command that will be run to start the infra container. Default: "/pause". -**--infra-image**=*image* +#### **--infra-image**=*image* The image that will be created for the infra container. Default: "k8s.gcr.io/pause:3.1". -**--ip**=*ipaddr* +#### **--ip**=*ipaddr* Set a static IP for the pod's shared network. -**-l**, **--label**=*label* +#### **-l**, **--label**=*label* Add metadata to a pod (e.g., --label com.example.key=value). -**--label-file**=*label* +#### **--label-file**=*label* Read in a line delimited file of labels. -**--mac-address**=*address* +#### **--mac-address**=*address* Set a static MAC address for the pod's shared network. -**-n**, **--name**=*name* +#### **-n**, **--name**=*name* Assign a name to the pod. -**--network**=*mode* +#### **--network**=*mode* Set network mode for the pod. Supported values are - `bridge`: Create a network stack on the default bridge. This is the default for rootful containers. @@ -96,15 +96,19 @@ Set network mode for the pod. Supported values are - **port_handler=rootlesskit**: Use rootlesskit for port forwarding. Default. - **port_handler=slirp4netns**: Use the slirp4netns port forwarding. -**--no-hosts**=**true**|**false** +#### **--network-alias**=strings + +Add a DNS alias for the container. When the container is joined to a CNI network with support for the dnsname plugin, the container will be accessible through this name from other containers in the network. + +#### **--no-hosts**=**true**|**false** Disable creation of /etc/hosts for the pod. -**--pod-id-file**=*path* +#### **--pod-id-file**=*path* Write the pod ID to the file. -**-p**, **--publish**=*port* +#### **-p**, **--publish**=*port* Publish a port or range of ports from the pod to the host. @@ -115,11 +119,11 @@ Use `podman port` to see the actual mapping: `podman port CONTAINER $CONTAINERPO NOTE: This cannot be modified once the pod is created. -**--replace**=**true**|**false** +#### **--replace**=**true**|**false** If another pod with the same name already exists, replace and remove it. The default is **false**. -**--share**=*namespace* +#### **--share**=*namespace* A comma delimited list of kernel namespaces to share. If none or "" is specified, no namespaces will be shared. The namespaces to choose from are ipc, net, pid, uts. diff --git a/docs/source/markdown/podman-pod-inspect.1.md b/docs/source/markdown/podman-pod-inspect.1.md index bc04b2b32..ece3ab885 100644 --- a/docs/source/markdown/podman-pod-inspect.1.md +++ b/docs/source/markdown/podman-pod-inspect.1.md @@ -11,14 +11,14 @@ Displays configuration and state information about a given pod. It also display that belong to the pod. ## OPTIONS -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, use the last created pod. If you use methods other than Podman to run pods such as CRI-O, the last started pod could be from either of those methods. The latest option is not supported on the remote client. -**-f**, **--format**=*format* +#### **-f**, **--format**=*format* Change the default output format. This can be of a supported type like 'json' or a Go template. diff --git a/docs/source/markdown/podman-pod-kill.1.md b/docs/source/markdown/podman-pod-kill.1.md index 596e15cea..d791b7cbd 100644 --- a/docs/source/markdown/podman-pod-kill.1.md +++ b/docs/source/markdown/podman-pod-kill.1.md @@ -10,18 +10,18 @@ podman\-pod\-kill - Kill the main process of each container in one or more pods The main process of each container inside the pods specified will be sent SIGKILL, or any signal specified with option --signal. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Sends signal to all containers associated with a pod. -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, use the last created pod. If you use methods other than Podman to run pods such as CRI-O, the last started pod could be from either of those methods. The latest option is not supported on the remote client. -**--signal**, **-s** +#### **--signal**, **-s** Signal to send to the containers in the pod. For more information on Linux signals, refer to *man signal(7)*. diff --git a/docs/source/markdown/podman-pod-pause.1.md b/docs/source/markdown/podman-pod-pause.1.md index 9533ed4a1..fc1727737 100644 --- a/docs/source/markdown/podman-pod-pause.1.md +++ b/docs/source/markdown/podman-pod-pause.1.md @@ -11,11 +11,11 @@ Pauses all the running processes in the containers of one or more pods. You may ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Pause all pods. -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, pause the last created pod. diff --git a/docs/source/markdown/podman-pod-prune.1.md b/docs/source/markdown/podman-pod-prune.1.md index 5b4c4661c..e90164c15 100644 --- a/docs/source/markdown/podman-pod-prune.1.md +++ b/docs/source/markdown/podman-pod-prune.1.md @@ -11,7 +11,7 @@ podman-pod-prune - Remove all stopped pods and their containers ## OPTIONS -**--force**, **-f** +#### **--force**, **-f** Force removal of all running pods and their containers. The default is false. ## EXAMPLES diff --git a/docs/source/markdown/podman-pod-ps.1.md b/docs/source/markdown/podman-pod-ps.1.md index 3df4403b7..94747cd10 100644 --- a/docs/source/markdown/podman-pod-ps.1.md +++ b/docs/source/markdown/podman-pod-ps.1.md @@ -26,37 +26,37 @@ By default it lists: ## OPTIONS -**--ctr-names** +#### **--ctr-names** Includes the container names in the container info field -**--ctr-ids** +#### **--ctr-ids** Includes the container IDs in the container info field -**--ctr-status** +#### **--ctr-status** Includes the container statuses in the container info field -**--latest**, **-l** +#### **--latest**, **-l** Show the latest pod created (all states) The latest option is not supported on the remote client. -**--no-trunc** +#### **--no-trunc** Display the extended information -**--ns** +#### **--ns** Display namespace information of the pod -**--quiet**, **-q** +#### **--quiet**, **-q** Print the numeric IDs of the pods only -**--format**=*format* +#### **--format**=*format* Pretty-print containers to JSON or using a Go template @@ -72,13 +72,13 @@ Valid placeholders for the Go template are listed below: | .Cgroup | Cgroup path of pod | | .Created | Creation time of pod | | .InfraID | Pod infra container ID | -**--sort** +#### **--sort** Sort by created, ID, name, status, or number of containers Default: created -**--filter**, **-f**=*filter* +#### **--filter**, **-f**=*filter* Filter output based on conditions given @@ -94,7 +94,7 @@ Valid filters are listed below: | ctr-status | Container status within the pod | | ctr-number | Number of containers in the pod | -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-pod-restart.1.md b/docs/source/markdown/podman-pod-restart.1.md index 57f479102..19c46b9de 100644 --- a/docs/source/markdown/podman-pod-restart.1.md +++ b/docs/source/markdown/podman-pod-restart.1.md @@ -14,11 +14,11 @@ When restarting multiple pods, an error from restarting one pod will not effect ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Restarts all pods -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, restart the last created pod. diff --git a/docs/source/markdown/podman-pod-rm.1.md b/docs/source/markdown/podman-pod-rm.1.md index dd89694ec..4ca113cf7 100644 --- a/docs/source/markdown/podman-pod-rm.1.md +++ b/docs/source/markdown/podman-pod-rm.1.md @@ -11,27 +11,27 @@ podman\-pod\-rm - Remove one or more stopped pods and containers ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Remove all pods. Can be used in conjunction with \-f as well. -**--ignore**, **-i** +#### **--ignore**, **-i** Ignore errors when specified pods are not in the container store. A user might have decided to manually remove a pod which would lead to a failure during the ExecStop directive of a systemd service referencing that pod. -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, remove the last created pod. The latest option is not supported on the remote client. -**--force**, **-f** +#### **--force**, **-f** Stop running containers and delete all stopped containers before removal of pod. -**--pod-id-file** +#### **--pod-id-file** Read pod ID from the specified file and remove the pod. Can be specified multiple times. diff --git a/docs/source/markdown/podman-pod-start.1.md b/docs/source/markdown/podman-pod-start.1.md index 6c6cfa2cf..38117ebe8 100644 --- a/docs/source/markdown/podman-pod-start.1.md +++ b/docs/source/markdown/podman-pod-start.1.md @@ -12,17 +12,17 @@ to be started. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Starts all pods -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, start the last created pod. The latest option is not supported on the remote client. -**--pod-id-file** +#### **--pod-id-file** Read pod ID from the specified file and start the pod. Can be specified multiple times. diff --git a/docs/source/markdown/podman-pod-stats.1.md b/docs/source/markdown/podman-pod-stats.1.md index f70a5a919..b1b23cd06 100644 --- a/docs/source/markdown/podman-pod-stats.1.md +++ b/docs/source/markdown/podman-pod-stats.1.md @@ -11,25 +11,25 @@ Display a live stream of containers in one or more pods resource usage statistic ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Show all containers. Only running containers are shown by default -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, use the last created pod. The latest option is not supported on the remote client. -**--no-reset** +#### **--no-reset** Do not clear the terminal/screen in between reporting intervals -**--no-stream** +#### **--no-stream** Disable streaming pod stats and only pull the first result, default setting is false -**--format**=*template* +#### **--format**=*template* Pretty-print container statistics to JSON or using a Go template diff --git a/docs/source/markdown/podman-pod-stop.1.md b/docs/source/markdown/podman-pod-stop.1.md index 7ce9ff941..df1b36fc4 100644 --- a/docs/source/markdown/podman-pod-stop.1.md +++ b/docs/source/markdown/podman-pod-stop.1.md @@ -11,27 +11,27 @@ Stop containers in one or more pods. You may use pod IDs or names as input. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Stops all pods -**--ignore**, **-i** +#### **--ignore**, **-i** Ignore errors when specified pods are not in the container store. A user might have decided to manually remove a pod which would lead to a failure during the ExecStop directive of a systemd service referencing that pod. -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, stop the last created pod. The latest option is not supported on the remote client. -**--time**, **-t**=*time* +#### **--time**, **-t**=*time* Timeout to wait before forcibly stopping the containers in the pod. -**--pod-id-file** +#### **--pod-id-file** Read pod ID from the specified file and stop the pod. Can be specified multiple times. diff --git a/docs/source/markdown/podman-pod-top.1.md b/docs/source/markdown/podman-pod-top.1.md index 1f2ffd662..80334ebd0 100644 --- a/docs/source/markdown/podman-pod-top.1.md +++ b/docs/source/markdown/podman-pod-top.1.md @@ -11,11 +11,11 @@ Display the running processes of containers in a pod. The *format-descriptors* a ## OPTIONS -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, use the last created pod. diff --git a/docs/source/markdown/podman-pod-unpause.1.md b/docs/source/markdown/podman-pod-unpause.1.md index e0a88c2e3..0b3c2d384 100644 --- a/docs/source/markdown/podman-pod-unpause.1.md +++ b/docs/source/markdown/podman-pod-unpause.1.md @@ -11,11 +11,11 @@ Unpauses all the paused processes in the containers of one or more pods. You ma ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Unpause all pods. -**--latest**, **-l** +#### **--latest**, **-l** Instead of providing the pod name or ID, unpause the last created pod. diff --git a/docs/source/markdown/podman-port.1.md b/docs/source/markdown/podman-port.1.md index c9833f447..9d56d5e8c 100644 --- a/docs/source/markdown/podman-port.1.md +++ b/docs/source/markdown/podman-port.1.md @@ -13,12 +13,12 @@ List port mappings for the *container* or lookup the public-facing port that is ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** List all known port mappings for running containers. When using this option, you cannot pass any container names or private ports/protocols as filters. -**--latest**, **-l** +#### **--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. diff --git a/docs/source/markdown/podman-ps.1.md b/docs/source/markdown/podman-ps.1.md index 90f147222..5869f2307 100644 --- a/docs/source/markdown/podman-ps.1.md +++ b/docs/source/markdown/podman-ps.1.md @@ -30,17 +30,17 @@ all the containers information. By default it lists: ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Show all the containers created by Podman, default is only running containers. Note: Podman shares containers storage with other tools such as Buildah and CRI-O. In some cases these `external` containers might also exist in the same storage. Use the `--external` option to see these external containers. External containers show the 'storage' status. -**--external** +#### **--external** Display external containers that are not controlled by Podman but are stored in containers storage. These external containers are generally created via other container technology such as Buildah or CRI-O and may depend on the same container images that Podman is also using. External containers are denoted with either a 'buildah' or 'storage' in the COMMAND and STATUS column of the ps output. Only used with the --all option. -**--filter**, **-f** +#### **--filter**, **-f** Filter what containers are shown in the output. Multiple filters can be given with multiple uses of the --filter flag. @@ -62,7 +62,7 @@ Valid filters are listed below: | volume | [VolumeName] or [MountpointDestination] Volume mounted in container | | health | [Status] healthy or unhealthy | -**--format**=*format* +#### **--format**=*format* Pretty-print containers to JSON or using a Go template @@ -84,54 +84,54 @@ Valid placeholders for the Go template are listed below: | .Labels | All the labels assigned to the container | | .Mounts | Volumes mounted in the container | -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--last**, **-n** +#### **--last**, **-n** Print the n last created containers (all states) -**--latest**, **-l** +#### **--latest**, **-l** Show the latest container created (all states) The latest option is not supported on the remote client. -**--namespace**, **--ns** +#### **--namespace**, **--ns** Display namespace information -**--no-trunc** +#### **--no-trunc** Display the extended information -**--pod**, **-p** +#### **--pod**, **-p** Display the pods the containers are associated with -**--quiet**, **-q** +#### **--quiet**, **-q** Print the numeric IDs of the containers only -**--sort** +#### **--sort** Sort by command, created, id, image, names, runningfor, size, or status", Note: Choosing size will sort by size of rootFs, not alphabetically like the rest of the options Default: created -**--size**, **-s** +#### **--size**, **-s** Display the total file size -**--sync** +#### **--sync** Force a sync of container state with the OCI runtime. In some cases, a container's state in the runtime can become out of sync with Podman's state. This will update Podman's state based on what the OCI runtime reports. Forcibly syncing is much slower, but can resolve inconsistent state issues. -**--watch**, **-w** +#### **--watch**, **-w** Refresh the output with current containers on an interval in seconds. diff --git a/docs/source/markdown/podman-pull.1.md b/docs/source/markdown/podman-pull.1.md index 46beb4c42..130c54ba9 100644 --- a/docs/source/markdown/podman-pull.1.md +++ b/docs/source/markdown/podman-pull.1.md @@ -48,13 +48,13 @@ Images are stored in local image storage. ## OPTIONS -**--all-tags**, **a** +#### **--all-tags**, **a** All tagged images in the repository will be pulled. Note: When using the all-tags flag, Podman will not iterate over the search registries in the containers-registries.conf(5) but will always use docker.io for unqualified image names. -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. @@ -62,44 +62,44 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--cert-dir**=*path* +#### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) -**--creds**=*[username[:password]]* +#### **--creds**=*[username[:password]]* The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. -**--disable-content-trust** +#### **--disable-content-trust** This is a Docker specific option to disable image verification to a Docker registry and is not supported by Podman. This flag is a NOOP and provided solely for scripting compatibility. -**--override-arch**=*ARCH* +#### **--override-arch**=*ARCH* Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. -**--override-os**=*OS* +#### **--override-os**=*OS* Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. -**--override-variant**=*VARIANT* +#### **--override-variant**=*VARIANT* Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. -**--quiet**, **-q** +#### **--quiet**, **-q** Suppress output information when pulling images -**--tls-verify**=*true|false* +#### **--tls-verify**=*true|false* Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified, TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf. -**--help**, **-h** +#### **--help**, **-h** Print usage statement @@ -120,6 +120,17 @@ Storing signatures ``` ``` +$ podman pull alpine@sha256:d7342993700f8cd7aba8496c2d0e57be0666e80b4c441925fc6f9361fa81d10e +Trying to pull docker.io/library/alpine@sha256:d7342993700f8cd7aba8496c2d0e57be0666e80b4c441925fc6f9361fa81d10e... +Getting image source signatures +Copying blob 188c0c94c7c5 done +Copying config d6e46aa247 done +Writing manifest to image destination +Storing signatures +d6e46aa2470df1d32034c6707c8041158b652f38d2a9ae3d7ad7e7532d22ebe0 +``` + +``` $ podman pull --authfile temp-auths/myauths.json docker://docker.io/umohnani/finaltest Trying to pull docker.io/umohnani/finaltest:latest...Getting image source signatures Copying blob sha256:6d987f6f42797d81a318c40d442369ba3dc124883a0964d40b0c8f4f7561d913 diff --git a/docs/source/markdown/podman-push.1.md b/docs/source/markdown/podman-push.1.md index e9b63dc43..87e64858c 100644 --- a/docs/source/markdown/podman-push.1.md +++ b/docs/source/markdown/podman-push.1.md @@ -43,7 +43,7 @@ Images are pushed from those stored in local image storage. ## OPTIONS -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. @@ -51,50 +51,50 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--creds**=*[username[:password]]* +#### **--creds**=*[username[:password]]* The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. -**--cert-dir**=*path* +#### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) -**--compress** +#### **--compress** Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type, compressed or uncompressed, as source) Note: This flag can only be set when using the **dir** transport -**--digestfile** *Digestfile* +#### **--digestfile** *Digestfile* After copying the image, write the digest of the resulting image to the file. (Not available for remote commands) -**--disable-content-trust** +#### **--disable-content-trust** This is a Docker specific option to disable image verification to a Docker registry and is not supported by Podman. This flag is a NOOP and provided solely for scripting compatibility. -**--format**, **-f**=*format* +#### **--format**, **-f**=*format* Manifest Type (oci, v2s1, or v2s2) to use when pushing an image to a directory using the 'dir:' transport (default is manifest type of source) Note: This flag can only be set when using the **dir** transport -**--quiet**, **-q** +#### **--quiet**, **-q** When writing the output image, suppress progress output -**--remove-signatures** +#### **--remove-signatures** Discard any pre-existing signatures in the image -**--sign-by**=*key* +#### **--sign-by**=*key* Add a signature at the destination using the specified key -**--tls-verify**=*true|false* +#### **--tls-verify**=*true|false* Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified, diff --git a/docs/source/markdown/podman-remote.1.md b/docs/source/markdown/podman-remote.1.md index b621c846a..1a6c7d3cc 100644 --- a/docs/source/markdown/podman-remote.1.md +++ b/docs/source/markdown/podman-remote.1.md @@ -25,15 +25,15 @@ The `containers.conf` file should be placed under `$HOME/.config/containers/cont ## GLOBAL OPTIONS -**--connection**=*name*, **-c** +#### **--connection**=*name*, **-c** Remote connection name -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--identity**=*path* +#### **--identity**=*path* Path to ssh identity file. If the identity file has been encrypted, Podman prompts the user for the passphrase. If no identity file is provided and no user is given, Podman defaults to the user running the podman command. @@ -44,11 +44,11 @@ Identity value resolution precedence: - environment variable `CONTAINER_SSHKEY`, if `CONTAINER_HOST` is found - `containers.conf` -**--log-level**=*level* +#### **--log-level**=*level* Log messages above specified level: debug, info, warn, error (default), fatal or panic -**--url**=*value* +#### **--url**=*value* URL to access Podman service (default from `containers.conf`, rootless "unix://run/user/$UID/podman/podman.sock" or as root "unix://run/podman/podman.sock). @@ -67,7 +67,7 @@ URL value resolution precedence: - `containers.conf` - `unix://run/podman/podman.sock` -**--version** +#### **--version** Print the version diff --git a/docs/source/markdown/podman-restart.1.md b/docs/source/markdown/podman-restart.1.md index 127aaa074..60c90ada1 100644 --- a/docs/source/markdown/podman-restart.1.md +++ b/docs/source/markdown/podman-restart.1.md @@ -14,19 +14,19 @@ 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** +#### **--all**, **-a** Restart all containers regardless of their current state. -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**--running** +#### **--running** Restart all containers that are already in the *running* state. -**-t**, **--time**=*time* +#### **-t**, **--time**=*time* Timeout to wait before forcibly stopping the container. diff --git a/docs/source/markdown/podman-rm.1.md b/docs/source/markdown/podman-rm.1.md index 36904a128..cba9a0b49 100644 --- a/docs/source/markdown/podman-rm.1.md +++ b/docs/source/markdown/podman-rm.1.md @@ -14,15 +14,15 @@ Running or unusable containers will not be removed without the **-f** option. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Remove all containers. Can be used in conjunction with **-f** as well. -**--cidfile** +#### **--cidfile** Read container ID from the specified file and remove the container. Can be specified multiple times. -**--force**, **-f** +#### **--force**, **-f** Force the removal of running and paused containers. Forcing a container removal also removes containers from container storage even if the container is not known to podman. @@ -30,20 +30,20 @@ Containers could have been created by a different container engine. In addition, forcing can be used to remove unusable containers, e.g. containers whose OCI runtime has become unavailable. -**--ignore**, **-i** +#### **--ignore**, **-i** Ignore errors when specified containers are not in the container store. A user might have decided to manually remove a container which would lead to a failure during the ExecStop directive of a systemd service referencing that container. -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**--volumes**, **-v** +#### **--volumes**, **-v** Remove anonymous volumes associated with the container. This does not include named volumes created with **podman volume create**, or the **--volume** option of **podman run** and **podman create**. diff --git a/docs/source/markdown/podman-rmi.1.md b/docs/source/markdown/podman-rmi.1.md index 27fe3b235..765c1bd6d 100644 --- a/docs/source/markdown/podman-rmi.1.md +++ b/docs/source/markdown/podman-rmi.1.md @@ -13,11 +13,11 @@ Removes one or more locally stored images. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Remove all images in the local storage. -**--force**, **-f** +#### **--force**, **-f** This option will cause podman to remove all containers that are using the image before removing the image from the system. diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 0166a344a..f67b7c652 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -34,17 +34,17 @@ When running from a user defined network namespace, the _/etc/netns/NSNAME/resol will be used if it exists, otherwise _/etc/resolv.conf_ will be used. ## OPTIONS -**--add-host**=_host_:_ip_ +#### **--add-host**=_host_:_ip_ Add a line to container's _/etc/hosts_ for custom host-to-IP mapping. This option can be set multiple times. -**--annotation**=_key_=_value_ +#### **--annotation**=_key_=_value_ Add an annotation to the container. This option can be set multiple times. -**--attach**, **-a**=**stdin**|**stdout**|**stderr** +#### **--attach**, **-a**=**stdin**|**stdout**|**stderr** Attach to STDIN, STDOUT or STDERR. @@ -55,30 +55,30 @@ error. It can even pretend to be a TTY (this is what most commandline executables expect) and pass along signals. The **-a** option can be set for each of **stdin**, **stdout**, and **stderr**. -**--authfile**[=*path*] +#### **--authfile**[=*path*] Path to the authentication file. Default is *${XDG_RUNTIME_DIR}/containers/auth.json*. Note: You can also override the default path of the authentication file by setting the **REGISTRY_AUTH_FILE** environment variable. -**--blkio-weight**=*weight* +#### **--blkio-weight**=*weight* Block IO relative weight. The _weight_ is a value between **10** and **1000**. -**--blkio-weight-device**=*device*:*weight* +#### **--blkio-weight-device**=*device*:*weight* Block IO relative device weight. -**--cap-add**=*capability* +#### **--cap-add**=*capability* Add Linux capabilities. -**--cap-drop**=*capability* +#### **--cap-drop**=*capability* Drop Linux capabilities. -**--cgroupns**=*mode* +#### **--cgroupns**=*mode* Set the cgroup namespace mode for the container. @@ -89,7 +89,7 @@ Set the cgroup namespace mode for the container. If the host uses cgroups v1, the default is set to **host**. On cgroups v2, the default is **private**. -**--cgroups**=**enabled**|**disabled**|**no-conmon**|**split** +#### **--cgroups**=**enabled**|**disabled**|**no-conmon**|**split** Determines whether the container will create CGroups. @@ -100,23 +100,23 @@ The **disabled** option will force the container to not create CGroups, and thus The **no-conmon** option disables a new CGroup only for the **conmon** process. The **split** option splits the current cgroup in two sub-cgroups: one for conmon and one for the container payload. It is not possible to set **--cgroup-parent** with **split**. -**--cgroup-parent**=*path* +#### **--cgroup-parent**=*path* Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist. -**--cgroup-conf**=*KEY=VALUE* +#### **--cgroup-conf**=*KEY=VALUE* When running on cgroup v2, specify the cgroup file to write to and its value. For example **--cgroup-conf=memory.high=1073741824** sets the memory.high limit to 1GB. -**--cidfile**=*file* +#### **--cidfile**=*file* Write the container ID to *file*. -**--conmon-pidfile**=*file* +#### **--conmon-pidfile**=*file* Write the pid of the **conmon** process to a file. As **conmon** runs in a separate process than Podman, this is necessary when using systemd to restart Podman containers. -**--cpu-period**=*limit* +#### **--cpu-period**=*limit* Set the CPU period for the Completely Fair Scheduler (CFS), which is a duration in microseconds. Once the container's CPU quota is used up, it will @@ -127,7 +127,7 @@ On some systems, changing the CPU limits may not be allowed for non-root users. For more details, see https://github.com/containers/podman/blob/master/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error -**--cpu-quota**=*limit* +#### **--cpu-quota**=*limit* Limit the CPU Completely Fair Scheduler (CFS) quota. @@ -140,13 +140,13 @@ On some systems, changing the CPU limits may not be allowed for non-root users. For more details, see https://github.com/containers/podman/blob/master/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error -**--cpu-rt-period**=*microseconds* +#### **--cpu-rt-period**=*microseconds* Limit the CPU real-time period in microseconds. Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify. -**--cpu-rt-runtime**=*microseconds* +#### **--cpu-rt-runtime**=*microseconds* Limit the CPU real-time runtime in microseconds. @@ -155,7 +155,7 @@ Period of 1,000,000us and Runtime of 950,000us means that this container could c The sum of all runtimes across containers cannot exceed the amount allotted to the parent cgroup. -**--cpu-shares**=*shares* +#### **--cpu-shares**=*shares* CPU shares (relative weight). @@ -190,30 +190,30 @@ division of CPU shares: | 101 | {C1} | 1 | 100% of CPU1 | | 102 | {C1} | 2 | 100% of CPU2 | -**--cpus**=*number* +#### **--cpus**=*number* Number of CPUs. The default is *0.0* which means no limit. This is shorthand for **--cpu-period** and **--cpu-quota**, so you may only set either -**--cpus** or **--cpu-period** and **--cpu-quota**. +#### **--cpus** or **--cpu-period** and **--cpu-quota**. On some systems, changing the CPU limits may not be allowed for non-root users. For more details, see https://github.com/containers/podman/blob/master/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error -**--cpuset-cpus**=*number* +#### **--cpuset-cpus**=*number* CPUs in which to allow execution. Can be specified as a comma-separated list (e.g. **0,1**), as a range (e.g. **0-3**), or any combination thereof (e.g. **0-3,7,11-15**). -**--cpuset-mems**=*nodes* +#### **--cpuset-mems**=*nodes* Memory nodes (MEMs) in which to allow execution. Only effective on NUMA systems. For example, if you have four memory nodes (0-3) on your system, use **--cpuset-mems=0,1** to only use memory from the first two memory nodes. -**--detach**, **-d**=**true**|**false** +#### **--detach**, **-d**=**true**|**false** Detached mode: run the container in the background and print the new container ID. The default is *false*. @@ -226,7 +226,7 @@ running) using a configurable key sequence. The default sequence is `ctrl-p,ctrl Configure the keys sequence using the **--detach-keys** option, or specifying it in the **containers.conf** file: see **containers.conf(5)** for more information. -**--detach-keys**=*sequence* +#### **--detach-keys**=*sequence* Specify the key sequence for detaching a container. Format is a single character `[a-Z]` or one or more `ctrl-<value>` characters where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. Specifying "" will disable this feature. The default is *ctrl-p,ctrl-q*. @@ -234,7 +234,7 @@ This option can also be set in **containers.conf**(5) file. Specifying "" will disable this feature. The default is **ctrl-p,ctrl-q**. -**--device**=_host-device_[**:**_container-device_][**:**_permissions_] +#### **--device**=_host-device_[**:**_container-device_][**:**_permissions_] Add a host device to the container. Optional *permissions* parameter can be used to specify device permissions, it is combination of @@ -253,33 +253,33 @@ Podman may load kernel modules required for using the specified device. The devices that podman will load modules when necessary are: /dev/fuse. -**--device-cgroup-rule**=rule +#### **--device-cgroup-rule**=rule Add a rule to the cgroup allowed devices list -**--device-read-bps**=_path_:_rate_ +#### **--device-read-bps**=_path_:_rate_ Limit read rate (in bytes per second) from a device (e.g. **--device-read-bps=/dev/sda:1mb**). -**--device-read-iops**=_path_:_rate_ +#### **--device-read-iops**=_path_:_rate_ Limit read rate (in IO operations per second) from a device (e.g. **--device-read-iops=/dev/sda:1000**). -**--device-write-bps**=_path_:_rate_ +#### **--device-write-bps**=_path_:_rate_ Limit write rate (in bytes per second) to a device (e.g. **--device-write-bps=/dev/sda:1mb**). -**--device-write-iops**=_path_:_rate_ +#### **--device-write-iops**=_path_:_rate_ Limit write rate (in IO operations per second) to a device (e.g. **--device-write-iops=/dev/sda:1000**). -**--disable-content-trust** +#### **--disable-content-trust** This is a Docker specific option to disable image verification to a Docker registry and is not supported by Podman. This flag is a NOOP and provided solely for scripting compatibility. -**--dns**=*ipaddr* +#### **--dns**=*ipaddr* Set custom DNS servers. Invalid if using **--dns** with **--network** that is set to **none** or **container:**_id_. @@ -291,16 +291,16 @@ is the case the **--dns** flags is necessary for every run. The special value **none** can be specified to disable creation of _/etc/resolv.conf_ in the container by Podman. The _/etc/resolv.conf_ file in the image will be used without changes. -**--dns-opt**=*option* +#### **--dns-opt**=*option* Set custom DNS options. Invalid if using **--dns-opt** with **--network** that is set to **none** or **container:**_id_. -**--dns-search**=*domain* +#### **--dns-search**=*domain* Set custom DNS search domains. Invalid if using **--dns-search** and **--network** that is set to **none** or **container:**_id_. Use **--dns-search=.** if you don't wish to set the search domain. -**--entrypoint**=*"command"* | *'["command", "arg1", ...]'* +#### **--entrypoint**=*"command"* | *'["command", "arg1", ...]'* Overwrite the default ENTRYPOINT of the image. @@ -318,7 +318,7 @@ ENTRYPOINT. You need to specify multi option commands in the form of a json string. -**--env**, **-e**=*env* +#### **--env**, **-e**=*env* Set environment variables. @@ -326,30 +326,30 @@ This option allows arbitrary environment variables that are available for the pr See [**Environment**](#environment) note below for precedence and examples. -**--env-host**=**true**|**false** +#### **--env-host**=**true**|**false** Use host environment inside of the container. See **Environment** note below for precedence. (Not available for remote commands) -**--env-file**=*file* +#### **--env-file**=*file* Read in a line delimited file of environment variables. See **Environment** note below for precedence. -**--expose**=*port* +#### **--expose**=*port* Expose a port, or a range of ports (e.g. **--expose=3300-3310**) to set up port redirection on the host system. -**--gidmap**=*container_gid*:*host_gid*:*amount* +#### **--gidmap**=*container_gid*:*host_gid*:*amount* Run the container in a new user namespace using the supplied mapping. This option conflicts with the **--userns** and **--subgidname** flags. This option can be passed several times to map different ranges. If calling **podman run** as an unprivileged user, the user needs to have the right to use the mapping. See **subuid**(5). The example maps gids **0-1999** in the container to the gids **30000-31999** on the host: **--gidmap=0:30000:2000**. -**--group-add**=*group* +#### **--group-add**=*group* Add additional groups to run as -**--health-cmd**=*"command"* | *'["command", "arg1", ...]'* +#### **--health-cmd**=*"command"* | *'["command", "arg1", ...]'* Set or alter a healthcheck command for a container. The command is a command to be executed inside your container that determines your container health. The command is required for other healthcheck options @@ -358,35 +358,35 @@ to be applied. A value of **none** disables existing healthchecks. Multiple options can be passed in the form of a JSON array; otherwise, the command will be interpreted as an argument to **/bin/sh -c**. -**--health-interval**=*interval* +#### **--health-interval**=*interval* Set an interval for the healthchecks. An _interval_ of **disable** results in no automatic timer setup. The default is **30s**. -**--health-retries**=*retries* +#### **--health-retries**=*retries* The number of retries allowed before a healthcheck is considered to be unhealthy. The default value is **3**. -**--health-start-period**=*period* +#### **--health-start-period**=*period* The initialization time needed for a container to bootstrap. The value can be expressed in time format like **2m3s**. The default value is **0s**. -**--health-timeout**=*timeout* +#### **--health-timeout**=*timeout* The maximum time allowed to complete the healthcheck before an interval is considered failed. Like start-period, the value can be expressed in a time format such as **1m22s**. The default value is **30s**. -**--help** +#### **--help** Print usage statement -**-h**, **--hostname**=*name* +#### **-h**, **--hostname**=*name* Container host name Sets the container host name that is available inside the container. Can only be used with a private UTS namespace `--uts=private` (default). If `--pod` is specified and the pod shares the UTS namespace (default) the pods hostname will be used. -**--http-proxy**=**true**|**false** +#### **--http-proxy**=**true**|**false** By default proxy environment variables are passed into the container if set for the Podman process. This can be disabled by setting the value to **false**. @@ -401,7 +401,7 @@ proxy environment at container build time.) (Not available for remote commands) Defaults to **true**. -**--image-volume**, **builtin-volume**=**bind**|**tmpfs**|**ignore** +#### **--image-volume**, **builtin-volume**=**bind**|**tmpfs**|**ignore** Tells Podman how to handle the builtin image volumes. Default is **bind**. @@ -410,30 +410,30 @@ Tells Podman how to handle the builtin image volumes. Default is **bind**. content that disappears when the container is stopped. - **ignore**: All volumes are just ignored and no action is taken. -**--init** +#### **--init** Run an init inside the container that forwards signals and reaps processes. -**--init-path**=*path* +#### **--init-path**=*path* Path to the container-init binary. -**--interactive**, **-i**=**true**|**false** +#### **--interactive**, **-i**=**true**|**false** When set to **true**, keep stdin open even if not attached. The default is **false**. -**--ip6**=*ip* +#### **--ip6**=*ip* Not implemented. -**--ip**=*ip* +#### **--ip**=*ip* Specify a static IP address for the container, for example **10.88.64.128**. This option can only be used if the container is joined to only a single network - i.e., `--network=_network-name_` is used at most once and if the container is not joining another container's network namespace via `--network=container:_id_`. The address must be within the CNI network's IP address pool (default **10.88.0.0/16**). -**--ipc**=*mode* +#### **--ipc**=*mode* Set the IPC namespace mode for a container. The default is to create a private IPC namespace. @@ -442,7 +442,7 @@ a private IPC namespace. - **host**: use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. - **ns:**_path_: path to an IPC namespace to join. -**--kernel-memory**=_number_[_unit_] +#### **--kernel-memory**=_number_[_unit_] Kernel memory limit. A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes). @@ -452,23 +452,23 @@ is not limited. If you specify a limit, it may be rounded up to a multiple of the operating system's page size and the value can be very large, millions of trillions. -**--label**, **-l**=*key*=*value* +#### **--label**, **-l**=*key*=*value* Add metadata to a container. -**--label-file**=*file* +#### **--label-file**=*file* Read in a line-delimited file of labels. -**--link-local-ip**=*ip* +#### **--link-local-ip**=*ip* Not implemented. -**--log-driver**="*driver*" +#### **--log-driver**="*driver*" Logging driver for the container. Currently available options are **k8s-file**, **journald**, and **none**, with **json-file** aliased to **k8s-file** for scripting compatibility. -**--log-opt**=*name*=*value* +#### **--log-opt**=*name*=*value* Logging driver specific options. @@ -485,7 +485,7 @@ Set custom logging configuration. The following *name*s are supported: This option is currently supported only by the **journald** log driver. -**--mac-address**=*address* +#### **--mac-address**=*address* Container MAC address (e.g. **92:d0:c6:0a:29:33**). @@ -493,7 +493,7 @@ Remember that the MAC address in an Ethernet network must be unique. The IPv6 link-local address will be based on the device's MAC address according to RFC4862. -**--memory**, **-m**=_number_[_unit_] +#### **--memory**, **-m**=_number_[_unit_] Memory limit. A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes). @@ -503,7 +503,7 @@ RAM. If a limit of 0 is specified (not using **-m**), the container's memory is not limited. The actual limit may be rounded up to a multiple of the operating system's page size (the value would be very large, that's millions of trillions). -**--memory-reservation**=_number_[_unit_] +#### **--memory-reservation**=_number_[_unit_] Memory soft limit. A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes). @@ -513,7 +513,7 @@ reservation. So you should always set the value below **--memory**, otherwise th hard limit will take precedence. By default, memory reservation will be the same as memory limit. -**--memory-swap**=_number_[_unit_] +#### **--memory-swap**=_number_[_unit_] A limit value equal to memory plus swap. A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes). @@ -525,11 +525,11 @@ the value of **--memory**. Set _number_ to **-1** to enable unlimited swap. -**--memory-swappiness**=*number* +#### **--memory-swappiness**=*number* Tune a container's memory swappiness behavior. Accepts an integer between *0* and *100*. -**--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]* +#### **--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]* Attach a filesystem mount to the container @@ -585,7 +585,7 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · notmpcopyup: Disable copying files from the image to the tmpfs. -**--name**=*name* +#### **--name**=*name* Assign a name to the container. @@ -600,7 +600,7 @@ to the container with **--name** then it will generate a random string name. The name is useful any place you need to identify a container. This works for both background and foreground containers. -**--network**, **--net**=*mode* +#### **--network**, **--net**=*mode* Set the network mode for the container. Invalid if using **--dns**, **--dns-opt**, or **--dns-search** with **--network** that is set to **none** or **container:**_id_. @@ -624,40 +624,40 @@ Valid _mode_ values are: - **port_handler=rootlesskit**: Use rootlesskit for port forwarding. Default. - **port_handler=slirp4netns**: Use the slirp4netns port forwarding. -**--network-alias**=*alias* +#### **--network-alias**=*alias* -Not implemented. +Add network-scoped alias for the container -**--no-healthcheck**=*true|false* +#### **--no-healthcheck**=*true|false* Disable any defined healthchecks for container. -**--no-hosts**=**true**|**false** +#### **--no-hosts**=**true**|**false** Do not create _/etc/hosts_ for the container. By default, Podman will manage _/etc/hosts_, adding the container's own IP address and any hosts from **--add-host**. -**--no-hosts** disables this, and the image's _/etc/hosts_ will be preserved unmodified. +#### **--no-hosts** disables this, and the image's _/etc/hosts_ will be preserved unmodified. This option conflicts with **--add-host**. -**--oom-kill-disable**=**true**|**false** +#### **--oom-kill-disable**=**true**|**false** Whether to disable OOM Killer for the container or not. -**--oom-score-adj**=*num* +#### **--oom-score-adj**=*num* Tune the host's OOM preferences for containers (accepts values from **-1000** to **1000**). -**--override-arch**=*ARCH* +#### **--override-arch**=*ARCH* Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. -**--override-os**=*OS* +#### **--override-os**=*OS* Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. -**--override-variant**=*VARIANT* +#### **--override-variant**=*VARIANT* Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. -**--pid**=*mode* +#### **--pid**=*mode* Set the PID namespace mode for the container. The efault is to create a private PID namespace for the container. @@ -667,25 +667,25 @@ The efault is to create a private PID namespace for the container. - **private**: create a new namespace for the container (default) - **ns:**_path_: join the specified PID namespace. -**--pids-limit**=*limit* +#### **--pids-limit**=*limit* Tune the container's pids limit. Set to **0** to have unlimited pids for the container. The default is **4096** on systems that support "pids" cgroup controller. -**--pod**=*name* +#### **--pod**=*name* Run container in an existing pod. If you want Podman to make the pod for you, prefix the pod name with **new:**. To make a pod with more granular options, use the **podman pod create** command before creating a container. If a container is run with a pod, and the pod has an infra-container, the infra-container will be started before the container is. -**--pod-id-file**=*path* +#### **--pod-id-file**=*path* Run container in an existing pod and read the pod's ID from the specified file. If a container is run within a pod, and the pod has an infra-container, the infra-container will be started before the container is. -**--preserve-fds**=*N* +#### **--preserve-fds**=*N* Pass down to the process N additional file descriptors (in addition to 0, 1, 2). The total FDs will be 3+N. -**--privileged**=**true**|**false** +#### **--privileged**=**true**|**false** Give extended privileges to this container. The default is **false**. @@ -700,7 +700,7 @@ points, Apparmor/SELinux separation, and Seccomp filters are all disabled. Rootless containers cannot have more privileges than the account that launched them. -**--publish**, **-p**=_ip_:_hostPort_:_containerPort_ | _ip_::_containerPort_ | _hostPort_:_containerPort_ | _containerPort_ +#### **--publish**, **-p**=_ip_:_hostPort_:_containerPort_ | _ip_::_containerPort_ | _hostPort_:_containerPort_ | _containerPort_ Publish a container's port, or range of ports, to the host. @@ -723,7 +723,7 @@ associated ports. If one container binds to a port, no other container can use t within the pod while it is in use. Containers in the pod can also communicate over localhost by having one container bind to localhost in the pod, and another connect to that port. -**--publish-all**, **-P**=**true**|**false** +#### **--publish-all**, **-P**=**true**|**false** Publish all exposed ports to random ports on the host interfaces. The default is **false**. @@ -736,7 +736,7 @@ When using this option, Podman will bind any exposed port to a random port on th within an ephemeral port range defined by */proc/sys/net/ipv4/ip_local_port_range*. To find the mapping between the host ports and the exposed ports, use **podman port**. -**--pull**=**always**|**missing**|**never** +#### **--pull**=**always**|**missing**|**never** Pull image before running. The default is **missing**. @@ -744,11 +744,11 @@ Pull image before running. The default is **missing**. - **always**: Pull the image from the first registry it is found in as listed in registries.conf. Raise an error if not found in the registries, even if the image is present locally. - **never**: do not pull the image from the registry, use only the local version. Raise an error if the image is not present locally. -**--quiet**, **-q** +#### **--quiet**, **-q** Suppress output information when pulling images -**--read-only**=**true**|**false** +#### **--read-only**=**true**|**false** Mount the container's root filesystem as read only. @@ -756,15 +756,15 @@ By default a container will have its root filesystem writable allowing processes to write files anywhere. By specifying the **--read-only** flag, the container will have its root filesystem mounted as read only prohibiting any writes. -**--read-only-tmpfs**=**true**|**false** +#### **--read-only-tmpfs**=**true**|**false** If container is running in **--read-only** mode, then mount a read-write tmpfs on _/run_, _/tmp_, and _/var/tmp_. The default is **true**. -**--replace**=**true**|**false** +#### **--replace**=**true**|**false** If another container with the same name already exists, replace and remove it. The default is **false**. -**--restart**=*policy* +#### **--restart**=*policy* Restart policy to follow when containers exit. Restart policy will not take effect if a container is stopped via the **podman kill** or **podman stop** commands. @@ -780,7 +780,7 @@ Please note that restart will not restart containers after a system reboot. If this functionality is required in your environment, you can invoke Podman from a **systemd.unit**(5) file, or create an init script for whichever init system is in use. To generate systemd unit files, please see **podman generate systemd**. -**--rm**=**true**|**false** +#### **--rm**=**true**|**false** Automatically remove the container when it exits. The default is **false**. @@ -788,12 +788,12 @@ Note that the container will not be removed when it could not be created or started successfully. This allows the user to inspect the container after failure. -**--rmi**=*true|false* +#### **--rmi**=*true|false* After exit of the container, remove the image unless another container is using it. The default is *false*. -**--rootfs** +#### **--rootfs** If specified, the first argument refers to an exploded container on the file system. @@ -803,7 +803,7 @@ of the container is assumed to be managed externally. Note: On **SELinux** systems, the rootfs needs the correct label, which is by default **unconfined_u:object_r:container_file_t**. -**--sdnotify**=**container**|**conmon**|**ignore** +#### **--sdnotify**=**container**|**conmon**|**ignore** Determines how to use the NOTIFY_SOCKET, as passed with systemd and Type=notify. @@ -814,13 +814,13 @@ has started. The socket is never passed to the runtime or the container. The **ignore** option removes NOTIFY_SOCKET from the environment for itself and child processes, for the case where some other process above Podman uses NOTIFY_SOCKET and Podman should not use it. -**--seccomp-policy**=*policy* +#### **--seccomp-policy**=*policy* Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below. Note that this feature is experimental and may change in the future. -**--security-opt**=*option* +#### **--security-opt**=*option* Security Options @@ -840,37 +840,37 @@ Security Options Note: Labeling can be disabled for all containers by setting **label=false** in the **containers.conf**(5) file. -**--shm-size**=_number_[_unit_] +#### **--shm-size**=_number_[_unit_] Size of _/dev/shm_. A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the default is **64m**. When _size_ is **0**, there is no limit on the amount of memory used for IPC by the container. -**--sig-proxy**=**true**|**false** +#### **--sig-proxy**=**true**|**false** Sets whether the signals sent to the **podman run** command are proxied to the container process. SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is **true**. -**--stop-signal**=*signal* +#### **--stop-signal**=*signal* Signal to stop a container. Default is **SIGTERM**. -**--stop-timeout**=*seconds* +#### **--stop-timeout**=*seconds* Timeout to stop a container. Default is **10**. -**--subgidname**=*name* +#### **--subgidname**=*name* Run the container in a new user namespace using the map with _name_ in the _/etc/subgid_ file. If calling **podman run** as an unprivileged user, the user needs to have the right to use the mapping. See **subgid**(5). This flag conflicts with **--userns** and **--gidmap**. -**--subuidname**=*name* +#### **--subuidname**=*name* Run the container in a new user namespace using the map with _name_ in the _/etc/subuid_ file. If calling **podman run** as an unprivileged user, the user needs to have the right to use the mapping. See **subuid**(5). This flag conflicts with **--userns** and **--uidmap**. -**--sysctl**=_name_=_value_ +#### **--sysctl**=_name_=_value_ Configure namespaced kernel parameters at runtime. @@ -894,7 +894,7 @@ For the network namespace, the following ysctls areallowed: Note: if you use the **--network=host** option, these sysctls will not be allowed. -**--systemd**=**true**|**false**|**always** +#### **--systemd**=**true**|**false**|**always** Run container in systemd mode. The default is **true**. @@ -923,7 +923,7 @@ The **container_manage_cgroup** boolean must be enabled for this to be allowed o setsebool -P container_manage_cgroup true ``` -**--tmpfs**=*fs* +#### **--tmpfs**=*fs* Create a tmpfs mount. @@ -938,7 +938,7 @@ options are the same as the Linux default mount flags. If you do not specify any options, the systems uses the following options: **rw,noexec,nosuid,nodev**. -**--tty**, **-t**=**true**|**false** +#### **--tty**, **-t**=**true**|**false** Allocate a pseudo-TTY. The default is **false**. @@ -949,15 +949,15 @@ interactive shell. The default is **false**. **NOTE**: The **-t** option is incompatible with a redirection of the Podman client standard input. -**--tz**=*timezone* +#### **--tz**=*timezone* Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones. -**--umask**=*umask* +#### **--umask**=*umask* Set the umask inside the container. Defaults to `0022`. -**--uidmap**=*container_uid*:*host_uid*:*amount* +#### **--uidmap**=*container_uid*:*host_uid*:*amount* Run the container in a new user namespace using the supplied mapping. This option conflicts with the **--userns** and **--subuidname** flags. @@ -966,11 +966,11 @@ as an unprivileged user, the user needs to have the right to use the mapping. Se The following example maps uids 0-1999 in the container to the uids 30000-31999 on the host: **--uidmap=0:30000:2000**. -**--ulimit**=*option* +#### **--ulimit**=*option* Ulimit options. You can use **host** to copy the current configuration from the host. -**--user**, **-u**=[_user_ | _user_:_group_ | _uid_ | _uid_:_gid_ | _user_:_gid_ | _uid_:_group_ ] +#### **--user**, **-u**=[_user_ | _user_:_group_ | _uid_ | _uid_:_gid_ | _user_:_gid_ | _uid_:_group_ ] Sets the username or UID used and optionally the groupname or GID for the specified command. @@ -978,7 +978,7 @@ Without this argument, the command will run as the user specified in the contain When a user namespace is not in use, the UID and GID used within the container and on the host will match. When user namespaces are in use, however, the UID and GID in the container may correspond to another UID and GID on the host. In rootless containers, for example, a user namespace is always used, and root in the container will by default correspond to the UID and GID of the user invoking Podman. -**--userns**=**auto**|**host**|**keep-id**|**container:**_id_|**ns:**_namespace_ +#### **--userns**=**auto**|**host**|**keep-id**|**container:**_id_|**ns:**_namespace_ Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value ("") means user namespaces are disabled unless an explicit mapping is set with they `--uidmapping` and `--gidmapping` options. @@ -994,7 +994,7 @@ Set the user namespace mode for the container. It defaults to the **PODMAN_USER This option is incompatible with **--gidmap**, **--uidmap**, **--subuid** and **--subgid**. -**--uts**=*mode* +#### **--uts**=*mode* Set the UTS namespace mode for the container. The following values are supported: @@ -1003,7 +1003,7 @@ Set the UTS namespace mode for the container. The following values are supported - **ns:[path]**: run the container in the given existing UTS namespace. - **container:[container]**: join the UTS namespace of the specified container. -**--volume**, **-v**[=[[_source-volume_|_host-dir_:]_container-dir_[:_options_]]] +#### **--volume**, **-v**[=[[_source-volume_|_host-dir_:]_container-dir_[:_options_]]] Create a bind mount. If you specify _/host-dir_:_/container-dir_, Podman bind mounts _host-dir_ in the host to _container-dir_ in the Podman @@ -1141,7 +1141,7 @@ will convert /foo into a shared mount point. Alternatively, one can directly change propagation properties of source mount. Say, if _/_ is source mount for _/foo_, then use **mount --make-shared /** to convert _/_ into a shared mount. -**--volumes-from**[=*CONTAINER*[:*OPTIONS*]] +#### **--volumes-from**[=*CONTAINER*[:*OPTIONS*]] Mount volumes from the specified container(s). Used to share volumes between containers. The *options* is a comma delimited list with the following available elements: @@ -1174,7 +1174,7 @@ If the location of the volume from the source container overlaps with data residing on a target container, then the volume hides that data on the target. -**--workdir**, **-w**=*dir* +#### **--workdir**, **-w**=*dir* Working directory inside the container. @@ -1400,7 +1400,7 @@ $ podman run --security-opt label=level:TopSecret -i -t rhel7 bash ``` To disable the security labeling for this container versus running with the -**--permissive** flag, use the following command: +#### **--permissive** flag, use the following command: ``` $ podman run --security-opt label=disable -i -t fedora bash diff --git a/docs/source/markdown/podman-save.1.md b/docs/source/markdown/podman-save.1.md index f19c9723a..bfb52e7f8 100644 --- a/docs/source/markdown/podman-save.1.md +++ b/docs/source/markdown/podman-save.1.md @@ -22,16 +22,16 @@ Note: `:` is a restricted character and cannot be part of the file name. ## OPTIONS -**--compress** +#### **--compress** Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type, compressed or uncompressed, as source) Note: This flag can only be set when using the **dir** transport i.e --format=oci-dir or --format-docker-dir -**--output**, **-o**=*file* +#### **--output**, **-o**=*file* Write to a file, default is STDOUT -**--format**=*format* +#### **--format**=*format* Save image to **oci-archive, oci-dir** (directory with oci manifest type), or **docker-dir** (directory with v2s2 manifest type) ``` @@ -40,15 +40,15 @@ Save image to **oci-archive, oci-dir** (directory with oci manifest type), or ** --format docker-dir ``` -**--multi-image-archive**, **-m** +#### **--multi-image-archive**, **-m** Allow for creating archives with more than one image. Additional names will be interpreted as images instead of tags. Only supported for **docker-archive**. -**--quiet**, **-q** +#### **--quiet**, **-q** Suppress the output -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-search.1.md b/docs/source/markdown/podman-search.1.md index 15a38383a..ec610d3ba 100644 --- a/docs/source/markdown/podman-search.1.md +++ b/docs/source/markdown/podman-search.1.md @@ -25,14 +25,14 @@ Note, searching without a search term will only work for registries that impleme ## OPTIONS -**--authfile**=*path* +#### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` -**--filter**, **-f**=*filter* +#### **--filter**, **-f**=*filter* Filter output based on conditions provided (default []) @@ -42,7 +42,7 @@ Supported filters are: * is-automated (boolean - true | false) - is the image automated or not * is-official (boolean - true | false) - is the image official or not -**--format**=*format* +#### **--format**=*format* Change the output format to a Go template @@ -60,7 +60,7 @@ Valid placeholders for the Go template are listed below: Note: use .Tag only if the --list-tags is set. -**--limit**=*limit* +#### **--limit**=*limit* Limit the number of results (default 25). Note: The results from each registry will be limited to this value. @@ -68,24 +68,24 @@ Example if limit is 10 and two registries are being searched, the total number of results will be 20, 10 from each (if there are at least 10 matches in each). The order of the search results is the order in which the API endpoint returns the results. -**--list-tags** +#### **--list-tags** List the available tags in the repository for the specified image. **Note:** --list-tags requires the search term to be a fully specified image name. The result contains the Image name and its tag, one line for every tag associated with the image. -**--no-trunc** +#### **--no-trunc** Do not truncate the output -**--tls-verify**=*true|false* +#### **--tls-verify**=*true|false* Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, then TLS verification will be used. If set to false, then TLS verification will not be used if needed. If not specified, default registries will be searched through (in /etc/containers/registries.conf), and TLS will be skipped if a default registry is listed in the insecure registries. -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-start.1.md b/docs/source/markdown/podman-start.1.md index 84af9d800..4f8aa2b18 100644 --- a/docs/source/markdown/podman-start.1.md +++ b/docs/source/markdown/podman-start.1.md @@ -16,27 +16,27 @@ attach to the container. ## OPTIONS -**--attach**, **-a** +#### **--attach**, **-a** Attach container's STDOUT and STDERR. The default is false. This option cannot be used when starting multiple containers. -**--detach-keys**=*sequence* +#### **--detach-keys**=*sequence* Specify the key sequence for detaching a container. Format is a single character `[a-Z]` or one or more `ctrl-<value>` characters where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. Specifying "" will disable this feature. The default is *ctrl-p,ctrl-q*. -**--interactive**, **-i** +#### **--interactive**, **-i** Attach container's STDIN. The default is false. -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**--sig-proxy**=*true|false* +#### **--sig-proxy**=*true|false* Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is *true* when attaching, *false* otherwise. diff --git a/docs/source/markdown/podman-stats.1.md b/docs/source/markdown/podman-stats.1.md index 042da26d1..d5de8caf2 100644 --- a/docs/source/markdown/podman-stats.1.md +++ b/docs/source/markdown/podman-stats.1.md @@ -20,26 +20,26 @@ about their networking usage. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Show all containers. Only running containers are shown by default -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**--no-reset** +#### **--no-reset** Do not clear the terminal/screen in between reporting intervals -**--no-stream** +#### **--no-stream** Disable streaming stats and only pull the first result, default setting is false -**--format**=*template* +#### **--format**=*template* Pretty-print container statistics to JSON or using a Go template diff --git a/docs/source/markdown/podman-stop.1.md b/docs/source/markdown/podman-stop.1.md index 1534063a5..83570f50d 100644 --- a/docs/source/markdown/podman-stop.1.md +++ b/docs/source/markdown/podman-stop.1.md @@ -17,28 +17,28 @@ container and also via command line when creating the container. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Stop all running containers. This does not include paused containers. -**--cidfile** +#### **--cidfile** Read container ID from the specified file and remove the container. Can be specified multiple times. -**--ignore**, **-i** +#### **--ignore**, **-i** Ignore errors when specified containers are not in the container store. A user might have decided to manually remove a container which would lead to a failure during the ExecStop directive of a systemd service referencing that container. -**--latest**, **-l** +#### **--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. The latest option is not supported on the remote client. -**--time**, **-t**=*time* +#### **--time**, **-t**=*time* Time to wait before forcibly stopping the container diff --git a/docs/source/markdown/podman-system-connection-add.1.md b/docs/source/markdown/podman-system-connection-add.1.md index 5059803a2..c8c6476bf 100644 --- a/docs/source/markdown/podman-system-connection-add.1.md +++ b/docs/source/markdown/podman-system-connection-add.1.md @@ -15,21 +15,21 @@ The user will be prompted for the remote ssh login password or key file pass phr ## OPTIONS -**-d**, **--default**=*false* +#### **-d**, **--default**=*false* Make the new destination the default for this user. -**--identity**=*path* +#### **--identity**=*path* Path to ssh identity file. If the identity file has been encrypted, Podman prompts the user for the passphrase. If no identity file is provided and no user is given, Podman defaults to the user running the podman command. Podman prompts for the login password on the remote server. -**-p**, **--port**=*port* +#### **-p**, **--port**=*port* Port for ssh destination. The default value is `22`. -**--socket-path**=*path* +#### **--socket-path**=*path* Path to the Podman service unix domain socket on the ssh destination host diff --git a/docs/source/markdown/podman-system-df.1.md b/docs/source/markdown/podman-system-df.1.md index 57c02b8e1..6c21a20b4 100644 --- a/docs/source/markdown/podman-system-df.1.md +++ b/docs/source/markdown/podman-system-df.1.md @@ -10,11 +10,11 @@ podman\-system\-df - Show podman disk usage Show podman disk usage ## OPTIONS -**--format**=*format* +#### **--format**=*format* Pretty-print images using a Go template -**-v**, **--verbose**[=*true|false*] +#### **-v**, **--verbose**[=*true|false*] Show detailed information on space usage ## EXAMPLE diff --git a/docs/source/markdown/podman-system-migrate.1.md b/docs/source/markdown/podman-system-migrate.1.md index 29c0ef94b..913f119b0 100644 --- a/docs/source/markdown/podman-system-migrate.1.md +++ b/docs/source/markdown/podman-system-migrate.1.md @@ -26,7 +26,7 @@ newly configured mappings. ## OPTIONS -**--new-runtime**=*runtime* +#### **--new-runtime**=*runtime* Set a new OCI runtime for all containers. This can be used after a system upgrade which changes the default OCI runtime to move all containers to the new runtime. diff --git a/docs/source/markdown/podman-system-prune.1.md b/docs/source/markdown/podman-system-prune.1.md index 9c6ef5d8b..9a078648b 100644 --- a/docs/source/markdown/podman-system-prune.1.md +++ b/docs/source/markdown/podman-system-prune.1.md @@ -14,19 +14,19 @@ With the **--all** option, you can delete all unused images. Unused images are By default, volumes are not removed to prevent important data from being deleted if there is currently no container using the volume. Use the **--volumes** flag when running the command to prune volumes as well. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Remove all unused images not just dangling ones. -**--force**, **-f** +#### **--force**, **-f** Do not prompt for confirmation -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--volumes** +#### **--volumes** Prune volumes currently unused by any container diff --git a/docs/source/markdown/podman-system-reset.1.md b/docs/source/markdown/podman-system-reset.1.md index 3294bac9b..744f917df 100644 --- a/docs/source/markdown/podman-system-reset.1.md +++ b/docs/source/markdown/podman-system-reset.1.md @@ -7,19 +7,43 @@ podman\-system\-reset - Reset storage back to initial state **podman system reset** [*options*] ## DESCRIPTION -**podman system reset** removes all pods, containers, images and volumes. Must be run after changing any of the following values in the `containers.conf` file: `static_dir`, `tmp_dir` or `volume_path`. +**podman system reset** removes all pods, containers, images and volumes. + +This command must be run **before** changing any of the following fields in the +`containers.conf` or `storage.conf` files: `driver`, `static_dir`, `tmp_dir` +or `volume_path`. + +`podman system reset` reads the current configuration and attempts to remove all +of the relevant configurations. If the administrator modified the configuration files first, +`podman system reset` might not be able to clean up the previous storage. ## OPTIONS -**--force**, **-f** +#### **--force**, **-f** Do not prompt for confirmation -**--help**, **-h** +#### **--help**, **-h** Print usage statement +## EXAMPLES + +### Switching rootless user from VFS driver to overlay with fuse-overlayfs + +If the user ran rootless containers without having the `fuse-overlayfs` program +installed, podman defaults to the `vfs` storage in their home directory. If they +want to switch to use fuse-overlay, they must install the fuse-overlayfs +package. The user needs to reset the storage to use overlayfs by default. +Execute `podman system reset` as the user first to remove the VFS storage. Now +the user can edit the `/etc/containers/storage.conf` to make any changes if +necessary. If the system's default was already `overlay`, then no changes are +necessary to switch to fuse-overlayfs. Podman looks for the existence of +fuse-overlayfs to use it when set in the `overlay` driver, only falling back to vfs +if the program does not exist. Users can run `podman info` to ensure Podman is +using fuse-overlayfs and the overlay driver. + ## SEE ALSO -`podman(1)`, `podman-system(1)` +`podman(1)`, `podman-system(1)`, `fuse-overlayfs(1)`, `containers-storage.conf(5)` ## HISTORY November 2019, Originally compiled by Dan Walsh (dwalsh at redhat dot com) diff --git a/docs/source/markdown/podman-system-service.1.md b/docs/source/markdown/podman-system-service.1.md index 580630cdc..39e30ec02 100644 --- a/docs/source/markdown/podman-system-service.1.md +++ b/docs/source/markdown/podman-system-service.1.md @@ -19,12 +19,12 @@ Both APIs are versioned, but the server will not reject requests with an unsuppo ## OPTIONS -**--time**, **-t** +#### **--time**, **-t** The time until the session expires in _seconds_. The default is 5 seconds. A value of `0` means no timeout and the session will not expire. -**--help**, **-h** +#### **--help**, **-h** Print usage statement. diff --git a/docs/source/markdown/podman-tag.1.md b/docs/source/markdown/podman-tag.1.md index 064ea401d..7eab62028 100644 --- a/docs/source/markdown/podman-tag.1.md +++ b/docs/source/markdown/podman-tag.1.md @@ -16,7 +16,7 @@ provided, then podman will default to `latest` for both the *image* and the ## OPTIONS -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-top.1.md b/docs/source/markdown/podman-top.1.md index 6a04ab91a..f307f96da 100644 --- a/docs/source/markdown/podman-top.1.md +++ b/docs/source/markdown/podman-top.1.md @@ -13,11 +13,11 @@ Display the running processes of the container. The *format-descriptors* are ps ## OPTIONS -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--latest**, **-l** +#### **--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. diff --git a/docs/source/markdown/podman-unmount.1.md b/docs/source/markdown/podman-unmount.1.md index 08d1286ab..97780111a 100644 --- a/docs/source/markdown/podman-unmount.1.md +++ b/docs/source/markdown/podman-unmount.1.md @@ -27,11 +27,11 @@ External containers are containers created in container/storage by other tools l Buildah and CRI-O. ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** All of the currently mounted containers will be unmounted. -**--force**, **-f** +#### **--force**, **-f** Force the unmounting of specified containers' root file system, even if other processes have mounted it. @@ -39,7 +39,7 @@ processes have mounted it. Note: This could cause other processes that are using the file system to fail, as the mount point could be removed without their knowledge. -**--latest**, **-l** +#### **--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 diff --git a/docs/source/markdown/podman-unpause.1.md b/docs/source/markdown/podman-unpause.1.md index f5538d6d5..ae178647a 100644 --- a/docs/source/markdown/podman-unpause.1.md +++ b/docs/source/markdown/podman-unpause.1.md @@ -13,7 +13,7 @@ Unpauses the processes in one or more containers. You may use container IDs or ## OPTIONS -**--all**, **-a** +#### **--all**, **-a** Unpause all paused containers. diff --git a/docs/source/markdown/podman-untag.1.md b/docs/source/markdown/podman-untag.1.md index d6ed7f3ea..70053c940 100644 --- a/docs/source/markdown/podman-untag.1.md +++ b/docs/source/markdown/podman-untag.1.md @@ -13,7 +13,7 @@ Remove one or more names from an image in the local storage. The image can be r ## OPTIONS -**--help**, **-h** +#### **--help**, **-h** Print usage statement diff --git a/docs/source/markdown/podman-version.1.md b/docs/source/markdown/podman-version.1.md index 185e8e296..a54e66372 100644 --- a/docs/source/markdown/podman-version.1.md +++ b/docs/source/markdown/podman-version.1.md @@ -12,11 +12,11 @@ OS, and Architecture. ## OPTIONS -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--format**, **-f**=*format* +#### **--format**, **-f**=*format* Change output format to "json" or a Go template. diff --git a/docs/source/markdown/podman-volume-create.1.md b/docs/source/markdown/podman-volume-create.1.md index 5672a80a5..4fd911c1f 100644 --- a/docs/source/markdown/podman-volume-create.1.md +++ b/docs/source/markdown/podman-volume-create.1.md @@ -15,19 +15,19 @@ driver options can be set using the **--opt** flag. ## OPTIONS -**--driver**=*driver* +#### **--driver**=*driver* Specify the volume driver name (default local). -**--help** +#### **--help** Print usage statement -**-l**, **--label**=*label* +#### **-l**, **--label**=*label* Set metadata for a volume (e.g., --label mykey=value). -**-o**, **--opt**=*option* +#### **-o**, **--opt**=*option* Set driver specific options. For the default driver, `local`, this allows a volume to be configured to mount a filesystem on the host. diff --git a/docs/source/markdown/podman-volume-inspect.1.md b/docs/source/markdown/podman-volume-inspect.1.md index b889383b1..e6be69e73 100644 --- a/docs/source/markdown/podman-volume-inspect.1.md +++ b/docs/source/markdown/podman-volume-inspect.1.md @@ -16,15 +16,15 @@ Volumes can be queried individually by providing their full name or a unique par ## OPTIONS -**-a**, **--all** +#### **-a**, **--all** Inspect all volumes. -**-f**, **--format**=*format* +#### **-f**, **--format**=*format* Format volume output using Go template -**--help** +#### **--help** Print usage statement diff --git a/docs/source/markdown/podman-volume-ls.1.md b/docs/source/markdown/podman-volume-ls.1.md index a4fb925f8..a3f3ff9ba 100644 --- a/docs/source/markdown/podman-volume-ls.1.md +++ b/docs/source/markdown/podman-volume-ls.1.md @@ -14,19 +14,19 @@ flag. Use the **--quiet** flag to print only the volume names. ## OPTIONS -**-f**, **--filter**=*filter* +#### **-f**, **--filter**=*filter* Filter volume output. -**--format**=*format* +#### **--format**=*format* Format volume output using Go template. -**--help** +#### **--help** Print usage statement. -**-q**, **--quiet** +#### **-q**, **--quiet** Print volume output in quiet mode. Only print the volume names. diff --git a/docs/source/markdown/podman-volume-prune.1.md b/docs/source/markdown/podman-volume-prune.1.md index 25ea701a3..097dded86 100644 --- a/docs/source/markdown/podman-volume-prune.1.md +++ b/docs/source/markdown/podman-volume-prune.1.md @@ -14,11 +14,11 @@ unused volumes. To bypass the confirmation, use the **--force** flag. ## OPTIONS -**-f**, **--force** +#### **-f**, **--force** Do not prompt for confirmation. -**--help** +#### **--help** Print usage statement diff --git a/docs/source/markdown/podman-volume-rm.1.md b/docs/source/markdown/podman-volume-rm.1.md index ed4a83f9e..5f2137f73 100644 --- a/docs/source/markdown/podman-volume-rm.1.md +++ b/docs/source/markdown/podman-volume-rm.1.md @@ -15,16 +15,16 @@ Volumes can be removed individually by providing their full name or a unique par ## OPTIONS -**-a**, **--all** +#### **-a**, **--all** Remove all volumes. -**-f**, **--force** +#### **-f**, **--force** Remove a volume by force. If it is being used by containers, the containers will be removed first. -**--help** +#### **--help** Print usage statement diff --git a/docs/source/markdown/podman-wait.1.md b/docs/source/markdown/podman-wait.1.md index f0ccb1f9e..07e42ca6e 100644 --- a/docs/source/markdown/podman-wait.1.md +++ b/docs/source/markdown/podman-wait.1.md @@ -16,17 +16,17 @@ separated by newline in the same order as they were given to the command. ## OPTIONS -**--condition**=*state* +#### **--condition**=*state* Condition to wait on (default "stopped") -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--interval**, **-i**=*duration* +#### **--interval**, **-i**=*duration* Time interval to wait before polling for completion. A duration string is a sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". Time unit defaults to "ms". -**--latest**, **-l** +#### **--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. diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 2d5110ad9..993f285ed 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -21,31 +21,31 @@ created by the other. ## GLOBAL OPTIONS -**--cgroup-manager**=*manager* +#### **--cgroup-manager**=*manager* The CGroup manager to use for container cgroups. Supported values are cgroupfs or systemd. Default is systemd unless overridden in the containers.conf file. Note: Setting this flag can cause certain commands to break when called on containers previously created by the other CGroup manager type. Note: CGroup manager is not supported in rootless mode when using CGroups Version V1. -**--cni-config-dir** +#### **--cni-config-dir** Path of the configuration directory for CNI networks. (Default: `/etc/cni/net.d`) -**--connection**, **-c** +#### **--connection**, **-c** Connection to use for remote podman (Default connection is configured in `containers.conf`) -**--conmon** +#### **--conmon** Path of the conmon binary (Default path is configured in `containers.conf`) -**--events-backend**=*type* +#### **--events-backend**=*type* Backend to use for storing events. Allowed values are **file**, **journald**, and **none**. -**--help**, **-h** +#### **--help**, **-h** Print usage statement -**--hooks-dir**=*path* +#### **--hooks-dir**=*path* Each `*.json` file in the path configures a hook for Podman containers. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated. @@ -61,7 +61,7 @@ Podman and libpod currently support an additional `precreate` state which is cal **WARNING**: the `precreate` hook lets you do powerful things, such as adding additional mounts to the runtime configuration. That power also makes it easy to break things. Before reporting libpod errors, try running your container with `precreate` hooks disabled to see if the problem is due to one of your hooks. -**--identity**=*path* +#### **--identity**=*path* Path to ssh identity file. If the identity file has been encrypted, podman prompts the user for the passphrase. If no identity file is provided and no user is given, podman defaults to the user running the podman command. @@ -72,22 +72,22 @@ Identity value resolution precedence: - environment variable `CONTAINER_SSHKEY`, if `CONTAINER_HOST` is found - `containers.conf` -**--log-level**=*level* +#### **--log-level**=*level* Log messages above specified level: debug, info, warn, error (default), fatal or panic (default: "error") -**--namespace**=*namespace* +#### **--namespace**=*namespace* Set libpod namespace. Namespaces are used to separate groups of containers and pods in libpod's state. When namespace is set, created containers and pods will join the given namespace, and only containers and pods in the given namespace will be visible to Podman. -**--network-cmd-path**=*path* +#### **--network-cmd-path**=*path* Path to the command binary to use for setting up a network. It is currently only used for setting up a slirp4netns network. If "" is used then the binary is looked up using the $PATH environment variable. -**--remote**, **-r** +#### **--remote**, **-r** Access Podman service will be remote -**--url**=*value* +#### **--url**=*value* URL to access Podman service (default from `containers.conf`, rootless `unix://run/user/$UID/podman/podman.sock` or as root `unix://run/podman/podman.sock`). - `CONTAINER_HOST` is of the format `<schema>://[<user[:<password>]@]<host>[:<port>][<path>]` @@ -105,21 +105,21 @@ URL value resolution precedence: - `containers.conf` - `unix://run/podman/podman.sock` -**--root**=*value* +#### **--root**=*value* Storage root dir in which data, including images, is stored (default: "/var/lib/containers/storage" for UID 0, "$HOME/.local/share/containers/storage" for other users). Default root dir configured in `/etc/containers/storage.conf`. -**--runroot**=*value* +#### **--runroot**=*value* Storage state directory where all state information is stored (default: "/var/run/containers/storage" for UID 0, "/var/run/user/$UID/run" for other users). Default state dir configured in `/etc/containers/storage.conf`. -**--runtime**=*value* +#### **--runtime**=*value* 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* +#### **--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 @@ -129,30 +129,30 @@ 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**=*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. Overriding this option will cause the *storage-opt* settings in /etc/containers/storage.conf to be ignored. The user must specify additional options via the `--storage-opt` flag. -**--storage-opt**=*value* +#### **--storage-opt**=*value* Storage driver option, Default storage driver options are configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode). The `STORAGE_OPTS` environment variable overrides the default. The --storage-opt specified options overrides all. -**--syslog**=*true|false* +#### **--syslog**=*true|false* Output logging information to syslog as well as the console (default *false*). On remote clients, logging is directed to the file $HOME/.config/containers/podman.log. -**--tmpdir** +#### **--tmpdir** Path to the tmp directory, for libpod runtime content. NOTE --tmpdir is not used for the temporary storage of downloaded images. Use the environment variable `TMPDIR` to change the temporary storage location of downloaded container images. Podman defaults to use `/var/tmp`. -**--version**, **-v** +#### **--version**, **-v** Print the version @@ -11,13 +11,13 @@ require ( github.com/containernetworking/cni v0.8.0 github.com/containernetworking/plugins v0.8.7 github.com/containers/buildah v1.17.0 - github.com/containers/common v0.26.3 + github.com/containers/common v0.27.0 github.com/containers/conmon v2.0.20+incompatible github.com/containers/image/v5 v5.7.0 github.com/containers/psgo v1.5.1 github.com/containers/storage v1.23.9 github.com/coreos/go-systemd/v22 v22.1.0 - github.com/cri-o/ocicni v0.2.0 + github.com/cri-o/ocicni v0.2.1-0.20201102180012-75c612fda1a2 github.com/cyphar/filepath-securejoin v0.2.2 github.com/davecgh/go-spew v1.1.1 github.com/docker/distribution v2.7.1+incompatible @@ -48,7 +48,7 @@ require ( github.com/opentracing/opentracing-go v1.2.0 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 - github.com/rootless-containers/rootlesskit v0.11.0 + github.com/rootless-containers/rootlesskit v0.11.1 github.com/sirupsen/logrus v1.7.0 github.com/spf13/cobra v1.1.1 github.com/spf13/pflag v1.0.5 @@ -72,3 +72,5 @@ require ( k8s.io/apimachinery v0.19.3 k8s.io/client-go v0.0.0-20190620085101-78d2af792bab ) + +replace github.com/cri-o/ocicni => github.com/cri-o/ocicni v0.2.1-0.20201109200316-afdc16ba66df @@ -86,8 +86,8 @@ github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CY github.com/containers/buildah v1.17.0 h1:oaBIxKtW4kJ06vj4l0C9MZfFVapksf6F4qdQGOvZ2J4= github.com/containers/buildah v1.17.0/go.mod h1:E6nOiMnF3uCAY3wAQK5lPR6w89SRp8iyIkjUfDKW+Eg= github.com/containers/common v0.26.2/go.mod h1:igUeog5hx8rYhJk67rG6rGAh3zEcf0Uxuzm9KpXzo2E= -github.com/containers/common v0.26.3 h1:5Kb5fMmJ7/xMiJ+iEbPA+5pQpl/FGxCgJex4nml4Slo= -github.com/containers/common v0.26.3/go.mod h1:hJWZIlrl5MsE2ELNRa+MPp6I1kPbXHauuj0Ym4BsLG4= +github.com/containers/common v0.27.0 h1:+QlYEOitVYtU9/x8xebRgxdGqt4sLaIqV6MBOns+zLk= +github.com/containers/common v0.27.0/go.mod h1:ZTswJJfu4aGF6Anyi2yON8Getda9NDYcdIzurOEHHXI= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.7.0 h1:fiTC8/Xbr+zEP6njGTZtPW/3UD7MC93nC9DbUoWdxkA= @@ -119,8 +119,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cri-o/ocicni v0.2.0 h1:p0kO+/fcLTO574CcDwzAosFdP2U+NEL+a4wph3Bt85k= -github.com/cri-o/ocicni v0.2.0/go.mod h1:ZOuIEOp/3MB1eCBWANnNxM3zUA3NWh76wSRCsnKAg2c= +github.com/cri-o/ocicni v0.2.1-0.20201109200316-afdc16ba66df h1:c35uRFkER07nAkB1X21e+PI5xO21SOyI6G7tdfvz1z4= +github.com/cri-o/ocicni v0.2.1-0.20201109200316-afdc16ba66df/go.mod h1:vingr1ztOAzP2WyTgGbpMov9dFhbjNxdLtDv0+PhAvY= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= @@ -459,8 +459,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rootless-containers/rootlesskit v0.11.0 h1:Yn51y7RU6vE3oKrMv54qBCWDM3K6c5cmEtqc9j332D4= -github.com/rootless-containers/rootlesskit v0.11.0/go.mod h1:pCUqFJBGOIonbjQBaxSVnk3w3KnK2drqjllgpgvNnO8= +github.com/rootless-containers/rootlesskit v0.11.1 h1:c0ffwH/D7wU8+IphrvoLoQO3EQArMcdGxw40A5zkynk= +github.com/rootless-containers/rootlesskit v0.11.1/go.mod h1:pCUqFJBGOIonbjQBaxSVnk3w3KnK2drqjllgpgvNnO8= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 h1:2c1EFnZHIPCW8qKWgHMH/fX2PkSabFc5mrVzfUNdg5U= diff --git a/hack/podman-commands.sh b/hack/podman-commands.sh index 587cac782..fd4ff2501 100755 --- a/hack/podman-commands.sh +++ b/hack/podman-commands.sh @@ -23,7 +23,7 @@ function die() { # the command name but not its description. function podman_commands() { $PODMAN help "$@" |\ - awk '/^Available Commands:/{ok=1;next}/^Flags:/{ok=0}ok { print $1 }' |\ + awk '/^Available Commands:/{ok=1;next}/^Options:/{ok=0}ok { print $1 }' |\ grep . } diff --git a/hack/xref-helpmsgs-manpages b/hack/xref-helpmsgs-manpages index a7063259f..082cc63f2 100755 --- a/hack/xref-helpmsgs-manpages +++ b/hack/xref-helpmsgs-manpages @@ -248,7 +248,7 @@ sub podman_help { unless $subcommand eq 'help'; # 'help' not in man } } - elsif ($section eq 'flags') { + elsif ($section eq 'options') { # Handle '--foo' or '-f, --foo' if ($line =~ /^\s{1,10}(--\S+)\s/) { print "> podman @_ $1\n" if $debug; @@ -293,7 +293,7 @@ sub podman_man { elsif ($line =~ /^\#\#\s+(SUB)?COMMANDS/) { $section = 'commands'; } - elsif ($line =~ /^\#\#/) { + elsif ($line =~ /^\#\#[^#]/) { $section = ''; } @@ -329,12 +329,15 @@ sub podman_man { } @most_recent_flags = (); - # Handle any variation of '**--foo**, **-f**' - while ($line =~ s/^\*\*((--[a-z0-9-]+)|(-.))\*\*(,\s+)?//g) { - $man{$1} = 1; - - # Keep track of them, in case we see 'Not implemented' below - push @most_recent_flags, $1; + # As of PR #8292, all options are <h4> and anchored + if ($line =~ s/^\#{4}\s+//) { + # Handle any variation of '**--foo**, **-f**' + while ($line =~ s/^\*\*((--[a-z0-9-]+)|(-.))\*\*(,\s+)?//g) { + $man{$1} = 1; + + # Keep track of them, in case we see 'Not implemented' below + push @most_recent_flags, $1; + } } } } diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 0b9b353c7..be0adfe6a 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -94,7 +94,6 @@ func NewBoltState(path string, runtime *Runtime) (State, error) { volBkt, allVolsBkt, execBkt, - aliasesBkt, runtimeConfigBkt, } @@ -972,6 +971,58 @@ func (s *BoltState) AllContainers() ([]*Container, error) { return ctrs, nil } +// GetNetworks returns the CNI networks this container is a part of. +func (s *BoltState) GetNetworks(ctr *Container) ([]string, error) { + if !s.valid { + return nil, define.ErrDBClosed + } + + if !ctr.valid { + return nil, define.ErrCtrRemoved + } + + if s.namespace != "" && s.namespace != ctr.config.Namespace { + return nil, errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace) + } + + ctrID := []byte(ctr.ID()) + + db, err := s.getDBCon() + if err != nil { + return nil, err + } + defer s.deferredCloseDBCon(db) + + networks := []string{} + + err = db.View(func(tx *bolt.Tx) error { + ctrBucket, err := getCtrBucket(tx) + if err != nil { + return err + } + + dbCtr := ctrBucket.Bucket(ctrID) + if dbCtr == nil { + ctr.valid = false + return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID()) + } + + ctrNetworkBkt := dbCtr.Bucket(networksBkt) + if ctrNetworkBkt == nil { + return errors.Wrapf(define.ErrNoSuchNetwork, "container %s is not joined to any CNI networks", ctr.ID()) + } + + return ctrNetworkBkt.ForEach(func(network, v []byte) error { + networks = append(networks, string(network)) + return nil + }) + }) + if err != nil { + return nil, err + } + return networks, nil +} + // GetNetworkAliases retrieves the network aliases for the given container in // the given CNI network. func (s *BoltState) GetNetworkAliases(ctr *Container, network string) ([]string, error) { @@ -1032,7 +1083,8 @@ func (s *BoltState) GetNetworkAliases(ctr *Container, network string) ([]string, netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network)) if netAliasesBkt == nil { - return errors.Wrapf(define.ErrNoAliasesForNetwork, "container %s has no aliases for network %q", ctr.ID(), network) + // No aliases for this specific network. + return nil } return netAliasesBkt.ForEach(func(alias, v []byte) error { @@ -1120,10 +1172,9 @@ func (s *BoltState) GetAllNetworkAliases(ctr *Container) (map[string][]string, e return aliases, nil } -// SetNetworkAliases sets network aliases for the given container in the given -// network. All existing aliases for that network (if any exist) will be removed, -// to be replaced by the new aliases given. -func (s *BoltState) SetNetworkAliases(ctr *Container, network string, aliases []string) error { +// NetworkConnect adds the given container to the given network. If aliases are +// specified, those will be added to the given network. +func (s *BoltState) NetworkConnect(ctr *Container, network string, aliases []string) error { if !s.valid { return define.ErrDBClosed } @@ -1154,90 +1205,60 @@ func (s *BoltState) SetNetworkAliases(ctr *Container, network string, aliases [] return err } - allAliasesBucket, err := getAliasesBucket(tx) - if err != nil { - return err - } - - netAllAliasesBucket, err := allAliasesBucket.CreateBucketIfNotExists([]byte(network)) - if err != nil { - return errors.Wrapf(err, "error creating network aliases bucket for network %s", network) - } - dbCtr := ctrBucket.Bucket(ctrID) if dbCtr == nil { ctr.valid = false return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID()) } - ctrAliasesBkt := dbCtr.Bucket(aliasesBkt) - if ctrAliasesBkt == nil { - return errors.Wrapf(define.ErrNoAliases, "container %s has no network aliases", ctr.ID()) + ctrAliasesBkt, err := dbCtr.CreateBucketIfNotExists(aliasesBkt) + if err != nil { + return errors.Wrapf(err, "error creating aliases bucket for container %s", ctr.ID()) } ctrNetworksBkt := dbCtr.Bucket(networksBkt) if ctrNetworksBkt == nil { - return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to any CNI networks, so cannot add aliases", ctr.ID()) + ctrNetworksBkt, err = dbCtr.CreateBucket(networksBkt) + if err != nil { + return errors.Wrapf(err, "error creating networks bucket for container %s", ctr.ID()) + } + ctrNetworks := ctr.config.Networks + if len(ctrNetworks) == 0 { + ctrNetworks = []string{ctr.runtime.netPlugin.GetDefaultNetworkName()} + } + // Copy in all the container's CNI networks + for _, net := range ctrNetworks { + if err := ctrNetworksBkt.Put([]byte(net), ctrID); err != nil { + return errors.Wrapf(err, "error adding container %s network %s to DB", ctr.ID(), net) + } + } } netConnected := ctrNetworksBkt.Get([]byte(network)) - if netConnected == nil { - return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to CNI network %q, so cannot add aliases for this network", ctr.ID(), network) - } - - namesBucket, err := getNamesBucket(tx) - if err != nil { - return err + if netConnected != nil { + return errors.Wrapf(define.ErrNetworkExists, "container %s is already connected to CNI network %q", ctr.ID(), network) } - // Check if the container already has network aliases for this network. - netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network)) - if netAliasesBkt != nil { - // We have aliases. Have to remove them. - forEachErr := netAliasesBkt.ForEach(func(alias, v []byte) error { - // Relies on errors.Wrapf(nil, ...) returning - // nil. - return errors.Wrapf(netAllAliasesBucket.Delete(alias), "error removing alias %q from network %q when changing aliases for container %s", string(alias), network, ctr.ID()) - }) - if forEachErr != nil { - return forEachErr - } + // Add the network + if err := ctrNetworksBkt.Put([]byte(network), ctrID); err != nil { + return errors.Wrapf(err, "error adding container %s to network %s in DB", ctr.ID(), network) } - if netAliasesBkt == nil { - newBkt, err := ctrAliasesBkt.CreateBucket([]byte(network)) - if err != nil { - return errors.Wrapf(err, "could not create bucket for network aliases for network %q", network) - } - netAliasesBkt = newBkt + ctrNetAliasesBkt, err := ctrAliasesBkt.CreateBucketIfNotExists([]byte(network)) + if err != nil { + return errors.Wrapf(err, "error adding container %s network aliases bucket for network %s", ctr.ID(), network) } - for _, alias := range aliases { - // Check if safe to use - aliasExists := netAllAliasesBucket.Get([]byte(alias)) - if aliasExists != nil { - return errors.Wrapf(define.ErrAliasExists, "network alias %q already exists in network %q (used by container %s)", alias, network, string(aliasExists)) - } - nameExists := namesBucket.Get([]byte(alias)) - if nameExists != nil { - return errors.Wrapf(define.ErrCtrExists, "a container or pod already uses the name %q, cannot add network alias for container %s", alias, ctr.ID()) - } - - // Add alias - if err := netAliasesBkt.Put([]byte(alias), ctrID); err != nil { - return errors.Wrapf(err, "error adding container %s network %q alias %q to DB", ctr.ID(), network, alias) - } - if err := netAllAliasesBucket.Put([]byte(alias), ctrID); err != nil { - return errors.Wrapf(err, "error adding container %s network %q alias %q to all aliases in DB", ctr.ID(), network, alias) + if err := ctrNetAliasesBkt.Put([]byte(alias), ctrID); err != nil { + return errors.Wrapf(err, "error adding container %s network alias %s for network %s", ctr.ID(), alias, network) } } - return nil }) } -// RemoveNetworkAliases removes network aliases of the given container in the -// given network. -func (s *BoltState) RemoveNetworkAliases(ctr *Container, network string) error { +// NetworkDisconnect disconnects the container from the given network, also +// removing any aliases in the network. +func (s *BoltState) NetworkDisconnect(ctr *Container, network string) error { if !s.valid { return define.ErrDBClosed } @@ -1268,16 +1289,6 @@ func (s *BoltState) RemoveNetworkAliases(ctr *Container, network string) error { return err } - allAliasesBucket, err := getAliasesBucket(tx) - if err != nil { - return err - } - - netAllAliasesBucket, err := allAliasesBucket.CreateBucketIfNotExists([]byte(network)) - if err != nil { - return errors.Wrapf(err, "error creating network aliases bucket for network %s", network) - } - dbCtr := ctrBucket.Bucket(ctrID) if dbCtr == nil { ctr.valid = false @@ -1291,141 +1302,27 @@ func (s *BoltState) RemoveNetworkAliases(ctr *Container, network string) error { ctrNetworksBkt := dbCtr.Bucket(networksBkt) if ctrNetworksBkt == nil { - return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to any CNI networks, so cannot add aliases", ctr.ID()) + return errors.Wrapf(define.ErrNoSuchNetwork, "container %s is not connected to any CNI networks, so cannot disconnect", ctr.ID()) } netConnected := ctrNetworksBkt.Get([]byte(network)) if netConnected == nil { - return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to CNI network %q, so cannot add aliases for this network", ctr.ID(), network) - } - - // Check if the container already has network aliases for this network. - netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network)) - if netAliasesBkt != nil { - // We have aliases. Remove them. - forEachErr := netAliasesBkt.ForEach(func(alias, v []byte) error { - // Relies on errors.Wrapf(nil, ...) returning - // nil. - return errors.Wrapf(netAllAliasesBucket.Delete(alias), "error removing alias %q from network %q when changing aliases for container %s", string(alias), network, ctr.ID()) - }) - if forEachErr != nil { - return forEachErr - } + return errors.Wrapf(define.ErrNoSuchNetwork, "container %s is not connected to CNI network %q", ctr.ID(), network) } - return nil - }) -} - -// Get all network aliases for a single CNI network. Returns a map of alias to -// container ID. -func (s *BoltState) GetAllAliasesForNetwork(network string) (map[string]string, error) { - if !s.valid { - return nil, define.ErrDBClosed - } - - if network == "" { - return nil, errors.Wrapf(define.ErrInvalidArg, "network name must not be empty") - } - - db, err := s.getDBCon() - if err != nil { - return nil, err - } - defer s.deferredCloseDBCon(db) - - aliases := make(map[string]string) - - err = db.View(func(tx *bolt.Tx) error { - aliasBucket, err := getAliasesBucket(tx) - if err != nil { - return err + if err := ctrNetworksBkt.Delete([]byte(network)); err != nil { + return errors.Wrapf(err, "error removing container %s from network %s", ctr.ID(), network) } - dbAlias := aliasBucket.Bucket([]byte(network)) - if dbAlias == nil { - // We can't tell if the network exists, or doesn't exist - // So... Assume it exists, but has no aliases. + bktExists := ctrAliasesBkt.Bucket([]byte(network)) + if bktExists == nil { return nil } - return dbAlias.ForEach(func(alias, ctrId []byte) error { - aliases[string(alias)] = string(ctrId) - return nil - }) - }) - if err != nil { - return nil, err - } - - return aliases, nil -} - -// RemoveAllAliasesForNetwork removes all the aliases in a given CNI network, as -// part of that network being removed. -func (s *BoltState) RemoveAllAliasesForNetwork(network string) error { - if !s.valid { - return define.ErrDBClosed - } - - if network == "" { - return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty") - } - - db, err := s.getDBCon() - if err != nil { - return err - } - defer s.deferredCloseDBCon(db) - - return db.Update(func(tx *bolt.Tx) error { - allCtrsBucket, err := getAllCtrsBucket(tx) - if err != nil { - return err + if err := ctrAliasesBkt.DeleteBucket([]byte(network)); err != nil { + return errors.Wrapf(err, "error removing container %s network aliases for network %s", ctr.ID(), network) } - ctrBucket, err := getCtrBucket(tx) - if err != nil { - return err - } - - allAliasesBucket, err := getAliasesBucket(tx) - if err != nil { - return err - } - - checkAliasesBucketExists := allAliasesBucket.Bucket([]byte(network)) - if checkAliasesBucketExists != nil { - if err := allAliasesBucket.DeleteBucket([]byte(network)); err != nil { - return errors.Wrapf(err, "error removing network %s aliases bucket from DB", network) - } - } - - // Iterate through all containers and remove their aliases - // bucket for the network. - return allCtrsBucket.ForEach(func(ctrID, ctrName []byte) error { - dbCtr := ctrBucket.Bucket(ctrID) - if dbCtr == nil { - // DB State is inconsistent... but we can't do - // anything about it. - // Log and move on. - logrus.Errorf("Container %s listed in all containers, but has no bucket!", string(ctrID)) - return nil - } - - dbCtrAliases := dbCtr.Bucket(aliasesBkt) - if dbCtrAliases == nil { - // Container has no aliases, this is OK. - return nil - } - - ctrNetAliases := dbCtrAliases.Bucket([]byte(network)) - if ctrNetAliases != nil { - if err := dbCtrAliases.DeleteBucket([]byte(network)); err != nil { - return errors.Wrapf(err, "error removing bucket for network aliases for network %s from container %s", network, string(ctrID)) - } - } - return nil - }) + return nil }) } diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go index a48de3092..c06fedd3e 100644 --- a/libpod/boltdb_state_internal.go +++ b/libpod/boltdb_state_internal.go @@ -354,14 +354,6 @@ func getExecBucket(tx *bolt.Tx) (*bolt.Bucket, error) { return bkt, nil } -func getAliasesBucket(tx *bolt.Tx) (*bolt.Bucket, error) { - bkt := tx.Bucket(aliasesBkt) - if bkt == nil { - return nil, errors.Wrapf(define.ErrDBBadConfig, "aliases bucket not found in DB") - } - return bkt, nil -} - func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) { bkt := tx.Bucket(runtimeConfigBkt) if bkt == nil { @@ -584,11 +576,6 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error { return err } - allAliasesBkt, err := getAliasesBucket(tx) - if err != nil { - return err - } - // If a pod was given, check if it exists var podDB *bolt.Bucket var podCtrs *bolt.Bucket @@ -635,41 +622,20 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error { return errors.Wrapf(err, "name \"%s\" is in use", ctr.Name()) } + allNets := make(map[string]bool) + // Check that we don't have any empty network names for _, net := range ctr.config.Networks { if net == "" { return errors.Wrapf(define.ErrInvalidArg, "network names cannot be an empty string") } + allNets[net] = true } - // If we have network aliases, check if they are already in use. - for net, aliases := range ctr.config.NetworkAliases { - // Aliases cannot conflict with container names. - for _, alias := range aliases { - aliasExist := namesBucket.Get([]byte(alias)) - if aliasExist != nil { - return errors.Wrapf(define.ErrCtrExists, "alias %q conflicts with existing container/pod name", alias) - } - } - - netAliasesBkt := allAliasesBkt.Bucket([]byte(net)) - if netAliasesBkt != nil { - for _, alias := range aliases { - aliasExist := netAliasesBkt.Get([]byte(alias)) - if aliasExist != nil { - return errors.Wrapf(define.ErrAliasExists, "network alias %q already exists for network %q", net, alias) - } - } - } - hasNet := false - for _, testNet := range ctr.config.Networks { - if testNet == net { - hasNet = true - break - } - } - if !hasNet { - return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not part of that network", ctr.ID(), net) + // Each network we have aliases for, must exist in networks + for net := range ctr.config.NetworkAliases { + if !allNets[net] { + return errors.Wrapf(define.ErrNoSuchNetwork, "container %s has network aliases for network %q but is not part of that network", ctr.ID(), net) } } @@ -690,63 +656,6 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error { return errors.Wrapf(err, "error adding container %s to all containers bucket in DB", ctr.ID()) } - // Check aliases for all networks, remove conflicts with the - // container name. - for _, net := range ctr.config.Networks { - netAliasesBkt := allAliasesBkt.Bucket([]byte(net)) - if netAliasesBkt == nil { - continue - } - - otherCtrID := netAliasesBkt.Get(ctrName) - if otherCtrID == nil { - continue - } - - if err := netAliasesBkt.Delete(ctrName); err != nil { - return errors.Wrapf(err, "error removing container %s name from network aliases for network %s", ctr.ID(), net) - } - - // We now need to remove from the other container. - // To do this, we work through the container bucket, - // then its aliases bucket, then its aliases for this - // specific network, then we remove the alias. - // Just slightly ridiculous. Just slightly. - otherCtr := ctrBucket.Bucket(otherCtrID) - if otherCtr == nil { - // The state is inconsistent, but we can't do - // much... - logrus.Errorf("Container %s referred to by network alias but not present in state", string(otherCtrID)) - continue - } - otherCtrAliases := otherCtr.Bucket(aliasesBkt) - if otherCtrAliases == nil { - logrus.Errorf("Container %s is missing aliases but but has an alias", string(otherCtrID)) - continue - } - otherCtrNetworkAliases := otherCtrAliases.Bucket([]byte(net)) - if otherCtrNetworkAliases == nil { - logrus.Errorf("Container %s is missing network aliases bucket for network %s but has alias in that network", string(otherCtrID), net) - } - if otherCtrNetworkAliases.Get(ctrName) != nil { - if err := otherCtrNetworkAliases.Delete(ctrName); err != nil { - return errors.Wrapf(err, "error removing container %s name from network %s aliases of container %s", ctr.Name(), net, string(otherCtrID)) - } - } - } - - for net, aliases := range ctr.config.NetworkAliases { - netAliasesBkt, err := allAliasesBkt.CreateBucketIfNotExists([]byte(net)) - if err != nil { - return errors.Wrapf(err, "error creating network aliases bucket for network %q", net) - } - for _, alias := range aliases { - if err := netAliasesBkt.Put([]byte(alias), ctrID); err != nil { - return errors.Wrapf(err, "error adding container %s network alias %q to network %q", ctr.ID(), alias, net) - } - } - } - newCtrBkt, err := ctrBucket.CreateBucket(ctrID) if err != nil { return errors.Wrapf(err, "error adding container %s bucket to DB", ctr.ID()) @@ -998,49 +907,6 @@ func (s *BoltState) removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error return errors.Wrapf(define.ErrCtrExists, "container %s is a dependency of the following containers: %s", ctr.ID(), strings.Join(deps, ", ")) } - // Does the container have any network aliases? - ctrNetAliasesBkt := ctrExists.Bucket(aliasesBkt) - if ctrNetAliasesBkt != nil { - allAliasesBkt, err := getAliasesBucket(tx) - if err != nil { - return err - } - ctrNetworksBkt := ctrExists.Bucket(networksBkt) - // Internal state mismatch if this doesn't exist - we'll just - // assume there are no aliases in that case. - if ctrNetworksBkt != nil { - // This is a little gross. Iterate through all networks - // the container is joined to. Check if we have aliases - // for them. If we do have such aliases, remove all of - // then from the global aliases table for that network. - err = ctrNetworksBkt.ForEach(func(network, v []byte) error { - netAliasesBkt := ctrNetAliasesBkt.Bucket(network) - if netAliasesBkt == nil { - return nil - } - netAllAliasesBkt := allAliasesBkt.Bucket(network) - if netAllAliasesBkt == nil { - // Again the state is inconsistent here, - // but the best we can do is try and - // recover by ignoring it. - return nil - } - return netAliasesBkt.ForEach(func(alias, v []byte) error { - // We don't want to hard-fail on a - // missing alias, so continue if we hit - // errors. - if err := netAllAliasesBkt.Delete(alias); err != nil { - logrus.Errorf("Error removing alias %q from network %q when removing container %s", string(alias), string(network), ctr.ID()) - } - return nil - }) - }) - if err != nil { - return err - } - } - } - if err := ctrBucket.DeleteBucket(ctrID); err != nil { return errors.Wrapf(define.ErrInternal, "error deleting container %s from DB", ctr.ID()) } diff --git a/libpod/container.go b/libpod/container.go index ea5a6e09c..580fa7b3d 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -1085,3 +1085,31 @@ func (c *Container) Timezone() string { func (c *Container) Umask() string { return c.config.Umask } + +// Networks gets all the networks this container is connected to. +// Please do NOT use ctr.config.Networks, as this can be changed from those +// values at runtime via network connect and disconnect. +// If the container is configured to use CNI and this function returns an empty +// array, the container will still be connected to the default network. +func (c *Container) Networks() ([]string, error) { + if !c.batched { + c.lock.Lock() + defer c.lock.Unlock() + + if err := c.syncContainer(); err != nil { + return nil, err + } + } + + return c.networks() +} + +// Unlocked accessor for networks +func (c *Container) networks() ([]string, error) { + networks, err := c.runtime.state.GetNetworks(c) + if err != nil && errors.Cause(err) == define.ErrNoSuchNetwork { + return c.config.Networks, nil + } + + return networks, err +} diff --git a/libpod/container_config.go b/libpod/container_config.go index d73fbb42f..cc3ad25ea 100644 --- a/libpod/container_config.go +++ b/libpod/container_config.go @@ -236,6 +236,9 @@ type ContainerNetworkConfig struct { // Will be appended to host's host file HostAdd []string `json:"hostsAdd,omitempty"` // Network names (CNI) to add container to. Empty to use default network. + // Please note that these can be altered at runtime. The actual list is + // stored in the DB and should be retrieved from there; this is only the + // set of networks the container was *created* with. Networks []string `json:"networks,omitempty"` // Network mode specified for the default network. NetMode namespaces.NetworkMode `json:"networkMode,omitempty"` diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 0aeaae43d..108954bad 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -641,12 +641,17 @@ func (c *Container) removeIPv4Allocations() error { cniDefaultNetwork = c.runtime.netPlugin.GetDefaultNetworkName() } + networks, err := c.networks() + if err != nil { + return err + } + switch { - case len(c.config.Networks) > 0 && len(c.config.Networks) != len(c.state.NetworkStatus): - return errors.Wrapf(define.ErrInternal, "network mismatch: asked to join %d CNI networks but got %d CNI results", len(c.config.Networks), len(c.state.NetworkStatus)) - case len(c.config.Networks) == 0 && len(c.state.NetworkStatus) != 1: + case len(networks) > 0 && len(networks) != len(c.state.NetworkStatus): + return errors.Wrapf(define.ErrInternal, "network mismatch: asked to join %d CNI networks but got %d CNI results", len(networks), len(c.state.NetworkStatus)) + case len(networks) == 0 && len(c.state.NetworkStatus) != 1: return errors.Wrapf(define.ErrInternal, "network mismatch: did not specify CNI networks but joined more than one (%d)", len(c.state.NetworkStatus)) - case len(c.config.Networks) == 0 && cniDefaultNetwork == "": + case len(networks) == 0 && cniDefaultNetwork == "": return errors.Wrapf(define.ErrInternal, "could not retrieve name of CNI default network") } @@ -656,11 +661,11 @@ func (c *Container) removeIPv4Allocations() error { continue } candidate := "" - if len(c.config.Networks) > 0 { + if len(networks) > 0 { // CNI returns networks in order we passed them. // So our index into results should be our index // into networks. - candidate = filepath.Join(cniNetworksDir, c.config.Networks[index], ctrIP.Address.IP.String()) + candidate = filepath.Join(cniNetworksDir, networks[index], ctrIP.Address.IP.String()) } else { candidate = filepath.Join(cniNetworksDir, cniDefaultNetwork, ctrIP.Address.IP.String()) } @@ -1503,6 +1508,7 @@ func (c *Container) mountStorage() (_ string, deferredErr error) { // config. // Returns the volume that was mounted. func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string) (*Volume, error) { + logrus.Debugf("Going to mount named volume %s", v.Name) vol, err := c.runtime.state.Volume(v.Name) if err != nil { return nil, errors.Wrapf(err, "error retrieving named volume %s for container %s", v.Name, c.ID()) diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go index 38b3a6686..775965477 100644 --- a/libpod/define/container_inspect.go +++ b/libpod/define/container_inspect.go @@ -575,6 +575,8 @@ type InspectAdditionalNetwork struct { // Links is presently unused and maintained exclusively for // compatibility. Links []string `json:"Links"` + // Aliases are any network aliases the container has in this network. + Aliases []string `json:"Aliases,omitempty"` } // InspectNetworkSettings holds information about the network settings of the diff --git a/libpod/define/errors.go b/libpod/define/errors.go index 27c5febf4..471827b7c 100644 --- a/libpod/define/errors.go +++ b/libpod/define/errors.go @@ -33,9 +33,6 @@ var ( // ErrNoAliases indicates that the container does not have any network // aliases. ErrNoAliases = errors.New("no aliases for container") - // ErrNoAliasesForNetwork indicates that the container has no aliases - // for a specific network. - ErrNoAliasesForNetwork = errors.New("no aliases for network") // ErrCtrExists indicates a container with the same name or ID already // exists @@ -49,9 +46,9 @@ var ( // ErrExecSessionExists indicates an exec session with the same ID // already exists. ErrExecSessionExists = errors.New("exec session already exists") - // ErrAliasExists indicates that a network alias with the same name - // already exists in the network. - ErrAliasExists = errors.New("alias already exists") + // ErrNetworkExists indicates that a network with the given name already + // exists. + ErrNetworkExists = errors.New("network already exists") // ErrCtrStateInvalid indicates a container is in an improper state for // the requested operation diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go index ba4c70c6b..6c0cde531 100644 --- a/libpod/in_memory_state.go +++ b/libpod/in_memory_state.go @@ -31,8 +31,7 @@ type InMemoryState struct { ctrExecSessions map[string][]string // Maps pod ID to a map of container ID to container struct. podContainers map[string]map[string]*Container - // Maps network name to alias to container ID - networkAliases map[string]map[string]string + ctrNetworks map[string][]string // Maps container ID to network name to list of aliases. ctrNetworkAliases map[string]map[string][]string // Global name registry - ensures name uniqueness and performs lookups. @@ -69,7 +68,7 @@ func NewInMemoryState() (State, error) { state.podContainers = make(map[string]map[string]*Container) - state.networkAliases = make(map[string]map[string]string) + state.ctrNetworks = make(map[string][]string) state.ctrNetworkAliases = make(map[string]map[string][]string) state.nameIndex = registrar.NewRegistrar() @@ -293,7 +292,7 @@ func (s *InMemoryState) AddContainer(ctr *Container) error { } // Check network aliases - for network, aliases := range ctr.config.NetworkAliases { + for network := range ctr.config.NetworkAliases { inNet := false for _, net := range ctr.config.Networks { if net == network { @@ -304,19 +303,6 @@ func (s *InMemoryState) AddContainer(ctr *Container) error { if !inNet { return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not joined to network", ctr.ID(), network) } - - allNetAliases, ok := s.networkAliases[network] - if ok { - for _, alias := range aliases { - // Check if alias is a name - if _, err := s.nameIndex.Get(alias); err == nil { - return define.ErrInvalidArg - } - if _, ok := allNetAliases[alias]; ok { - return define.ErrAliasExists - } - } - } } // There are potential race conditions with this @@ -375,46 +361,17 @@ func (s *InMemoryState) AddContainer(ctr *Container) error { s.addCtrToVolDependsMap(ctr.ID(), vol.Name) } - for _, network := range ctr.config.Networks { - allNetAliases, ok := s.networkAliases[network] - if !ok { - continue - } - otherCtrID, ok := allNetAliases[ctr.Name()] - if !ok { - continue - } - delete(allNetAliases, ctr.Name()) - - otherCtrAliases, ok := s.ctrNetworkAliases[otherCtrID] - if !ok { - continue - } - otherCtrNetAliases, ok := otherCtrAliases[network] - if !ok { - continue - } - newAliases := []string{} - for _, alias := range otherCtrNetAliases { - if alias != ctr.Name() { - newAliases = append(newAliases, alias) - } + // Add networks + newNets := make([]string, 0, len(ctr.config.Networks)) + for _, net := range ctr.config.Networks { + if net == "" { + return define.ErrInvalidArg } - otherCtrAliases[network] = newAliases + newNets = append(newNets, net) } + s.ctrNetworks[ctr.ID()] = newNets // Add network aliases - for network, aliases := range ctr.config.NetworkAliases { - allNetAliases, ok := s.networkAliases[network] - if !ok { - allNetAliases = make(map[string]string) - s.networkAliases[network] = allNetAliases - } - - for _, alias := range aliases { - allNetAliases[alias] = ctr.ID() - } - } s.ctrNetworkAliases[ctr.ID()] = ctr.config.NetworkAliases return nil @@ -480,18 +437,12 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error { } // Remove our network aliases - ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()] - if ok { - for network, aliases := range ctrAliases { - netAliases, ok := s.networkAliases[network] - if ok { - for _, alias := range aliases { - delete(netAliases, alias) - } - } - } + if _, ok := s.ctrNetworkAliases[ctr.ID()]; ok { delete(s.ctrNetworkAliases, ctr.ID()) } + if _, ok := s.ctrNetworks[ctr.ID()]; ok { + delete(s.ctrNetworks, ctr.ID()) + } return nil } @@ -569,6 +520,26 @@ func (s *InMemoryState) AllContainers() ([]*Container, error) { return ctrs, nil } +// Get all networks this container is present in. +func (s *InMemoryState) GetNetworks(ctr *Container) ([]string, error) { + if !ctr.valid { + return nil, define.ErrCtrRemoved + } + + ctr, ok := s.containers[ctr.ID()] + if !ok { + ctr.valid = false + return nil, define.ErrNoSuchCtr + } + + ctrNetworks, ok := s.ctrNetworks[ctr.ID()] + if !ok { + return nil, define.ErrNoSuchNetwork + } + + return ctrNetworks, nil +} + // GetNetworkAliases returns network aliases for the given container in the // given network. func (s *InMemoryState) GetNetworkAliases(ctr *Container, network string) ([]string, error) { @@ -582,6 +553,7 @@ func (s *InMemoryState) GetNetworkAliases(ctr *Container, network string) ([]str ctr, ok := s.containers[ctr.ID()] if !ok { + ctr.valid = false return nil, define.ErrNoSuchCtr } @@ -615,6 +587,7 @@ func (s *InMemoryState) GetAllNetworkAliases(ctr *Container) (map[string][]strin ctr, ok := s.containers[ctr.ID()] if !ok { + ctr.valid = false return nil, define.ErrNoSuchCtr } @@ -626,9 +599,8 @@ func (s *InMemoryState) GetAllNetworkAliases(ctr *Container) (map[string][]strin return ctrAliases, nil } -// SetNetworkAliases sets network aliases for the given container in the given -// network. -func (s *InMemoryState) SetNetworkAliases(ctr *Container, network string, aliases []string) error { +// NetworkConnect connects to the given network +func (s *InMemoryState) NetworkConnect(ctr *Container, network string, aliases []string) error { if !ctr.valid { return define.ErrCtrRemoved } @@ -639,55 +611,37 @@ func (s *InMemoryState) SetNetworkAliases(ctr *Container, network string, aliase ctr, ok := s.containers[ctr.ID()] if !ok { + ctr.valid = false return define.ErrNoSuchCtr } inNet := false - for _, net := range ctr.config.Networks { + ctrNetworks, ok := s.ctrNetworks[ctr.ID()] + if !ok { + return define.ErrNoSuchNetwork + } + for _, net := range ctrNetworks { if net == network { inNet = true } } - if !inNet { - return define.ErrInvalidArg + if inNet { + return define.ErrNoSuchNetwork } + s.ctrNetworks[ctr.ID()] = append(ctrNetworks, network) ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()] if !ok { ctrAliases = make(map[string][]string) s.ctrNetworkAliases[ctr.ID()] = ctrAliases } - netAliases, ok := ctrAliases[network] - if !ok { - netAliases = []string{} - ctrAliases[network] = netAliases - } - - allAliases, ok := s.networkAliases[network] - if !ok { - allAliases = make(map[string]string) - s.networkAliases[network] = allAliases - } - - for _, alias := range netAliases { - delete(allAliases, alias) - } - - for _, newAlias := range aliases { - if _, ok := allAliases[newAlias]; ok { - return define.ErrAliasExists - } - allAliases[newAlias] = ctr.ID() - } - ctrAliases[network] = aliases return nil } -// RemoveNetworkAliases removes network aliases from the given container in the -// given network. -func (s *InMemoryState) RemoveNetworkAliases(ctr *Container, network string) error { +// Disconnect from the given network and remove all aliases in it. +func (s *InMemoryState) NetworkDisconnect(ctr *Container, network string) error { if !ctr.valid { return define.ErrCtrRemoved } @@ -698,73 +652,36 @@ func (s *InMemoryState) RemoveNetworkAliases(ctr *Container, network string) err ctr, ok := s.containers[ctr.ID()] if !ok { + ctr.valid = false return define.ErrNoSuchCtr } + ctrNetworks, ok := s.ctrNetworks[ctr.ID()] + if !ok { + return define.ErrNoSuchNetwork + } inNet := false - for _, net := range ctr.config.Networks { + remainingNets := make([]string, 0, len(ctrNetworks)) + for _, net := range ctrNetworks { if net == network { inNet = true + break + } else { + remainingNets = append(remainingNets, net) } } if !inNet { - return define.ErrInvalidArg + return define.ErrNoSuchNetwork } + s.ctrNetworks[ctr.ID()] = remainingNets ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()] if !ok { ctrAliases = make(map[string][]string) s.ctrNetworkAliases[ctr.ID()] = ctrAliases } - netAliases, ok := ctrAliases[network] - if !ok { - netAliases = []string{} - ctrAliases[network] = netAliases - } - - allAliases, ok := s.networkAliases[network] - if !ok { - allAliases = make(map[string]string) - s.networkAliases[network] = allAliases - } - - for _, alias := range netAliases { - delete(allAliases, alias) - } - - return nil -} - -// GetAllAliasesForNetwork gets all the aliases for a single network. -func (s *InMemoryState) GetAllAliasesForNetwork(network string) (map[string]string, error) { - if network == "" { - return nil, errors.Wrapf(define.ErrInvalidArg, "network names must not be empty") - } - - allAliases, ok := s.networkAliases[network] - if !ok { - // Can't tell if the network exists. - // Assume it does. - return map[string]string{}, nil - } - - return allAliases, nil -} - -// RemoveAllAliasesForNetwork removes all the aliases for a given network. -func (s *InMemoryState) RemoveAllAliasesForNetwork(network string) error { - if network == "" { - return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty") - } - - if _, ok := s.networkAliases[network]; ok { - delete(s.networkAliases, network) - } - - for _, ctrAliases := range s.ctrNetworkAliases { - if _, ok := ctrAliases[network]; ok { - delete(ctrAliases, network) - } + if _, ok := ctrAliases[network]; ok { + delete(ctrAliases, network) } return nil @@ -1422,7 +1339,7 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error { } // Check network aliases - for network, aliases := range ctr.config.NetworkAliases { + for network := range ctr.config.NetworkAliases { inNet := false for _, net := range ctr.config.Networks { if net == network { @@ -1433,19 +1350,6 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error { if !inNet { return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not joined to network", ctr.ID(), network) } - - allNetAliases, ok := s.networkAliases[network] - if ok { - for _, alias := range aliases { - // Check if alias is a name - if _, err := s.nameIndex.Get(alias); err == nil { - return define.ErrInvalidArg - } - if _, ok := allNetAliases[alias]; ok { - return define.ErrAliasExists - } - } - } } // Retrieve pod containers list @@ -1525,46 +1429,17 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error { s.addCtrToVolDependsMap(ctr.ID(), vol.Name) } - for _, network := range ctr.config.Networks { - allNetAliases, ok := s.networkAliases[network] - if !ok { - continue - } - otherCtrID, ok := allNetAliases[ctr.Name()] - if !ok { - continue - } - delete(allNetAliases, ctr.Name()) - - otherCtrAliases, ok := s.ctrNetworkAliases[otherCtrID] - if !ok { - continue - } - otherCtrNetAliases, ok := otherCtrAliases[network] - if !ok { - continue - } - newAliases := []string{} - for _, alias := range otherCtrNetAliases { - if alias != ctr.Name() { - newAliases = append(newAliases, alias) - } + // Add networks + newNets := make([]string, 0, len(ctr.config.Networks)) + for _, net := range ctr.config.Networks { + if net == "" { + return define.ErrInvalidArg } - otherCtrAliases[network] = newAliases + newNets = append(newNets, net) } + s.ctrNetworks[ctr.ID()] = newNets // Add network aliases - for network, aliases := range ctr.config.NetworkAliases { - allNetAliases, ok := s.networkAliases[network] - if !ok { - allNetAliases = make(map[string]string) - s.networkAliases[network] = allNetAliases - } - - for _, alias := range aliases { - allNetAliases[alias] = ctr.ID() - } - } s.ctrNetworkAliases[ctr.ID()] = ctr.config.NetworkAliases return nil @@ -1648,18 +1523,12 @@ func (s *InMemoryState) RemoveContainerFromPod(pod *Pod, ctr *Container) error { } // Remove our network aliases - ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()] - if ok { - for network, aliases := range ctrAliases { - netAliases, ok := s.networkAliases[network] - if ok { - for _, alias := range aliases { - delete(netAliases, alias) - } - } - } + if _, ok := s.ctrNetworkAliases[ctr.ID()]; ok { delete(s.ctrNetworkAliases, ctr.ID()) } + if _, ok := s.ctrNetworks[ctr.ID()]; ok { + delete(s.ctrNetworks, ctr.ID()) + } return nil } diff --git a/libpod/network/config.go b/libpod/network/config.go index a08e684d8..ce8a4446c 100644 --- a/libpod/network/config.go +++ b/libpod/network/config.go @@ -131,8 +131,9 @@ func (f FirewallConfig) Bytes() ([]byte, error) { // DNSNameConfig describes the dns container name resolution plugin config type DNSNameConfig struct { - PluginType string `json:"type"` - DomainName string `json:"domainName"` + PluginType string `json:"type"` + DomainName string `json:"domainName"` + Capabilities map[string]bool `json:"capabilities"` } // Bytes outputs the configuration as []byte diff --git a/libpod/network/create.go b/libpod/network/create.go index bf11631bf..c11904ecf 100644 --- a/libpod/network/create.go +++ b/libpod/network/create.go @@ -15,6 +15,7 @@ import ( "github.com/pkg/errors" ) +// Create the CNI network func Create(name string, options entities.NetworkCreateOptions, r *libpod.Runtime) (*entities.NetworkCreateReport, error) { var fileName string if err := isSupportedDriver(options.Driver); err != nil { @@ -41,60 +42,120 @@ func Create(name string, options entities.NetworkCreateOptions, r *libpod.Runtim return &entities.NetworkCreateReport{Filename: fileName}, nil } +// validateBridgeOptions validate the bridge networking options +func validateBridgeOptions(options entities.NetworkCreateOptions) error { + subnet := &options.Subnet + ipRange := &options.Range + gateway := options.Gateway + // if IPv6 is set an IPv6 subnet MUST be specified + if options.IPv6 && ((subnet.IP == nil) || (subnet.IP != nil && !IsIPv6(subnet.IP))) { + return errors.Errorf("ipv6 option requires an IPv6 --subnet to be provided") + } + // range and gateway depend on subnet + if subnet.IP == nil && (ipRange.IP != nil || gateway != nil) { + return errors.Errorf("every ip-range or gateway must have a corresponding subnet") + } + + // if a range is given, we need to ensure it is "in" the network range. + if ipRange.IP != nil { + firstIP, err := FirstIPInSubnet(ipRange) + if err != nil { + return errors.Wrapf(err, "failed to get first IP address from ip-range") + } + lastIP, err := LastIPInSubnet(ipRange) + if err != nil { + return errors.Wrapf(err, "failed to get last IP address from ip-range") + } + if !subnet.Contains(firstIP) || !subnet.Contains(lastIP) { + return errors.Errorf("the ip range %s does not fall within the subnet range %s", ipRange.String(), subnet.String()) + } + } + + // if network is provided and if gateway is provided, make sure it is "in" network + if gateway != nil && !subnet.Contains(gateway) { + return errors.Errorf("gateway %s is not in valid for subnet %s", gateway.String(), subnet.String()) + } + + return nil + +} + // createBridge creates a CNI network func createBridge(r *libpod.Runtime, name string, options entities.NetworkCreateOptions) (string, error) { isGateway := true ipMasq := true - subnet := &options.Subnet - ipRange := options.Range runtimeConfig, err := r.GetConfig() if err != nil { return "", err } - // if range is provided, make sure it is "in" network - if subnet.IP != nil { - // if network is provided, does it conflict with existing CNI or live networks - err = ValidateUserNetworkIsAvailable(runtimeConfig, subnet) - } else { - // if no network is provided, figure out network - subnet, err = GetFreeNetwork(runtimeConfig) - } + + // validate options + err = validateBridgeOptions(options) if err != nil { return "", err } + + // For compatibility with the docker implementation: + // if IPv6 is enabled (it really means dual-stack) then an IPv6 subnet has to be provided, and one free network is allocated for IPv4 + // if IPv6 is not specified the subnet may be specified and can be either IPv4 or IPv6 (podman, unlike docker, allows IPv6 only networks) + // If not subnet is specified an IPv4 subnet will be allocated + subnet := &options.Subnet + ipRange := &options.Range gateway := options.Gateway - if gateway == nil { - // if no gateway is provided, provide it as first ip of network - gateway = CalcGatewayIP(subnet) - } - // if network is provided and if gateway is provided, make sure it is "in" network - if options.Subnet.IP != nil && options.Gateway != nil { - if !subnet.Contains(gateway) { - return "", errors.Errorf("gateway %s is not in valid for subnet %s", gateway.String(), subnet.String()) + var ipamRanges [][]IPAMLocalHostRangeConf + var routes []IPAMRoute + if subnet.IP != nil { + // if network is provided, does it conflict with existing CNI or live networks + err = ValidateUserNetworkIsAvailable(runtimeConfig, subnet) + if err != nil { + return "", err } - } - if options.Internal { - isGateway = false - ipMasq = false - } - - // if a range is given, we need to ensure it is "in" the network range. - if options.Range.IP != nil { - if options.Subnet.IP == nil { - return "", errors.New("you must define a subnet range to define an ip-range") + // obtain CNI subnet default route + defaultRoute, err := NewIPAMDefaultRoute(IsIPv6(subnet.IP)) + if err != nil { + return "", err } - firstIP, err := FirstIPInSubnet(&options.Range) + routes = append(routes, defaultRoute) + // obtain CNI range + ipamRange, err := NewIPAMLocalHostRange(subnet, ipRange, gateway) if err != nil { return "", err } - lastIP, err := LastIPInSubnet(&options.Range) + ipamRanges = append(ipamRanges, ipamRange) + } + // if no network is provided or IPv6 flag used, figure out the IPv4 network + if options.IPv6 || len(routes) == 0 { + subnetV4, err := GetFreeNetwork(runtimeConfig) if err != nil { return "", err } - if !subnet.Contains(firstIP) || !subnet.Contains(lastIP) { - return "", errors.Errorf("the ip range %s does not fall within the subnet range %s", options.Range.String(), subnet.String()) + // obtain IPv4 default route + defaultRoute, err := NewIPAMDefaultRoute(false) + if err != nil { + return "", err } + routes = append(routes, defaultRoute) + // the CNI bridge plugin does not need to set + // the range or gateway options explicitly + ipamRange, err := NewIPAMLocalHostRange(subnetV4, nil, nil) + if err != nil { + return "", err + } + ipamRanges = append(ipamRanges, ipamRange) + } + + // create CNI config + ipamConfig, err := NewIPAMHostLocalConf(routes, ipamRanges) + if err != nil { + return "", err } + + if options.Internal { + isGateway = false + ipMasq = false + } + + // obtain host bridge name bridgeDeviceName, err := GetFreeDeviceName(runtimeConfig) if err != nil { return "", err @@ -113,20 +174,9 @@ func createBridge(r *libpod.Runtime, name string, options entities.NetworkCreate name = bridgeDeviceName } + // create CNI plugin configuration ncList := NewNcList(name, version.Current()) var plugins []CNIPlugins - var routes []IPAMRoute - - defaultRoute, err := NewIPAMDefaultRoute(IsIPv6(subnet.IP)) - if err != nil { - return "", err - } - routes = append(routes, defaultRoute) - ipamConfig, err := NewIPAMHostLocalConf(subnet, routes, ipRange, gateway) - if err != nil { - return "", err - } - // TODO need to iron out the role of isDefaultGW and IPMasq bridge := NewHostLocalBridge(bridgeDeviceName, isGateway, false, ipMasq, ipamConfig) plugins = append(plugins, bridge) diff --git a/libpod/network/create_test.go b/libpod/network/create_test.go new file mode 100644 index 000000000..16188e497 --- /dev/null +++ b/libpod/network/create_test.go @@ -0,0 +1,131 @@ +package network + +import ( + "net" + "testing" + + "github.com/containers/podman/v2/pkg/domain/entities" +) + +func Test_validateBridgeOptions(t *testing.T) { + + tests := []struct { + name string + subnet net.IPNet + ipRange net.IPNet + gateway net.IP + isIPv6 bool + wantErr bool + }{ + { + name: "IPv4 subnet only", + subnet: net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, + }, + { + name: "IPv4 subnet and range", + subnet: net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, + ipRange: net.IPNet{IP: net.IPv4(192, 168, 0, 128), Mask: net.IPv4Mask(255, 255, 255, 128)}, + }, + { + name: "IPv4 subnet and gateway", + subnet: net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, + gateway: net.ParseIP("192.168.0.10"), + }, + { + name: "IPv4 subnet, range and gateway", + subnet: net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, + ipRange: net.IPNet{IP: net.IPv4(192, 168, 0, 128), Mask: net.IPv4Mask(255, 255, 255, 128)}, + gateway: net.ParseIP("192.168.0.10"), + }, + { + name: "IPv6 subnet only", + subnet: net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, + }, + { + name: "IPv6 subnet and range", + subnet: net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, + ipRange: net.IPNet{IP: net.ParseIP("2001:DB8:0:0:1::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::"))}, + isIPv6: true, + }, + { + name: "IPv6 subnet and gateway", + subnet: net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, + gateway: net.ParseIP("2001:DB8::2"), + isIPv6: true, + }, + { + name: "IPv6 subnet, range and gateway", + subnet: net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, + ipRange: net.IPNet{IP: net.ParseIP("2001:DB8:0:0:1::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::"))}, + gateway: net.ParseIP("2001:DB8::2"), + isIPv6: true, + }, + { + name: "IPv6 subnet, range and gateway without IPv6 option (PODMAN SUPPORTS IT UNLIKE DOCKEr)", + subnet: net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, + ipRange: net.IPNet{IP: net.ParseIP("2001:DB8:0:0:1::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::"))}, + gateway: net.ParseIP("2001:DB8::2"), + isIPv6: false, + }, + { + name: "range provided but not subnet", + ipRange: net.IPNet{IP: net.IPv4(192, 168, 0, 128), Mask: net.IPv4Mask(255, 255, 255, 128)}, + wantErr: true, + }, + { + name: "gateway provided but not subnet", + gateway: net.ParseIP("192.168.0.10"), + wantErr: true, + }, + { + name: "IPv4 subnet but IPv6 required", + subnet: net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, + ipRange: net.IPNet{IP: net.IPv4(192, 168, 0, 128), Mask: net.IPv4Mask(255, 255, 255, 128)}, + gateway: net.ParseIP("192.168.0.10"), + isIPv6: true, + wantErr: true, + }, + { + name: "IPv6 required but IPv4 options used", + subnet: net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, + ipRange: net.IPNet{IP: net.IPv4(192, 168, 0, 128), Mask: net.IPv4Mask(255, 255, 255, 128)}, + gateway: net.ParseIP("192.168.0.10"), + isIPv6: true, + wantErr: true, + }, + { + name: "IPv6 required but not subnet provided", + isIPv6: true, + wantErr: true, + }, + { + name: "range out of the subnet", + subnet: net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, + ipRange: net.IPNet{IP: net.ParseIP("2001:1:1::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::"))}, + gateway: net.ParseIP("2001:DB8::2"), + isIPv6: true, + wantErr: true, + }, + { + name: "gateway out of the subnet", + subnet: net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, + gateway: net.ParseIP("2001::2"), + isIPv6: true, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + options := entities.NetworkCreateOptions{ + Subnet: tt.subnet, + Range: tt.ipRange, + Gateway: tt.gateway, + IPv6: tt.isIPv6, + } + if err := validateBridgeOptions(options); (err != nil) != tt.wantErr { + t.Errorf("validateBridgeOptions() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/libpod/network/files.go b/libpod/network/files.go index a2090491f..846e5c62d 100644 --- a/libpod/network/files.go +++ b/libpod/network/files.go @@ -14,6 +14,7 @@ import ( "github.com/pkg/errors" ) +// GetCNIConfDir get CNI configuration directory func GetCNIConfDir(configArg *config.Config) string { if len(configArg.Network.NetworkConfigDir) < 1 { dc, err := config.DefaultConfig() diff --git a/libpod/network/netconflist.go b/libpod/network/netconflist.go index 8187fdb39..111f1715c 100644 --- a/libpod/network/netconflist.go +++ b/libpod/network/netconflist.go @@ -42,8 +42,7 @@ func NewHostLocalBridge(name string, isGateWay, isDefaultGW, ipMasq bool, ipamCo } // NewIPAMHostLocalConf creates a new IPAMHostLocal configfuration -func NewIPAMHostLocalConf(subnet *net.IPNet, routes []IPAMRoute, ipRange net.IPNet, gw net.IP) (IPAMHostLocalConf, error) { - var ipamRanges [][]IPAMLocalHostRangeConf +func NewIPAMHostLocalConf(routes []IPAMRoute, ipamRanges [][]IPAMLocalHostRangeConf) (IPAMHostLocalConf, error) { ipamConf := IPAMHostLocalConf{ PluginType: "host-local", Routes: routes, @@ -51,22 +50,19 @@ func NewIPAMHostLocalConf(subnet *net.IPNet, routes []IPAMRoute, ipRange net.IPN //ResolveConf: "", //DataDir: "" } - IPAMRange, err := newIPAMLocalHostRange(subnet, &ipRange, &gw) - if err != nil { - return ipamConf, err - } - ipamRanges = append(ipamRanges, IPAMRange) + ipamConf.Ranges = ipamRanges return ipamConf, nil } -func newIPAMLocalHostRange(subnet *net.IPNet, ipRange *net.IPNet, gw *net.IP) ([]IPAMLocalHostRangeConf, error) { //nolint:interfacer +// NewIPAMLocalHostRange create a new IPAM range +func NewIPAMLocalHostRange(subnet *net.IPNet, ipRange *net.IPNet, gw net.IP) ([]IPAMLocalHostRangeConf, error) { //nolint:interfacer var ranges []IPAMLocalHostRangeConf hostRange := IPAMLocalHostRangeConf{ Subnet: subnet.String(), } // an user provided a range, we add it here - if ipRange.IP != nil { + if ipRange != nil && ipRange.IP != nil { first, err := FirstIPInSubnet(ipRange) if err != nil { return nil, err @@ -126,9 +122,12 @@ func NewFirewallPlugin() FirewallConfig { // NewDNSNamePlugin creates the dnsname config with a given // domainname func NewDNSNamePlugin(domainName string) DNSNameConfig { + caps := make(map[string]bool, 1) + caps["aliases"] = true return DNSNameConfig{ - PluginType: "dnsname", - DomainName: domainName, + PluginType: "dnsname", + DomainName: domainName, + Capabilities: caps, } } diff --git a/libpod/network/netconflist_test.go b/libpod/network/netconflist_test.go index 5893bf985..6bf1a9777 100644 --- a/libpod/network/netconflist_test.go +++ b/libpod/network/netconflist_test.go @@ -1,6 +1,7 @@ package network import ( + "net" "reflect" "testing" ) @@ -36,3 +37,72 @@ func TestNewIPAMDefaultRoute(t *testing.T) { }) } } + +func TestNewIPAMLocalHostRange(t *testing.T) { + tests := []struct { + name string + subnet *net.IPNet + ipRange *net.IPNet + gw net.IP + want []IPAMLocalHostRangeConf + }{ + { + name: "IPv4 subnet", + subnet: &net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, + want: []IPAMLocalHostRangeConf{ + { + Subnet: "192.168.0.0/24", + }, + }, + }, + { + name: "IPv4 subnet, range and gateway", + subnet: &net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, + ipRange: &net.IPNet{IP: net.IPv4(192, 168, 0, 128), Mask: net.IPv4Mask(255, 255, 255, 128)}, + gw: net.ParseIP("192.168.0.10"), + want: []IPAMLocalHostRangeConf{ + { + Subnet: "192.168.0.0/24", + RangeStart: "192.168.0.129", + RangeEnd: "192.168.0.255", + Gateway: "192.168.0.10", + }, + }, + }, + { + name: "IPv6 subnet", + subnet: &net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, + want: []IPAMLocalHostRangeConf{ + { + Subnet: "2001:db8::/48", + }, + }, + }, + { + name: "IPv6 subnet, range and gateway", + subnet: &net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, + ipRange: &net.IPNet{IP: net.ParseIP("2001:DB8:1:1::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::"))}, + gw: net.ParseIP("2001:DB8::2"), + want: []IPAMLocalHostRangeConf{ + { + Subnet: "2001:db8::/48", + RangeStart: "2001:db8:1:1::1", + RangeEnd: "2001:db8:1:1:ffff:ffff:ffff:ffff", + Gateway: "2001:db8::2", + }, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + got, err := NewIPAMLocalHostRange(tt.subnet, tt.ipRange, tt.gw) + if err != nil { + t.Errorf("no error expected: %v", err) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewIPAMLocalHostRange() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 28dca8dd8..1a7740085 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -104,7 +104,18 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re podName := getCNIPodName(ctr) - podNetwork := r.getPodNetwork(ctr.ID(), podName, ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP, requestedMAC) + networks, err := ctr.networks() + if err != nil { + return nil, err + } + podNetwork := r.getPodNetwork(ctr.ID(), podName, ctrNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC) + aliases, err := ctr.runtime.state.GetAllNetworkAliases(ctr) + if err != nil { + return nil, err + } + if len(aliases) > 0 { + podNetwork.Aliases = aliases + } results, err := r.netPlugin.SetUpPod(podNetwork) if err != nil { @@ -202,7 +213,11 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error { if ctr.config.NetMode.IsSlirp4netns() { return r.setupSlirp4netns(ctr) } - if len(ctr.config.Networks) > 0 { + networks, err := ctr.networks() + if err != nil { + return err + } + if len(networks) > 0 { // set up port forwarder for CNI-in-slirp4netns netnsPath := ctr.state.NetNS.Path() // TODO: support slirp4netns port forwarder as well @@ -718,6 +733,11 @@ func (r *Runtime) teardownNetNS(ctr *Container) error { logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID()) + networks, err := ctr.networks() + if err != nil { + return err + } + // rootless containers do not use the CNI plugin directly if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() { var requestedIP net.IP @@ -738,7 +758,7 @@ func (r *Runtime) teardownNetNS(ctr *Container) error { requestedMAC = ctr.config.StaticMAC } - podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP, requestedMAC) + podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC) if err := r.netPlugin.TearDownPod(podNetwork); err != nil { return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID()) @@ -746,7 +766,7 @@ func (r *Runtime) teardownNetNS(ctr *Container) error { } // CNI-in-slirp4netns - if rootless.IsRootless() && len(ctr.config.Networks) != 0 { + if rootless.IsRootless() && len(networks) != 0 { if err := DeallocRootlessCNI(context.Background(), ctr); err != nil { return errors.Wrapf(err, "error tearing down CNI-in-slirp4netns for container %s", ctr.ID()) } @@ -832,13 +852,18 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e settings := new(define.InspectNetworkSettings) settings.Ports = makeInspectPortBindings(c.config.PortMappings) + networks, err := c.networks() + if err != nil { + return nil, err + } + // We can't do more if the network is down. if c.state.NetNS == nil { // We still want to make dummy configurations for each CNI net // the container joined. - if len(c.config.Networks) > 0 { - settings.Networks = make(map[string]*define.InspectAdditionalNetwork, len(c.config.Networks)) - for _, net := range c.config.Networks { + if len(networks) > 0 { + settings.Networks = make(map[string]*define.InspectAdditionalNetwork, len(networks)) + for _, net := range networks { cniNet := new(define.InspectAdditionalNetwork) cniNet.NetworkID = net settings.Networks[net] = cniNet @@ -857,16 +882,16 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e } // If we have CNI networks - handle that here - if len(c.config.Networks) > 0 { - if len(c.config.Networks) != len(c.state.NetworkStatus) { - return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI networks but have information on %d networks", len(c.config.Networks), len(c.state.NetworkStatus)) + if len(networks) > 0 { + if len(networks) != len(c.state.NetworkStatus) { + return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI networks but have information on %d networks", len(networks), len(c.state.NetworkStatus)) } settings.Networks = make(map[string]*define.InspectAdditionalNetwork) // CNI results should be in the same order as the list of // networks we pass into CNI. - for index, name := range c.config.Networks { + for index, name := range networks { cniResult := c.state.NetworkStatus[index] addedNet := new(define.InspectAdditionalNetwork) addedNet.NetworkID = name @@ -875,6 +900,13 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e if err != nil { return nil, err } + + aliases, err := c.runtime.state.GetNetworkAliases(c, name) + if err != nil { + return nil, err + } + addedNet.Aliases = aliases + addedNet.InspectBasicNetworkConfig = basicConfig settings.Networks[name] = addedNet diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go index 3d4ff6e86..1d6158cc2 100644 --- a/libpod/rootless_cni_linux.go +++ b/libpod/rootless_cni_linux.go @@ -40,8 +40,12 @@ const ( // // AllocRootlessCNI does not lock c. c should be already locked. func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.Result, error) { - if len(c.config.Networks) == 0 { - return nil, nil, errors.New("allocRootlessCNI shall not be called when len(c.config.Networks) == 0") + networks, err := c.networks() + if err != nil { + return nil, nil, err + } + if len(networks) == 0 { + return nil, nil, errors.New("rootless CNI networking requires that the container has joined at least one CNI network") } l, err := getRootlessCNIInfraLock(c.runtime) if err != nil { @@ -54,8 +58,8 @@ func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes. return nil, nil, err } k8sPodName := getCNIPodName(c) // passed to CNI as K8S_POD_NAME - cniResults := make([]*cnitypes.Result, len(c.config.Networks)) - for i, nw := range c.config.Networks { + cniResults := make([]*cnitypes.Result, len(networks)) + for i, nw := range networks { cniRes, err := rootlessCNIInfraCallAlloc(infra, c.ID(), nw, k8sPodName) if err != nil { return nil, nil, err @@ -77,8 +81,12 @@ func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes. // // DeallocRootlessCNI does not lock c. c should be already locked. func DeallocRootlessCNI(ctx context.Context, c *Container) error { - if len(c.config.Networks) == 0 { - return errors.New("deallocRootlessCNI shall not be called when len(c.config.Networks) == 0") + networks, err := c.networks() + if err != nil { + return err + } + if len(networks) == 0 { + return errors.New("rootless CNI networking requires that the container has joined at least one CNI network") } l, err := getRootlessCNIInfraLock(c.runtime) if err != nil { @@ -91,7 +99,7 @@ func DeallocRootlessCNI(ctx context.Context, c *Container) error { return nil } var errs *multierror.Error - for _, nw := range c.config.Networks { + for _, nw := range networks { err := rootlessCNIInfraCallDelloc(infra, c.ID(), nw) if err != nil { errs = multierror.Append(errs, err) diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index c84268889..14b537ca2 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -345,8 +345,15 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai // Lock all named volumes we are adding ourself to, to ensure we can't // use a volume being removed. + volsLocked := make(map[string]bool) for _, namedVol := range ctrNamedVolumes { toLock := namedVol + // Ensure that we don't double-lock a named volume that is used + // more than once. + if volsLocked[namedVol.Name()] { + continue + } + volsLocked[namedVol.Name()] = true toLock.lock.Lock() defer toLock.lock.Unlock() } diff --git a/libpod/state.go b/libpod/state.go index 183f773b5..074d21740 100644 --- a/libpod/state.go +++ b/libpod/state.go @@ -98,20 +98,18 @@ type State interface { // returned. AllContainers() ([]*Container, error) + // Get networks the container is currently connected to. + GetNetworks(ctr *Container) ([]string, error) // Get network aliases for the given container in the given network. GetNetworkAliases(ctr *Container, network string) ([]string, error) // Get all network aliases for the given container. GetAllNetworkAliases(ctr *Container) (map[string][]string, error) - // Set network aliases for the given container in the given network. - SetNetworkAliases(ctr *Container, network string, aliases []string) error - // Remove network aliases for the given container in the given network. - RemoveNetworkAliases(ctr *Container, network string) error - // GetAllAliasesForNetwork returns all the aliases for a given - // network. Returns a map of alias to container ID. - GetAllAliasesForNetwork(network string) (map[string]string, error) - // RemoveAllAliasesForNetwork removes all the aliases for a given - // network. - RemoveAllAliasesForNetwork(network string) error + // Add the container to the given network, adding the given aliases + // (if present). + NetworkConnect(ctr *Container, network string, aliases []string) error + // Remove the container from the given network, removing all aliases for + // the container in that network in the process. + NetworkDisconnect(ctr *Container, network string) error // Return a container config from the database by full ID GetContainerConfig(id string) (*ContainerConfig, error) diff --git a/libpod/state_test.go b/libpod/state_test.go index cf41270bf..da28f3d3f 100644 --- a/libpod/state_test.go +++ b/libpod/state_test.go @@ -1345,224 +1345,6 @@ func TestAddContainerNetworkAliasesButNoMatchingNetwork(t *testing.T) { }) } -func TestAddContainerNetworkAliasConflictWithName(t *testing.T) { - runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) { - testCtr1, err := getTestCtr1(manager) - assert.NoError(t, err) - - netName := "testnet" - testCtr1.config.Networks = []string{netName} - testCtr1.config.NetworkAliases = make(map[string][]string) - testCtr1.config.NetworkAliases[netName] = []string{"alias1"} - - testCtr2, err := getTestCtr2(manager) - assert.NoError(t, err) - - testCtr2.config.Networks = []string{netName} - testCtr2.config.NetworkAliases = make(map[string][]string) - testCtr2.config.NetworkAliases[netName] = []string{testCtr1.Name()} - - err = state.AddContainer(testCtr1) - assert.NoError(t, err) - - err = state.AddContainer(testCtr2) - assert.Error(t, err) - }) -} - -func TestAddContainerNetworkAliasConflictWithAlias(t *testing.T) { - runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) { - testCtr1, err := getTestCtr1(manager) - assert.NoError(t, err) - - netName := "testnet" - aliasName := "alias1" - testCtr1.config.Networks = []string{netName} - testCtr1.config.NetworkAliases = make(map[string][]string) - testCtr1.config.NetworkAliases[netName] = []string{aliasName} - - testCtr2, err := getTestCtr2(manager) - assert.NoError(t, err) - - testCtr2.config.Networks = []string{netName} - testCtr2.config.NetworkAliases = make(map[string][]string) - testCtr2.config.NetworkAliases[netName] = []string{aliasName} - - err = state.AddContainer(testCtr1) - assert.NoError(t, err) - - err = state.AddContainer(testCtr2) - assert.Error(t, err) - }) -} - -func TestAddContainerNetworkAliasConflictWithAliasButDifferentNets(t *testing.T) { - runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) { - testCtr1, err := getTestCtr1(manager) - assert.NoError(t, err) - - netName := "testnet" - aliasName := "alias1" - testCtr1.config.Networks = []string{netName} - testCtr1.config.NetworkAliases = make(map[string][]string) - testCtr1.config.NetworkAliases[netName] = []string{aliasName} - - testCtr2, err := getTestCtr2(manager) - assert.NoError(t, err) - - netName2 := "testnet2" - testCtr2.config.Networks = []string{netName2} - testCtr2.config.NetworkAliases = make(map[string][]string) - testCtr2.config.NetworkAliases[netName2] = []string{aliasName} - - err = state.AddContainer(testCtr1) - assert.NoError(t, err) - - err = state.AddContainer(testCtr2) - assert.NoError(t, err) - }) -} - -func TestAddContainerNameConflictsWithAliasRemovesAlias(t *testing.T) { - runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) { - testCtr1, err := getTestCtr1(manager) - assert.NoError(t, err) - - testCtr2, err := getTestCtr2(manager) - assert.NoError(t, err) - - netName := "testnet" - aliasName := testCtr2.Name() - testCtr1.config.Networks = []string{netName} - testCtr1.config.NetworkAliases = make(map[string][]string) - testCtr1.config.NetworkAliases[netName] = []string{aliasName} - - testCtr2.config.Networks = []string{netName} - - err = state.AddContainer(testCtr1) - assert.NoError(t, err) - - err = state.AddContainer(testCtr2) - assert.NoError(t, err) - - aliases, err := state.GetNetworkAliases(testCtr1, netName) - assert.NoError(t, err) - assert.Equal(t, 0, len(aliases)) - }) -} - -func TestNetworkAliasAddAndRemoveSingleContainer(t *testing.T) { - runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) { - testCtr, err := getTestCtr1(manager) - assert.NoError(t, err) - - netName := "testnet" - testCtr.config.Networks = []string{netName} - testCtr.config.NetworkAliases = make(map[string][]string) - testCtr.config.NetworkAliases[netName] = []string{"alias1"} - - startAliases, err := state.GetAllAliasesForNetwork(netName) - assert.NoError(t, err) - assert.Equal(t, 0, len(startAliases)) - - err = state.AddContainer(testCtr) - assert.NoError(t, err) - - oneAlias, err := state.GetAllAliasesForNetwork(netName) - assert.NoError(t, err) - assert.Equal(t, 1, len(oneAlias)) - assert.Equal(t, testCtr.ID(), oneAlias["alias1"]) - - allAliases, err := state.GetAllNetworkAliases(testCtr) - assert.NoError(t, err) - assert.Equal(t, 1, len(allAliases)) - netAliases, ok := allAliases[netName] - assert.True(t, ok) - assert.Equal(t, 1, len(netAliases)) - assert.Equal(t, "alias1", netAliases[0]) - - ctrNetAliases, err := state.GetNetworkAliases(testCtr, netName) - assert.NoError(t, err) - assert.Equal(t, 1, len(ctrNetAliases)) - assert.Equal(t, "alias1", ctrNetAliases[0]) - - err = state.RemoveContainer(testCtr) - assert.NoError(t, err) - - noAliases, err := state.GetAllAliasesForNetwork(netName) - assert.NoError(t, err) - assert.Equal(t, 0, len(noAliases)) - }) -} - -func TestNetworkAliasAddAndRemoveTwoContainers(t *testing.T) { - runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) { - testCtr1, err := getTestCtr1(manager) - assert.NoError(t, err) - - netName := "testnet" - testCtr1.config.Networks = []string{netName} - testCtr1.config.NetworkAliases = make(map[string][]string) - testCtr1.config.NetworkAliases[netName] = []string{"alias1"} - - testCtr2, err := getTestCtr2(manager) - assert.NoError(t, err) - - testCtr2.config.Networks = []string{netName} - testCtr2.config.NetworkAliases = make(map[string][]string) - testCtr2.config.NetworkAliases[netName] = []string{"alias2"} - - startAliases, err := state.GetAllAliasesForNetwork(netName) - assert.NoError(t, err) - assert.Equal(t, 0, len(startAliases)) - - err = state.AddContainer(testCtr1) - assert.NoError(t, err) - - oneAlias, err := state.GetAllAliasesForNetwork(netName) - assert.NoError(t, err) - assert.Equal(t, 1, len(oneAlias)) - assert.Equal(t, testCtr1.ID(), oneAlias["alias1"]) - - err = state.AddContainer(testCtr2) - assert.NoError(t, err) - - twoAliases, err := state.GetAllAliasesForNetwork(netName) - assert.NoError(t, err) - assert.Equal(t, 2, len(twoAliases)) - assert.Equal(t, testCtr1.ID(), twoAliases["alias1"]) - assert.Equal(t, testCtr2.ID(), twoAliases["alias2"]) - - allAliases, err := state.GetAllNetworkAliases(testCtr1) - assert.NoError(t, err) - assert.Equal(t, 1, len(allAliases)) - netAliases, ok := allAliases[netName] - assert.True(t, ok) - assert.Equal(t, 1, len(netAliases)) - assert.Equal(t, "alias1", netAliases[0]) - - ctrNetAliases, err := state.GetNetworkAliases(testCtr1, netName) - assert.NoError(t, err) - assert.Equal(t, 1, len(ctrNetAliases)) - assert.Equal(t, "alias1", ctrNetAliases[0]) - - err = state.RemoveContainer(testCtr2) - assert.NoError(t, err) - - oneAlias, err = state.GetAllAliasesForNetwork(netName) - assert.NoError(t, err) - assert.Equal(t, 1, len(oneAlias)) - assert.Equal(t, testCtr1.ID(), oneAlias["alias1"]) - - err = state.RemoveContainer(testCtr1) - assert.NoError(t, err) - - noAliases, err := state.GetAllAliasesForNetwork(netName) - assert.NoError(t, err) - assert.Equal(t, 0, len(noAliases)) - }) -} - func TestCannotUseBadIDAsDependency(t *testing.T) { runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) { testCtr, err := getTestCtr1(manager) diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go index f9407df1a..4efe770b3 100644 --- a/pkg/api/handlers/compat/containers_create.go +++ b/pkg/api/handlers/compat/containers_create.go @@ -54,6 +54,9 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { return } + // Add the container name to the input struct + input.Name = query.Name + // Take input structure and convert to cliopts cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(input, rtc.Engine.CgroupManager) if err != nil { @@ -65,6 +68,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "fill out specgen")) return } + ic := abi.ContainerEngine{Libpod: runtime} report, err := ic.ContainerCreate(r.Context(), sg) if err != nil { diff --git a/pkg/api/handlers/compat/unsupported.go b/pkg/api/handlers/compat/unsupported.go index 659c15328..e5ff266f9 100644 --- a/pkg/api/handlers/compat/unsupported.go +++ b/pkg/api/handlers/compat/unsupported.go @@ -14,6 +14,5 @@ func UnsupportedHandler(w http.ResponseWriter, r *http.Request) { msg := fmt.Sprintf("Path %s is not supported", r.URL.Path) log.Infof("Request Failed: %s", msg) - utils.WriteJSON(w, http.StatusInternalServerError, - entities.ErrorModel{Message: msg}) + utils.WriteJSON(w, http.StatusNotFound, entities.ErrorModel{Message: msg}) } diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go index 9f6103c45..78e525f1f 100644 --- a/pkg/api/handlers/libpod/networks.go +++ b/pkg/api/handlers/libpod/networks.go @@ -6,6 +6,7 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" + "github.com/containers/podman/v2/libpod/network" "github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/infra/abi" @@ -31,6 +32,9 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) { errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } + if len(options.Driver) < 1 { + options.Driver = network.DefaultNetworkDriver + } ic := abi.ContainerEngine{Libpod: runtime} report, err := ic.NetworkCreate(r.Context(), query.Name, options) if err != nil { diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go index b81bc9d6b..0c7a6e19d 100644 --- a/pkg/api/handlers/libpod/play.go +++ b/pkg/api/handlers/libpod/play.go @@ -22,6 +22,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) { query := struct { Network string `schema:"reference"` TLSVerify bool `schema:"tlsVerify"` + LogDriver string `schema:"logDriver"` }{ TLSVerify: true, } @@ -62,11 +63,12 @@ func PlayKube(w http.ResponseWriter, r *http.Request) { containerEngine := abi.ContainerEngine{Libpod: runtime} options := entities.PlayKubeOptions{ - Authfile: authfile, - Username: username, - Password: password, - Network: query.Network, - Quiet: true, + Authfile: authfile, + Username: username, + Password: password, + Network: query.Network, + Quiet: true, + LogDriver: query.LogDriver, } if _, found := r.URL.Query()["tlsVerify"]; found { options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) diff --git a/pkg/api/server/register_play.go b/pkg/api/server/register_play.go index 9b27f36e4..e41f8311d 100644 --- a/pkg/api/server/register_play.go +++ b/pkg/api/server/register_play.go @@ -25,6 +25,10 @@ func (s *APIServer) registerPlayHandlers(r *mux.Router) error { // type: boolean // default: true // description: Require HTTPS and verify signatures when contacting registries. + // - in: query + // name: logDriver + // type: string + // description: Logging driver for the containers in the pod. // - in: body // name: request // description: Kubernetes YAML file. diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go index 750a6dbe1..a73517bac 100644 --- a/pkg/bindings/containers/logs.go +++ b/pkg/bindings/containers/logs.go @@ -1,7 +1,6 @@ package containers import ( - "bytes" "context" "fmt" "io" @@ -64,7 +63,6 @@ func Logs(ctx context.Context, nameOrID string, opts LogOptions, stdoutChan, std if err != nil { return err } - frame = bytes.Replace(frame[0:l], []byte{13}, []byte{10}, -1) switch fd { case 0: diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go index ffaee3208..8af3b8fb1 100644 --- a/pkg/bindings/play/play.go +++ b/pkg/bindings/play/play.go @@ -28,6 +28,7 @@ func Kube(ctx context.Context, path string, options entities.PlayKubeOptions) (* params := url.Values{} params.Set("network", options.Network) + params.Set("logDriver", options.LogDriver) if options.SkipTLSVerify != types.OptionalBoolUndefined { params.Set("tlsVerify", strconv.FormatBool(options.SkipTLSVerify == types.OptionalBoolTrue)) } diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go index 0bab672a7..3cc970531 100644 --- a/pkg/domain/entities/network.go +++ b/pkg/domain/entities/network.go @@ -42,6 +42,7 @@ type NetworkCreateOptions struct { MacVLAN string Range net.IPNet Subnet net.IPNet + IPv6 bool } // NetworkCreateReport describes a created network for the cli diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index 356e6869d..7e4afcc28 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -26,6 +26,8 @@ type PlayKubeOptions struct { SeccompProfileRoot string // ConfigMaps - slice of pathnames to kubernetes configmap YAMLs. ConfigMaps []string + // LogDriver for the container. For example: journald + LogDriver string } // PlayKubePod represents a single pod and associated containers created by play kube diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go index d8ad2d891..12135c2b1 100644 --- a/pkg/domain/entities/types.go +++ b/pkg/domain/entities/types.go @@ -32,6 +32,7 @@ type VolumeDeleteReport struct{ Report } // pods and containers type NetOptions struct { AddHosts []string + Aliases []string CNINetworks []string UseImageResolvConf bool DNSOptions []string diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index fbba00984..c0948e099 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -6,29 +6,22 @@ import ( "io" "io/ioutil" "os" - "path/filepath" "strings" "github.com/containers/buildah/pkg/parse" "github.com/containers/image/v5/types" "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/image" - ann "github.com/containers/podman/v2/pkg/annotations" "github.com/containers/podman/v2/pkg/domain/entities" - envLib "github.com/containers/podman/v2/pkg/env" - ns "github.com/containers/podman/v2/pkg/namespaces" - createconfig "github.com/containers/podman/v2/pkg/spec" "github.com/containers/podman/v2/pkg/specgen/generate" + "github.com/containers/podman/v2/pkg/specgen/generate/kube" "github.com/containers/podman/v2/pkg/util" - "github.com/containers/storage" - "github.com/cri-o/ocicni/pkg/ocicni" "github.com/docker/distribution/reference" "github.com/ghodss/yaml" "github.com/pkg/errors" "github.com/sirupsen/logrus" v1apps "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" ) const ( @@ -110,7 +103,6 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { var ( - pod *libpod.Pod registryCreds *types.DockerAuthConfig writer io.Writer playKubePod entities.PlayKubePod @@ -129,49 +121,10 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } } - podOptions := []libpod.PodCreateOption{ - libpod.WithInfraContainer(), - libpod.WithPodName(podName), - } - - if podYAML.ObjectMeta.Labels != nil { - podOptions = append(podOptions, libpod.WithPodLabels(podYAML.ObjectMeta.Labels)) - } - - // TODO we only configure Process namespace. We also need to account for Host{IPC,Network,PID} - // which is not currently possible with pod create - if podYAML.Spec.ShareProcessNamespace != nil && *podYAML.Spec.ShareProcessNamespace { - podOptions = append(podOptions, libpod.WithPodPID()) - } - - hostname := podYAML.Spec.Hostname - if hostname == "" { - hostname = podName - } - podOptions = append(podOptions, libpod.WithPodHostname(hostname)) - - if podYAML.Spec.HostNetwork { - podOptions = append(podOptions, libpod.WithPodHostNetwork()) - } - - if podYAML.Spec.HostAliases != nil { - hosts := make([]string, 0, len(podYAML.Spec.HostAliases)) - for _, hostAlias := range podYAML.Spec.HostAliases { - for _, host := range hostAlias.Hostnames { - hosts = append(hosts, host+":"+hostAlias.IP) - } - } - podOptions = append(podOptions, libpod.WithPodHosts(hosts)) - } - - nsOptions, err := generate.GetNamespaceOptions(strings.Split(createconfig.DefaultKernelNamespaces, ",")) + p, err := kube.ToPodGen(ctx, podName, podYAML) if err != nil { return nil, err } - podOptions = append(podOptions, nsOptions...) - podPorts := getPodPorts(podYAML.Spec.Containers) - podOptions = append(podOptions, libpod.WithInfraContainerPorts(podPorts)) - if options.Network != "" { switch strings.ToLower(options.Network) { case "bridge", "host": @@ -183,12 +136,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY // networks. networks := strings.Split(options.Network, ",") logrus.Debugf("Pod joining CNI networks: %v", networks) - podOptions = append(podOptions, libpod.WithPodNetworks(networks)) + p.CNINetworks = append(p.CNINetworks, networks...) } } // Create the Pod - pod, err = ic.Libpod.NewPod(ctx, podOptions...) + pod, err := generate.MakePod(p, ic.Libpod) if err != nil { return nil, err } @@ -197,29 +150,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if err != nil { return nil, err } - hasUserns := false - if podInfraID != "" { - podCtr, err := ic.Libpod.GetContainer(podInfraID) - if err != nil { - return nil, err - } - mappings, err := podCtr.IDMappings() - if err != nil { - return nil, err - } - hasUserns = len(mappings.UIDMap) > 0 - } - namespaces := map[string]string{ - // Disabled during code review per mheon - //"pid": fmt.Sprintf("container:%s", podInfraID), - "net": fmt.Sprintf("container:%s", podInfraID), - "ipc": fmt.Sprintf("container:%s", podInfraID), - "uts": fmt.Sprintf("container:%s", podInfraID), - } - if hasUserns { - namespaces["user"] = fmt.Sprintf("container:%s", podInfraID) - } if !options.Quiet { writer = os.Stderr } @@ -295,7 +226,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY volumes[volume.Name] = hostPath.Path } - seccompPaths, err := initializeSeccompPaths(podYAML.ObjectMeta.Annotations, options.SeccompProfileRoot) + seccompPaths, err := kube.InitializeSeccompPaths(podYAML.ObjectMeta.Annotations, options.SeccompProfileRoot) if err != nil { return nil, err } @@ -347,28 +278,39 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY pullPolicy = util.PullImageAlways } } + + // This ensures the image is the image store newImage, err := ic.Libpod.ImageRuntime().New(ctx, container.Image, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy) if err != nil { return nil, err } - conf, err := kubeContainerToCreateConfig(ctx, container, newImage, namespaces, volumes, pod.ID(), podName, podInfraID, configMaps, seccompPaths) + + specGen, err := kube.ToSpecGen(ctx, container, container.Image, newImage, volumes, pod.ID(), podName, podInfraID, configMaps, seccompPaths, ctrRestartPolicy) if err != nil { return nil, err } - conf.RestartPolicy = ctrRestartPolicy - ctr, err := createconfig.CreateContainerFromCreateConfig(ctx, ic.Libpod, conf, pod) + + ctr, err := generate.MakeContainer(ctx, ic.Libpod, specGen) if err != nil { return nil, err } containers = append(containers, ctr) } - // start the containers - for _, ctr := range containers { - if err := ctr.Start(ctx, true); err != nil { - // Making this a hard failure here to avoid a mess - // the other containers are in created status - return nil, err + //start the containers + podStartErrors, err := pod.Start(ctx) + if err != nil { + return nil, err + } + + // Previous versions of playkube started containers individually and then + // looked for errors. Because we now use the uber-Pod start call, we should + // iterate the map of possible errors and return one if there is a problem. This + // keeps the behavior the same + + for _, e := range podStartErrors { + if e != nil { + return nil, e } } @@ -382,264 +324,6 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY return &report, nil } -// getPodPorts converts a slice of kube container descriptions to an -// array of ocicni portmapping descriptions usable in libpod -func getPodPorts(containers []v1.Container) []ocicni.PortMapping { - var infraPorts []ocicni.PortMapping - for _, container := range containers { - for _, p := range container.Ports { - if p.HostPort != 0 && p.ContainerPort == 0 { - p.ContainerPort = p.HostPort - } - if p.Protocol == "" { - p.Protocol = "tcp" - } - portBinding := ocicni.PortMapping{ - HostPort: p.HostPort, - ContainerPort: p.ContainerPort, - Protocol: strings.ToLower(string(p.Protocol)), - HostIP: p.HostIP, - } - // only hostPort is utilized in podman context, all container ports - // are accessible inside the shared network namespace - if p.HostPort != 0 { - infraPorts = append(infraPorts, portBinding) - } - - } - } - return infraPorts -} - -func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfig *createconfig.UserConfig, containerYAML v1.Container) { - if containerYAML.SecurityContext == nil { - return - } - if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil { - securityConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem - } - if containerYAML.SecurityContext.Privileged != nil { - securityConfig.Privileged = *containerYAML.SecurityContext.Privileged - } - - if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil { - securityConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation - } - - if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil { - if seopt.User != "" { - securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User)) - securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User)) - } - if seopt.Role != "" { - securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role)) - securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role)) - } - if seopt.Type != "" { - securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type)) - securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type)) - } - if seopt.Level != "" { - securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level)) - securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level)) - } - } - if caps := containerYAML.SecurityContext.Capabilities; caps != nil { - for _, capability := range caps.Add { - securityConfig.CapAdd = append(securityConfig.CapAdd, string(capability)) - } - for _, capability := range caps.Drop { - securityConfig.CapDrop = append(securityConfig.CapDrop, string(capability)) - } - } - if containerYAML.SecurityContext.RunAsUser != nil { - userConfig.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser) - } - if containerYAML.SecurityContext.RunAsGroup != nil { - if userConfig.User == "" { - userConfig.User = "0" - } - userConfig.User = fmt.Sprintf("%s:%d", userConfig.User, *containerYAML.SecurityContext.RunAsGroup) - } -} - -// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container -func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) { - var ( - containerConfig createconfig.CreateConfig - pidConfig createconfig.PidConfig - networkConfig createconfig.NetworkConfig - cgroupConfig createconfig.CgroupConfig - utsConfig createconfig.UtsConfig - ipcConfig createconfig.IpcConfig - userConfig createconfig.UserConfig - securityConfig createconfig.SecurityConfig - ) - - // The default for MemorySwappiness is -1, not 0 - containerConfig.Resources.MemorySwappiness = -1 - - containerConfig.Image = containerYAML.Image - containerConfig.ImageID = newImage.ID() - - // podName should be non-empty for Deployment objects to be able to create - // multiple pods having containers with unique names - if podName == "" { - return nil, errors.Errorf("kubeContainerToCreateConfig got empty podName") - } - containerConfig.Name = fmt.Sprintf("%s-%s", podName, containerYAML.Name) - - containerConfig.Tty = containerYAML.TTY - - containerConfig.Pod = podID - - imageData, _ := newImage.Inspect(ctx) - - userConfig.User = "0" - if imageData != nil { - userConfig.User = imageData.Config.User - } - - setupSecurityContext(&securityConfig, &userConfig, containerYAML) - - // Since we prefix the container name with pod name to work-around the uniqueness requirement, - // the seccom profile should reference the actual container name from the YAML - // but apply to the containers with the prefixed name - securityConfig.SeccompProfilePath = seccompPaths.findForContainer(containerYAML.Name) - - var err error - milliCPU, err := quantityToInt64(containerYAML.Resources.Limits.Cpu()) - if err != nil { - return nil, errors.Wrap(err, "Failed to set CPU quota") - } - if milliCPU > 0 { - period, quota := util.CoresToPeriodAndQuota(float64(milliCPU) / 1000) - containerConfig.Resources.CPUPeriod = period - containerConfig.Resources.CPUQuota = quota - } - - containerConfig.Resources.Memory, err = quantityToInt64(containerYAML.Resources.Limits.Memory()) - if err != nil { - return nil, errors.Wrap(err, "Failed to set memory limit") - } - containerConfig.Resources.MemoryReservation, err = quantityToInt64(containerYAML.Resources.Requests.Memory()) - if err != nil { - return nil, errors.Wrap(err, "Failed to set memory reservation") - } - - containerConfig.Command = []string{} - if imageData != nil && imageData.Config != nil { - containerConfig.Command = imageData.Config.Entrypoint - } - if len(containerYAML.Command) != 0 { - containerConfig.Command = containerYAML.Command - } - // doc https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes - if len(containerYAML.Args) != 0 { - containerConfig.Command = append(containerConfig.Command, containerYAML.Args...) - } else if len(containerYAML.Command) == 0 { - // Add the Cmd from the image config only if containerYAML.Command and containerYAML.Args are empty - containerConfig.Command = append(containerConfig.Command, imageData.Config.Cmd...) - } - if imageData != nil && len(containerConfig.Command) == 0 { - return nil, errors.Errorf("No command specified in container YAML or as CMD or ENTRYPOINT in this image for %s", containerConfig.Name) - } - - containerConfig.UserCommand = containerConfig.Command - - containerConfig.StopSignal = 15 - - containerConfig.WorkDir = "/" - if imageData != nil { - // FIXME, - // we are currently ignoring imageData.Config.ExposedPorts - containerConfig.BuiltinImgVolumes = imageData.Config.Volumes - if imageData.Config.WorkingDir != "" { - containerConfig.WorkDir = imageData.Config.WorkingDir - } - containerConfig.Labels = imageData.Config.Labels - if imageData.Config.StopSignal != "" { - stopSignal, err := util.ParseSignal(imageData.Config.StopSignal) - if err != nil { - return nil, err - } - containerConfig.StopSignal = stopSignal - } - } - - if containerYAML.WorkingDir != "" { - containerConfig.WorkDir = containerYAML.WorkingDir - } - // If the user does not pass in ID mappings, just set to basics - if userConfig.IDMappings == nil { - userConfig.IDMappings = &storage.IDMappingOptions{} - } - - networkConfig.NetMode = ns.NetworkMode(namespaces["net"]) - ipcConfig.IpcMode = ns.IpcMode(namespaces["ipc"]) - utsConfig.UtsMode = ns.UTSMode(namespaces["uts"]) - // disabled in code review per mheon - //containerConfig.PidMode = ns.PidMode(namespaces["pid"]) - userConfig.UsernsMode = ns.UsernsMode(namespaces["user"]) - if len(containerConfig.WorkDir) == 0 { - containerConfig.WorkDir = "/" - } - - containerConfig.Pid = pidConfig - containerConfig.Network = networkConfig - containerConfig.Uts = utsConfig - containerConfig.Ipc = ipcConfig - containerConfig.Cgroup = cgroupConfig - containerConfig.User = userConfig - containerConfig.Security = securityConfig - - annotations := make(map[string]string) - if infraID != "" { - annotations[ann.SandboxID] = infraID - annotations[ann.ContainerType] = ann.ContainerTypeContainer - } - containerConfig.Annotations = annotations - - // Environment Variables - envs := map[string]string{} - if imageData != nil { - imageEnv, err := envLib.ParseSlice(imageData.Config.Env) - if err != nil { - return nil, errors.Wrap(err, "error parsing image environment variables") - } - envs = imageEnv - } - for _, env := range containerYAML.Env { - value := envVarValue(env, configMaps) - - envs[env.Name] = value - } - for _, envFrom := range containerYAML.EnvFrom { - cmEnvs := envVarsFromConfigMap(envFrom, configMaps) - - for k, v := range cmEnvs { - envs[k] = v - } - } - containerConfig.Env = envs - - for _, volume := range containerYAML.VolumeMounts { - var readonly string - hostPath, exists := volumes[volume.Name] - if !exists { - return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name) - } - if err := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil { - return nil, errors.Wrapf(err, "error in parsing MountPath") - } - if volume.ReadOnly { - readonly = ":ro" - } - containerConfig.Volumes = append(containerConfig.Volumes, fmt.Sprintf("%s:%s%s", hostPath, volume.MountPath, readonly)) - } - return &containerConfig, nil -} - // readConfigMapFromFile returns a kubernetes configMap obtained from --configmap flag func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) { var cm v1.ConfigMap @@ -659,125 +343,3 @@ func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) { return cm, nil } - -// envVarsFromConfigMap returns all key-value pairs as env vars from a configMap that matches the envFrom setting of a container -func envVarsFromConfigMap(envFrom v1.EnvFromSource, configMaps []v1.ConfigMap) map[string]string { - envs := map[string]string{} - - if envFrom.ConfigMapRef != nil { - cmName := envFrom.ConfigMapRef.Name - - for _, c := range configMaps { - if cmName == c.Name { - envs = c.Data - break - } - } - } - - return envs -} - -// envVarValue returns the environment variable value configured within the container's env setting. -// It gets the value from a configMap if specified, otherwise returns env.Value -func envVarValue(env v1.EnvVar, configMaps []v1.ConfigMap) string { - for _, c := range configMaps { - if env.ValueFrom != nil { - if env.ValueFrom.ConfigMapKeyRef != nil { - if env.ValueFrom.ConfigMapKeyRef.Name == c.Name { - if value, ok := c.Data[env.ValueFrom.ConfigMapKeyRef.Key]; ok { - return value - } - } - } - } - } - - return env.Value -} - -// kubeSeccompPaths holds information about a pod YAML's seccomp configuration -// it holds both container and pod seccomp paths -type kubeSeccompPaths struct { - containerPaths map[string]string - podPath string -} - -// findForContainer checks whether a container has a seccomp path configured for it -// if not, it returns the podPath, which should always have a value -func (k *kubeSeccompPaths) findForContainer(ctrName string) string { - if path, ok := k.containerPaths[ctrName]; ok { - return path - } - return k.podPath -} - -// initializeSeccompPaths takes annotations from the pod object metadata and finds annotations pertaining to seccomp -// it parses both pod and container level -// if the annotation is of the form "localhost/%s", the seccomp profile will be set to profileRoot/%s -func initializeSeccompPaths(annotations map[string]string, profileRoot string) (*kubeSeccompPaths, error) { - seccompPaths := &kubeSeccompPaths{containerPaths: make(map[string]string)} - var err error - if annotations != nil { - for annKeyValue, seccomp := range annotations { - // check if it is prefaced with container.seccomp.security.alpha.kubernetes.io/ - prefixAndCtr := strings.Split(annKeyValue, "/") - if prefixAndCtr[0]+"/" != v1.SeccompContainerAnnotationKeyPrefix { - continue - } else if len(prefixAndCtr) != 2 { - // this could be caused by a user inputting either of - // container.seccomp.security.alpha.kubernetes.io{,/} - // both of which are invalid - return nil, errors.Errorf("Invalid seccomp path: %s", prefixAndCtr[0]) - } - - path, err := verifySeccompPath(seccomp, profileRoot) - if err != nil { - return nil, err - } - seccompPaths.containerPaths[prefixAndCtr[1]] = path - } - - podSeccomp, ok := annotations[v1.SeccompPodAnnotationKey] - if ok { - seccompPaths.podPath, err = verifySeccompPath(podSeccomp, profileRoot) - } else { - seccompPaths.podPath, err = libpod.DefaultSeccompPath() - } - if err != nil { - return nil, err - } - } - return seccompPaths, nil -} - -// verifySeccompPath takes a path and checks whether it is a default, unconfined, or a path -// the available options are parsed as defined in https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp -func verifySeccompPath(path string, profileRoot string) (string, error) { - switch path { - case v1.DeprecatedSeccompProfileDockerDefault: - fallthrough - case v1.SeccompProfileRuntimeDefault: - return libpod.DefaultSeccompPath() - case "unconfined": - return path, nil - default: - parts := strings.Split(path, "/") - if parts[0] == "localhost" { - return filepath.Join(profileRoot, parts[1]), nil - } - return "", errors.Errorf("invalid seccomp path: %s", path) - } -} - -func quantityToInt64(quantity *resource.Quantity) (int64, error) { - if i, ok := quantity.AsInt64(); ok { - return i, nil - } - - if i, ok := quantity.AsDec().Unscaled(); ok { - return i, nil - } - - return 0, errors.Errorf("Quantity cannot be represented as int64: %v", quantity) -} diff --git a/pkg/domain/infra/abi/play_test.go b/pkg/domain/infra/abi/play_test.go index 5595476c3..4354a3835 100644 --- a/pkg/domain/infra/abi/play_test.go +++ b/pkg/domain/infra/abi/play_test.go @@ -6,34 +6,9 @@ import ( "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v12 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -var configMapList = []v1.ConfigMap{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - }, - Data: map[string]string{ - "myvar": "bar", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Data: map[string]string{ - "myvar": "foo", - }, - }, -} - func TestReadConfigMapFromFile(t *testing.T) { tests := []struct { name string @@ -55,11 +30,11 @@ data: false, "", v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ + TypeMeta: v12.TypeMeta{ Kind: "ConfigMap", APIVersion: "v1", }, - ObjectMeta: metav1.ObjectMeta{ + ObjectMeta: v12.ObjectMeta{ Name: "foo", }, Data: map[string]string{ @@ -114,141 +89,3 @@ data: }) } } - -func TestEnvVarsFromConfigMap(t *testing.T) { - tests := []struct { - name string - envFrom v1.EnvFromSource - configMapList []v1.ConfigMap - expected map[string]string - }{ - { - "ConfigMapExists", - v1.EnvFromSource{ - ConfigMapRef: &v1.ConfigMapEnvSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "foo", - }, - }, - }, - configMapList, - map[string]string{ - "myvar": "foo", - }, - }, - { - "ConfigMapDoesNotExist", - v1.EnvFromSource{ - ConfigMapRef: &v1.ConfigMapEnvSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "doesnotexist", - }, - }, - }, - configMapList, - map[string]string{}, - }, - { - "EmptyConfigMapList", - v1.EnvFromSource{ - ConfigMapRef: &v1.ConfigMapEnvSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "foo", - }, - }, - }, - []v1.ConfigMap{}, - map[string]string{}, - }, - } - - for _, test := range tests { - test := test - t.Run(test.name, func(t *testing.T) { - result := envVarsFromConfigMap(test.envFrom, test.configMapList) - assert.Equal(t, test.expected, result) - }) - } -} - -func TestEnvVarValue(t *testing.T) { - tests := []struct { - name string - envVar v1.EnvVar - configMapList []v1.ConfigMap - expected string - }{ - { - "ConfigMapExists", - v1.EnvVar{ - Name: "FOO", - ValueFrom: &v1.EnvVarSource{ - ConfigMapKeyRef: &v1.ConfigMapKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "foo", - }, - Key: "myvar", - }, - }, - }, - configMapList, - "foo", - }, - { - "ContainerKeyDoesNotExistInConfigMap", - v1.EnvVar{ - Name: "FOO", - ValueFrom: &v1.EnvVarSource{ - ConfigMapKeyRef: &v1.ConfigMapKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "foo", - }, - Key: "doesnotexist", - }, - }, - }, - configMapList, - "", - }, - { - "ConfigMapDoesNotExist", - v1.EnvVar{ - Name: "FOO", - ValueFrom: &v1.EnvVarSource{ - ConfigMapKeyRef: &v1.ConfigMapKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "doesnotexist", - }, - Key: "myvar", - }, - }, - }, - configMapList, - "", - }, - { - "EmptyConfigMapList", - v1.EnvVar{ - Name: "FOO", - ValueFrom: &v1.EnvVarSource{ - ConfigMapKeyRef: &v1.ConfigMapKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "foo", - }, - Key: "myvar", - }, - }, - }, - []v1.ConfigMap{}, - "", - }, - } - - for _, test := range tests { - test := test - t.Run(test.name, func(t *testing.T) { - result := envVarValue(test.envVar, test.configMapList) - assert.Equal(t, test.expected, result) - }) - } -} diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 53dc35df1..c049e64cf 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -133,6 +133,10 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener } options = append(options, libpod.WithExitCommand(exitCommandArgs)) + if len(s.Aliases) > 0 { + options = append(options, libpod.WithNetworkAliases(s.Aliases)) + } + runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command) if err != nil { return nil, err diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go new file mode 100644 index 000000000..e1202956c --- /dev/null +++ b/pkg/specgen/generate/kube/kube.go @@ -0,0 +1,312 @@ +package kube + +import ( + "context" + "fmt" + "strings" + + "github.com/containers/buildah/pkg/parse" + "github.com/containers/podman/v2/libpod/image" + ann "github.com/containers/podman/v2/pkg/annotations" + "github.com/containers/podman/v2/pkg/specgen" + "github.com/containers/podman/v2/pkg/util" + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" +) + +func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec) (*specgen.PodSpecGenerator, error) { + p := specgen.NewPodSpecGenerator() + p.Name = podName + p.Labels = podYAML.ObjectMeta.Labels + // TODO we only configure Process namespace. We also need to account for Host{IPC,Network,PID} + // which is not currently possible with pod create + if podYAML.Spec.ShareProcessNamespace != nil && *podYAML.Spec.ShareProcessNamespace { + p.SharedNamespaces = append(p.SharedNamespaces, "pid") + } + p.Hostname = podYAML.Spec.Hostname + if p.Hostname == "" { + p.Hostname = podName + } + if podYAML.Spec.HostNetwork { + p.NetNS.Value = "host" + } + if podYAML.Spec.HostAliases != nil { + hosts := make([]string, 0, len(podYAML.Spec.HostAliases)) + for _, hostAlias := range podYAML.Spec.HostAliases { + for _, host := range hostAlias.Hostnames { + hosts = append(hosts, host+":"+hostAlias.IP) + } + } + p.HostAdd = hosts + } + podPorts := getPodPorts(podYAML.Spec.Containers) + p.PortMappings = podPorts + + return p, nil +} + +func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newImage *image.Image, volumes map[string]string, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *KubeSeccompPaths, restartPolicy string) (*specgen.SpecGenerator, error) { + s := specgen.NewSpecGenerator(iid, false) + + // podName should be non-empty for Deployment objects to be able to create + // multiple pods having containers with unique names + if len(podName) < 1 { + return nil, errors.Errorf("kubeContainerToCreateConfig got empty podName") + } + + s.Name = fmt.Sprintf("%s-%s", podName, containerYAML.Name) + + s.Terminal = containerYAML.TTY + + s.Pod = podID + + setupSecurityContext(s, containerYAML) + + // Since we prefix the container name with pod name to work-around the uniqueness requirement, + // the seccomp profile should reference the actual container name from the YAML + // but apply to the containers with the prefixed name + s.SeccompProfilePath = seccompPaths.FindForContainer(containerYAML.Name) + + s.ResourceLimits = &spec.LinuxResources{} + milliCPU, err := quantityToInt64(containerYAML.Resources.Limits.Cpu()) + if err != nil { + return nil, errors.Wrap(err, "Failed to set CPU quota") + } + if milliCPU > 0 { + period, quota := util.CoresToPeriodAndQuota(float64(milliCPU) / 1000) + s.ResourceLimits.CPU = &spec.LinuxCPU{ + Quota: "a, + Period: &period, + } + } + + limit, err := quantityToInt64(containerYAML.Resources.Limits.Memory()) + if err != nil { + return nil, errors.Wrap(err, "Failed to set memory limit") + } + + memoryRes, err := quantityToInt64(containerYAML.Resources.Requests.Memory()) + if err != nil { + return nil, errors.Wrap(err, "Failed to set memory reservation") + } + + if limit > 0 || memoryRes > 0 { + s.ResourceLimits.Memory = &spec.LinuxMemory{} + } + + if limit > 0 { + s.ResourceLimits.Memory.Limit = &limit + } + + if memoryRes > 0 { + s.ResourceLimits.Memory.Reservation = &memoryRes + } + + // TODO: We dont understand why specgen does not take of this, but + // integration tests clearly pointed out that it was required. + s.Command = []string{} + imageData, err := newImage.Inspect(ctx) + if err != nil { + return nil, err + } + s.WorkDir = "/" + if imageData != nil && imageData.Config != nil { + if imageData.Config.WorkingDir != "" { + s.WorkDir = imageData.Config.WorkingDir + } + s.Command = imageData.Config.Entrypoint + s.Labels = imageData.Config.Labels + if len(imageData.Config.StopSignal) > 0 { + stopSignal, err := util.ParseSignal(imageData.Config.StopSignal) + if err != nil { + return nil, err + } + s.StopSignal = &stopSignal + } + } + if len(containerYAML.Command) != 0 { + s.Command = containerYAML.Command + } + // doc https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes + if len(containerYAML.Args) != 0 { + s.Command = append(s.Command, containerYAML.Args...) + } + // FIXME, + // we are currently ignoring imageData.Config.ExposedPorts + if containerYAML.WorkingDir != "" { + s.WorkDir = containerYAML.WorkingDir + } + + annotations := make(map[string]string) + if infraID != "" { + annotations[ann.SandboxID] = infraID + annotations[ann.ContainerType] = ann.ContainerTypeContainer + } + s.Annotations = annotations + + // Environment Variables + envs := map[string]string{} + for _, env := range containerYAML.Env { + value := envVarValue(env, configMaps) + + envs[env.Name] = value + } + for _, envFrom := range containerYAML.EnvFrom { + cmEnvs := envVarsFromConfigMap(envFrom, configMaps) + + for k, v := range cmEnvs { + envs[k] = v + } + } + s.Env = envs + + for _, volume := range containerYAML.VolumeMounts { + hostPath, exists := volumes[volume.Name] + if !exists { + return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name) + } + if err := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil { + return nil, errors.Wrapf(err, "error in parsing MountPath") + } + mount := spec.Mount{ + Destination: volume.MountPath, + Source: hostPath, + Type: "bind", + } + if volume.ReadOnly { + mount.Options = []string{"ro"} + } + s.Mounts = append(s.Mounts, mount) + } + + s.RestartPolicy = restartPolicy + + return s, nil +} + +func setupSecurityContext(s *specgen.SpecGenerator, containerYAML v1.Container) { + if containerYAML.SecurityContext == nil { + return + } + if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil { + s.ReadOnlyFilesystem = *containerYAML.SecurityContext.ReadOnlyRootFilesystem + } + if containerYAML.SecurityContext.Privileged != nil { + s.Privileged = *containerYAML.SecurityContext.Privileged + } + + if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil { + s.NoNewPrivileges = !*containerYAML.SecurityContext.AllowPrivilegeEscalation + } + + if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil { + if seopt.User != "" { + s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("role:%s", seopt.User)) + } + if seopt.Role != "" { + s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("role:%s", seopt.Role)) + } + if seopt.Type != "" { + s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("role:%s", seopt.Type)) + } + if seopt.Level != "" { + s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("role:%s", seopt.Level)) + } + } + if caps := containerYAML.SecurityContext.Capabilities; caps != nil { + for _, capability := range caps.Add { + s.CapAdd = append(s.CapAdd, string(capability)) + } + for _, capability := range caps.Drop { + s.CapDrop = append(s.CapDrop, string(capability)) + } + } + if containerYAML.SecurityContext.RunAsUser != nil { + s.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser) + } + if containerYAML.SecurityContext.RunAsGroup != nil { + if s.User == "" { + s.User = "0" + } + s.User = fmt.Sprintf("%s:%d", s.User, *containerYAML.SecurityContext.RunAsGroup) + } +} + +func quantityToInt64(quantity *resource.Quantity) (int64, error) { + if i, ok := quantity.AsInt64(); ok { + return i, nil + } + + if i, ok := quantity.AsDec().Unscaled(); ok { + return i, nil + } + + return 0, errors.Errorf("Quantity cannot be represented as int64: %v", quantity) +} + +// envVarsFromConfigMap returns all key-value pairs as env vars from a configMap that matches the envFrom setting of a container +func envVarsFromConfigMap(envFrom v1.EnvFromSource, configMaps []v1.ConfigMap) map[string]string { + envs := map[string]string{} + + if envFrom.ConfigMapRef != nil { + cmName := envFrom.ConfigMapRef.Name + + for _, c := range configMaps { + if cmName == c.Name { + envs = c.Data + break + } + } + } + + return envs +} + +// envVarValue returns the environment variable value configured within the container's env setting. +// It gets the value from a configMap if specified, otherwise returns env.Value +func envVarValue(env v1.EnvVar, configMaps []v1.ConfigMap) string { + for _, c := range configMaps { + if env.ValueFrom != nil { + if env.ValueFrom.ConfigMapKeyRef != nil { + if env.ValueFrom.ConfigMapKeyRef.Name == c.Name { + if value, ok := c.Data[env.ValueFrom.ConfigMapKeyRef.Key]; ok { + return value + } + } + } + } + } + + return env.Value +} + +// getPodPorts converts a slice of kube container descriptions to an +// array of portmapping +func getPodPorts(containers []v1.Container) []specgen.PortMapping { + var infraPorts []specgen.PortMapping + for _, container := range containers { + for _, p := range container.Ports { + if p.HostPort != 0 && p.ContainerPort == 0 { + p.ContainerPort = p.HostPort + } + if p.Protocol == "" { + p.Protocol = "tcp" + } + portBinding := specgen.PortMapping{ + HostPort: uint16(p.HostPort), + ContainerPort: uint16(p.ContainerPort), + Protocol: strings.ToLower(string(p.Protocol)), + HostIP: p.HostIP, + } + // only hostPort is utilized in podman context, all container ports + // are accessible inside the shared network namespace + if p.HostPort != 0 { + infraPorts = append(infraPorts, portBinding) + } + + } + } + return infraPorts +} diff --git a/pkg/specgen/generate/kube/play_test.go b/pkg/specgen/generate/kube/play_test.go new file mode 100644 index 000000000..148540e9f --- /dev/null +++ b/pkg/specgen/generate/kube/play_test.go @@ -0,0 +1,172 @@ +package kube + +import ( + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + v12 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestEnvVarsFromConfigMap(t *testing.T) { + tests := []struct { + name string + envFrom v1.EnvFromSource + configMapList []v1.ConfigMap + expected map[string]string + }{ + { + "ConfigMapExists", + v1.EnvFromSource{ + ConfigMapRef: &v1.ConfigMapEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + }, + }, + configMapList, + map[string]string{ + "myvar": "foo", + }, + }, + { + "ConfigMapDoesNotExist", + v1.EnvFromSource{ + ConfigMapRef: &v1.ConfigMapEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "doesnotexist", + }, + }, + }, + configMapList, + map[string]string{}, + }, + { + "EmptyConfigMapList", + v1.EnvFromSource{ + ConfigMapRef: &v1.ConfigMapEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + }, + }, + []v1.ConfigMap{}, + map[string]string{}, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + result := envVarsFromConfigMap(test.envFrom, test.configMapList) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestEnvVarValue(t *testing.T) { + tests := []struct { + name string + envVar v1.EnvVar + configMapList []v1.ConfigMap + expected string + }{ + { + "ConfigMapExists", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + ConfigMapKeyRef: &v1.ConfigMapKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + Key: "myvar", + }, + }, + }, + configMapList, + "foo", + }, + { + "ContainerKeyDoesNotExistInConfigMap", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + ConfigMapKeyRef: &v1.ConfigMapKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + Key: "doesnotexist", + }, + }, + }, + configMapList, + "", + }, + { + "ConfigMapDoesNotExist", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + ConfigMapKeyRef: &v1.ConfigMapKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "doesnotexist", + }, + Key: "myvar", + }, + }, + }, + configMapList, + "", + }, + { + "EmptyConfigMapList", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + ConfigMapKeyRef: &v1.ConfigMapKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + Key: "myvar", + }, + }, + }, + []v1.ConfigMap{}, + "", + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + result := envVarValue(test.envVar, test.configMapList) + assert.Equal(t, test.expected, result) + }) + } +} + +var configMapList = []v1.ConfigMap{ + { + TypeMeta: v12.TypeMeta{ + Kind: "ConfigMap", + }, + ObjectMeta: v12.ObjectMeta{ + Name: "bar", + }, + Data: map[string]string{ + "myvar": "bar", + }, + }, + { + TypeMeta: v12.TypeMeta{ + Kind: "ConfigMap", + }, + ObjectMeta: v12.ObjectMeta{ + Name: "foo", + }, + Data: map[string]string{ + "myvar": "foo", + }, + }, +} diff --git a/pkg/specgen/generate/kube/seccomp.go b/pkg/specgen/generate/kube/seccomp.go new file mode 100644 index 000000000..4cbdf6e2e --- /dev/null +++ b/pkg/specgen/generate/kube/seccomp.go @@ -0,0 +1,84 @@ +package kube + +import ( + "path/filepath" + "strings" + + "github.com/containers/podman/v2/libpod" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" +) + +// KubeSeccompPaths holds information about a pod YAML's seccomp configuration +// it holds both container and pod seccomp paths +type KubeSeccompPaths struct { + containerPaths map[string]string + podPath string +} + +// FindForContainer checks whether a container has a seccomp path configured for it +// if not, it returns the podPath, which should always have a value +func (k *KubeSeccompPaths) FindForContainer(ctrName string) string { + if path, ok := k.containerPaths[ctrName]; ok { + return path + } + return k.podPath +} + +// InitializeSeccompPaths takes annotations from the pod object metadata and finds annotations pertaining to seccomp +// it parses both pod and container level +// if the annotation is of the form "localhost/%s", the seccomp profile will be set to profileRoot/%s +func InitializeSeccompPaths(annotations map[string]string, profileRoot string) (*KubeSeccompPaths, error) { + seccompPaths := &KubeSeccompPaths{containerPaths: make(map[string]string)} + var err error + if annotations != nil { + for annKeyValue, seccomp := range annotations { + // check if it is prefaced with container.seccomp.security.alpha.kubernetes.io/ + prefixAndCtr := strings.Split(annKeyValue, "/") + if prefixAndCtr[0]+"/" != v1.SeccompContainerAnnotationKeyPrefix { + continue + } else if len(prefixAndCtr) != 2 { + // this could be caused by a user inputting either of + // container.seccomp.security.alpha.kubernetes.io{,/} + // both of which are invalid + return nil, errors.Errorf("Invalid seccomp path: %s", prefixAndCtr[0]) + } + + path, err := verifySeccompPath(seccomp, profileRoot) + if err != nil { + return nil, err + } + seccompPaths.containerPaths[prefixAndCtr[1]] = path + } + + podSeccomp, ok := annotations[v1.SeccompPodAnnotationKey] + if ok { + seccompPaths.podPath, err = verifySeccompPath(podSeccomp, profileRoot) + } else { + seccompPaths.podPath, err = libpod.DefaultSeccompPath() + } + if err != nil { + return nil, err + } + } + return seccompPaths, nil +} + +// verifySeccompPath takes a path and checks whether it is a default, unconfined, or a path +// the available options are parsed as defined in https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp +func verifySeccompPath(path string, profileRoot string) (string, error) { + switch path { + case v1.DeprecatedSeccompProfileDockerDefault: + fallthrough + case v1.SeccompProfileRuntimeDefault: + return libpod.DefaultSeccompPath() + case "unconfined": + return path, nil + default: + parts := strings.Split(path, "/") + if parts[0] == "localhost" { + return filepath.Join(profileRoot, parts[1]), nil + } + return "", errors.Errorf("invalid seccomp path: %s", path) + } +} diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index d68f55402..0a9a16ea7 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -328,6 +328,9 @@ type ContainerCgroupConfig struct { // ContainerNetworkConfig contains information on a container's network // configuration. type ContainerNetworkConfig struct { + // Aliases are a list of network-scoped aliases for container + // Optional + Aliases map[string][]string `json:"aliases"` // NetNS is the configuration to use for the container's network // namespace. // Mandatory. diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at index 72c63207d..ad34511c7 100644 --- a/test/apiv2/35-networks.at +++ b/test/apiv2/35-networks.at @@ -6,52 +6,48 @@ t GET networks/non-existing-network 404 \ .cause='network not found' -# FIXME FIXME FIXME: failing in CI. Deferring to someone else to fix later. -#if root; then -if false; then - t POST libpod/networks/create?name=network1 '' 200 \ - .Filename~.*/network1\\.conflist - - # --data '{"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]}}' - t POST libpod/networks/create?name=network2 '"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]}' 200 \ - .Filename~.*/network2\\.conflist - - # test for empty mask - t POST libpod/networks/create '"Subnet":{"IP":"10.10.1.0","Mask":[]}' 500 \ - .cause~'.*cannot be empty' - # test for invalid mask - t POST libpod/networks/create '"Subnet":{"IP":"10.10.1.0","Mask":[0,255,255,0]}' 500 \ - .cause~'.*mask is invalid' - - # network list - t GET libpod/networks/json 200 - t GET libpod/networks/json?filter=name=network1 200 \ - length=1 \ - .[0].Name=network1 - t GET networks 200 - - #network list docker endpoint - #filters={"name":["network1","network2"]} - t GET networks?filters=%7B%22name%22%3A%5B%22network1%22%2C%22network2%22%5D%7D 200 \ - length=2 - #filters={"name":["network"]} - t GET networks?filters=%7B%22name%22%3A%5B%22network%22%5D%7D 200 \ - length=2 - # invalid filter filters={"label":"abc"} - t GET networks?filters=%7B%22label%22%3A%5B%22abc%22%5D%7D 500 \ - .cause="only the name filter for listing networks is implemented" - # invalid filter filters={"label":"abc","name":["network"]} - t GET networks?filters=%7B%22label%22%3A%22abc%22%2C%22name%22%3A%5B%22network%22%5D%7D 500 \ - .cause="only the name filter for listing networks is implemented" - - # clean the network - t DELETE libpod/networks/network1 200 \ - .[0].Name~network1 \ - .[0].Err=null - t DELETE libpod/networks/network2 200 \ - .[0].Name~network2 \ - .[0].Err=null - -fi +t POST libpod/networks/create?name=network1 '' 200 \ +.Filename~.*/network1\\.conflist + +# --data '{"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]}}' +t POST libpod/networks/create?name=network2 '"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]}' 200 \ +.Filename~.*/network2\\.conflist + +# test for empty mask +t POST libpod/networks/create '"Subnet":{"IP":"10.10.1.0","Mask":[]}' 500 \ +.cause~'.*cannot be empty' +# test for invalid mask +t POST libpod/networks/create '"Subnet":{"IP":"10.10.1.0","Mask":[0,255,255,0]}' 500 \ +.cause~'.*mask is invalid' + +# network list +t GET libpod/networks/json 200 +t GET libpod/networks/json?filter=name=network1 200 \ +length=1 \ +.[0].Name=network1 +t GET networks 200 + +#network list docker endpoint +#filters={"name":["network1","network2"]} +t GET networks?filters=%7B%22name%22%3A%5B%22network1%22%2C%22network2%22%5D%7D 200 \ +length=2 +#filters={"name":["network"]} +t GET networks?filters=%7B%22name%22%3A%5B%22network%22%5D%7D 200 \ +length=2 +# invalid filter filters={"label":"abc"} +t GET networks?filters=%7B%22label%22%3A%5B%22abc%22%5D%7D 500 \ +.cause="only the name filter for listing networks is implemented" +# invalid filter filters={"label":"abc","name":["network"]} +t GET networks?filters=%7B%22label%22%3A%22abc%22%2C%22name%22%3A%5B%22network%22%5D%7D 500 \ +.cause="only the name filter for listing networks is implemented" + +# clean the network +t DELETE libpod/networks/network1 200 \ +.[0].Name~network1 \ +.[0].Err=null +t DELETE libpod/networks/network2 200 \ +.[0].Name~network2 \ +.[0].Err=null + # vim: filetype=sh diff --git a/test/apiv2/rest_api/__init__.py b/test/apiv2/rest_api/__init__.py index 5f0777d58..8100a4df5 100644 --- a/test/apiv2/rest_api/__init__.py +++ b/test/apiv2/rest_api/__init__.py @@ -3,7 +3,6 @@ import json import os import shutil import subprocess -import sys import tempfile diff --git a/test/apiv2/rest_api/test_rest_v2_0_0.py b/test/apiv2/rest_api/test_rest_v2_0_0.py index 5dfd1fc02..0ac4fde75 100644 --- a/test/apiv2/rest_api/test_rest_v2_0_0.py +++ b/test/apiv2/rest_api/test_rest_v2_0_0.py @@ -62,7 +62,7 @@ class TestApi(unittest.TestCase): TestApi.podman = Podman() TestApi.service = TestApi.podman.open( - "system", "service", "tcp:localhost:8080", "--log-level=debug", "--time=0" + "system", "service", "tcp:localhost:8080", "--time=0" ) # give the service some time to be ready... time.sleep(2) diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go index 4214bd50e..a749a86ff 100644 --- a/test/e2e/logs_test.go +++ b/test/e2e/logs_test.go @@ -337,4 +337,22 @@ var _ = Describe("Podman logs", func() { Expect(results).To(Exit(0)) Expect(results.OutputToString()).To(Equal("podman podman podman")) }) + + It("Make sure logs match expected length", func() { + logc := podmanTest.Podman([]string{"run", "-t", "--name", "test", ALPINE, "sh", "-c", "echo 1; echo 2"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + + wait := podmanTest.Podman([]string{"wait", "test"}) + wait.WaitWithDefaultTimeout() + Expect(wait).To(Exit(0)) + + results := podmanTest.Podman([]string{"logs", "test"}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + outlines := results.OutputToStringArray() + Expect(len(outlines)).To(Equal(2)) + Expect(outlines[0]).To(Equal("1\r")) + Expect(outlines[1]).To(Equal("2\r")) + }) }) diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index 21f03901b..cb997d10a 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -177,8 +177,7 @@ var _ = Describe("Podman network create", func() { }) It("podman network create with name and IPv6 subnet", func() { - SkipIfRootless("FIXME I believe this should work in rootlessmode") - + SkipIfRootless("FIXME It needs the ip6tables modules loaded") var ( results []network.NcList ) @@ -218,12 +217,72 @@ var _ = Describe("Podman network create", func() { Expect(subnet.Contains(containerIP)).To(BeTrue()) }) + It("podman network create with name and IPv6 flag (dual-stack)", func() { + SkipIfRootless("FIXME It needs the ip6tables modules loaded") + var ( + results []network.NcList + ) + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:3:2:1::/64", "--ipv6", "newDualStacknetwork"}) + nc.WaitWithDefaultTimeout() + Expect(nc.ExitCode()).To(BeZero()) + + defer podmanTest.removeCNINetwork("newDualStacknetwork") + + // Inspect the network configuration + inspect := podmanTest.Podman([]string{"network", "inspect", "newDualStacknetwork"}) + inspect.WaitWithDefaultTimeout() + + // JSON the network configuration into something usable + err := json.Unmarshal([]byte(inspect.OutputToString()), &results) + Expect(err).To(BeNil()) + result := results[0] + Expect(result["name"]).To(Equal("newDualStacknetwork")) + + // JSON the bridge info + bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge") + Expect(err).To(BeNil()) + Expect(bridgePlugin.IPAM.Routes[0].Dest).To(Equal("::/0")) + Expect(bridgePlugin.IPAM.Routes[1].Dest).To(Equal("0.0.0.0/0")) + + // Once a container executes a new network, the nic will be created. We should clean those up + // best we can + defer removeNetworkDevice(bridgePlugin.BrName) + + try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", "newDualStacknetwork", ALPINE, "sh", "-c", "ip addr show eth0 | grep global | awk ' /inet6 / {print $2}'"}) + try.WaitWithDefaultTimeout() + + _, subnet, err := net.ParseCIDR("fd00:4:3:2:1::/64") + Expect(err).To(BeNil()) + containerIP, _, err := net.ParseCIDR(try.OutputToString()) + Expect(err).To(BeNil()) + // Ensure that the IP the container got is within the subnet the user asked for + Expect(subnet.Contains(containerIP)).To(BeTrue()) + // verify the container has an IPv4 address too (the IPv4 subnet is autogenerated) + try = podmanTest.Podman([]string{"run", "-it", "--rm", "--network", "newDualStacknetwork", ALPINE, "sh", "-c", "ip addr show eth0 | awk ' /inet / {print $2}'"}) + try.WaitWithDefaultTimeout() + containerIP, _, err = net.ParseCIDR(try.OutputToString()) + Expect(err).To(BeNil()) + Expect(containerIP.To4()).To(Not(BeNil())) + }) + It("podman network create with invalid subnet", func() { nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/17000", "fail"}) nc.WaitWithDefaultTimeout() Expect(nc).To(ExitWithError()) }) + It("podman network create with ipv4 subnet and ipv6 flag", func() { + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--ipv6", "fail"}) + nc.WaitWithDefaultTimeout() + Expect(nc).To(ExitWithError()) + }) + + It("podman network create with empty subnet and ipv6 flag", func() { + nc := podmanTest.Podman([]string{"network", "create", "--ipv6", "fail"}) + nc.WaitWithDefaultTimeout() + Expect(nc).To(ExitWithError()) + }) + It("podman network create with invalid IP", func() { nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.0/17000", "fail"}) nc.WaitWithDefaultTimeout() @@ -247,6 +306,29 @@ var _ = Describe("Podman network create", func() { Expect(ncFail).To(ExitWithError()) }) + It("podman network create two networks with same subnet should fail", func() { + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.13.0/24", "subnet1"}) + nc.WaitWithDefaultTimeout() + Expect(nc.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork("subnet1") + + ncFail := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.13.0/24", "subnet2"}) + ncFail.WaitWithDefaultTimeout() + Expect(ncFail).To(ExitWithError()) + }) + + It("podman network create two IPv6 networks with same subnet should fail", func() { + SkipIfRootless("FIXME It needs the ip6tables modules loaded") + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:4:4:4::/64", "--ipv6", "subnet1v6"}) + nc.WaitWithDefaultTimeout() + Expect(nc.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork("subnet1v6") + + ncFail := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:4:4:4::/64", "--ipv6", "subnet2v6"}) + ncFail.WaitWithDefaultTimeout() + Expect(ncFail).To(ExitWithError()) + }) + It("podman network create with invalid network name", func() { nc := podmanTest.Podman([]string{"network", "create", "foo "}) nc.WaitWithDefaultTimeout() diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 9bd16c008..7933580a5 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "strings" + "time" "github.com/containers/podman/v2/pkg/rootless" . "github.com/containers/podman/v2/test/utils" @@ -351,4 +352,42 @@ var _ = Describe("Podman network", func() { Expect(lines[0]).To(Equal(netName1)) Expect(lines[1]).To(Equal(netName2)) }) + It("podman network with multiple aliases", func() { + Skip("Until DNSName is updated on our CI images") + var worked bool + netName := "aliasTest" + stringid.GenerateNonCryptoID() + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName) + + top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx}) + top.WaitWithDefaultTimeout() + Expect(top.ExitCode()).To(BeZero()) + interval := time.Duration(250 * time.Millisecond) + // Wait for the nginx service to be running + for i := 0; i < 6; i++ { + // Test curl against the container's name + c1 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web"}) + c1.WaitWithDefaultTimeout() + worked = Expect(c1.ExitCode()).To(BeZero()) + if worked { + break + } + time.Sleep(interval) + interval *= 2 + } + Expect(worked).To(BeTrue()) + + // Nginx is now running so no need to do a loop + // Test against the first alias + c2 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web1"}) + c2.WaitWithDefaultTimeout() + Expect(c2.ExitCode()).To(BeZero()) + + // Test against the second alias + c3 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web2"}) + c3.WaitWithDefaultTimeout() + Expect(c3.ExitCode()).To(BeZero()) + }) }) diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 1d683e987..7ae474c76 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -959,7 +959,7 @@ var _ = Describe("Podman play kube", func() { kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "{{ .HostConfig.ExtraHosts }}"}) + inspect := podmanTest.Podman([]string{"inspect", pod.Name, "--format", "{{ .InfraConfig.HostAdd}}"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) Expect(inspect.OutputToString()). @@ -1466,4 +1466,20 @@ MemoryReservation: {{ .HostConfig.MemoryReservation }}`}) Expect(kube.ExitCode()).To(Equal(125)) Expect(kube.ErrorToString()).To(ContainSubstring(invalidImageName)) }) + + It("podman play kube applies log driver to containers", func() { + Skip("need to verify images have correct packages for journald") + pod := getPod() + err := generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", "--log-driver", "journald", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .HostConfig.LogConfig.Type }}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring("journald")) + }) }) diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index a3cc352b1..e9c1bab21 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -6,6 +6,7 @@ import ( "strings" . "github.com/containers/podman/v2/test/utils" + "github.com/containers/storage/pkg/stringid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/uber/jaeger-client-go/utils" @@ -601,11 +602,11 @@ var _ = Describe("Podman run networking", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(BeZero()) - net := "dnsNetTest" + net := "IntTest" + stringid.GenerateNonCryptoID() session = podmanTest.Podman([]string{"network", "create", net}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(net) + Expect(session.ExitCode()).To(BeZero()) pod2 := "testpod2" session = podmanTest.Podman([]string{"pod", "create", "--network", net, "--name", pod2}) diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 1c8a67123..7c74cea78 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -540,4 +540,12 @@ VOLUME /test/` session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "--mount", fmt.Sprintf("type=tmpfs,target=%s", mountDest), ALPINE}) Expect(session.ExitCode()).To(Not(Equal(0))) }) + + It("same volume in multiple places does not deadlock", func() { + volName := "testVol1" + session := podmanTest.Podman([]string{"run", "-t", "-i", "-v", fmt.Sprintf("%s:/test1", volName), "-v", fmt.Sprintf("%s:/test2", volName), "--rm", ALPINE, "sh", "-c", "mount | grep /test"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(2)) + }) }) diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index 424a191c5..edd2fedad 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -116,6 +116,14 @@ registries = ['{{.Host}}:{{.Port}}']` Expect(search.LineInOutputContains("docker.io/library/alpine")).To(BeTrue()) }) + It("podman search format json", func() { + search := podmanTest.Podman([]string{"search", "--format", "json", "alpine"}) + search.WaitWithDefaultTimeout() + Expect(search.ExitCode()).To(Equal(0)) + Expect(search.IsJSONOutputValid()).To(BeTrue()) + Expect(search.OutputToString()).To(ContainSubstring("docker.io/library/alpine")) + }) + It("podman search no-trunc flag", func() { search := podmanTest.Podman([]string{"search", "--no-trunc", "alpine"}) search.WaitWithDefaultTimeout() diff --git a/test/python/docker/README.md b/test/python/docker/README.md new file mode 100644 index 000000000..c10fd636d --- /dev/null +++ b/test/python/docker/README.md @@ -0,0 +1,38 @@ +# Docker regression test + +Python test suite to validate Podman endpoints using docker library (aka docker-py). +See [Docker SDK for Python](https://docker-py.readthedocs.io/en/stable/index.html). + +## Running Tests + +To run the tests locally in your sandbox (Fedora 32,33): + +```shell +# dnf install python3-docker +``` + +### Run the entire test suite + +```shell +# python3 -m unittest discover test/python/docker +``` + +Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, and produce detailed output: + +```shell +# python3 -m unittest -v discover test/python/docker +``` + +### Run a specific test class + +```shell +# cd test/python/docker +# python3 -m unittest -v tests.test_images +``` + +### Run a specific test within the test class + +```shell +# cd test/python/docker +# python3 -m unittest tests.test_images.TestImages.test_import_image +``` diff --git a/test/python/docker/__init__.py b/test/python/docker/__init__.py new file mode 100644 index 000000000..0e10676b9 --- /dev/null +++ b/test/python/docker/__init__.py @@ -0,0 +1,157 @@ +import configparser +import json +import os +import pathlib +import shutil +import subprocess +import tempfile + +from test.python.docker import constant + + +class Podman(object): + """ + Instances hold the configuration and setup for running podman commands + """ + + def __init__(self): + """Initialize a Podman instance with global options""" + binary = os.getenv("PODMAN", "bin/podman") + self.cmd = [binary, "--storage-driver=vfs"] + + cgroupfs = os.getenv("CGROUP_MANAGER", "systemd") + self.cmd.append(f"--cgroup-manager={cgroupfs}") + + # No support for tmpfs (/tmp) or extfs (/var/tmp) + # self.cmd.append("--storage-driver=overlay") + + if os.getenv("DEBUG"): + self.cmd.append("--log-level=debug") + self.cmd.append("--syslog=true") + + self.anchor_directory = tempfile.mkdtemp(prefix="podman_docker_") + + self.image_cache = os.path.join(self.anchor_directory, "cache") + os.makedirs(self.image_cache, exist_ok=True) + + self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio")) + self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run")) + + os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join( + self.anchor_directory, "registry.conf" + ) + p = configparser.ConfigParser() + p.read_dict( + { + "registries.search": {"registries": "['quay.io', 'docker.io']"}, + "registries.insecure": {"registries": "[]"}, + "registries.block": {"registries": "[]"}, + } + ) + with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w: + p.write(w) + + os.environ["CNI_CONFIG_PATH"] = os.path.join( + self.anchor_directory, "cni", "net.d" + ) + os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True) + self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"]) + cni_cfg = os.path.join( + os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist" + ) + # json decoded and encoded to ensure legal json + buf = json.loads( + """ + { + "cniVersion": "0.3.0", + "name": "podman", + "plugins": [{ + "type": "bridge", + "bridge": "cni0", + "isGateway": true, + "ipMasq": true, + "ipam": { + "type": "host-local", + "subnet": "10.88.0.0/16", + "routes": [{ + "dst": "0.0.0.0/0" + }] + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + } + ] + } + """ + ) + with open(cni_cfg, "w") as w: + json.dump(buf, w) + + def open(self, command, *args, **kwargs): + """Podman initialized instance to run a given command + + :param self: Podman instance + :param command: podman sub-command to run + :param args: arguments and options for command + :param kwargs: See subprocess.Popen() for shell keyword + :return: subprocess.Popen() instance configured to run podman instance + """ + cmd = self.cmd.copy() + cmd.append(command) + cmd.extend(args) + + shell = kwargs.get("shell", False) + + return subprocess.Popen( + cmd, + shell=shell, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + def run(self, command, *args, **kwargs): + """Podman initialized instance to run a given command + + :param self: Podman instance + :param command: podman sub-command to run + :param args: arguments and options for command + :param kwargs: See subprocess.Popen() for shell and check keywords + :return: subprocess.Popen() instance configured to run podman instance + """ + cmd = self.cmd.copy() + cmd.append(command) + cmd.extend(args) + + check = kwargs.get("check", False) + shell = kwargs.get("shell", False) + + return subprocess.run( + cmd, + shell=shell, + check=check, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + + def tear_down(self): + shutil.rmtree(self.anchor_directory, ignore_errors=True) + + def restore_image_from_cache(self, client): + img = os.path.join(self.image_cache, constant.ALPINE_TARBALL) + if not os.path.exists(img): + client.pull(constant.ALPINE) + image = client.get_image(constant.ALPINE) + with open(img, mode="wb") as tarball: + for frame in image: + tarball.write(frame) + else: + self.run("load", "-i", img, check=True) + + def flush_image_cache(self): + for f in pathlib.Path(self.image_cache).glob("*.tar"): + f.unlink(f) diff --git a/test/python/docker/common.py b/test/python/docker/common.py new file mode 100644 index 000000000..2828d2d20 --- /dev/null +++ b/test/python/docker/common.py @@ -0,0 +1,21 @@ +from docker import APIClient + +from test.python.docker import constant + + +def run_top_container(client: APIClient): + c = client.create_container( + constant.ALPINE, command="top", detach=True, tty=True, name="top" + ) + client.start(c.get("Id")) + return c.get("Id") + + +def remove_all_containers(client: APIClient): + for ctnr in client.containers(quiet=True): + client.remove_container(ctnr, force=True) + + +def remove_all_images(client: APIClient): + for image in client.images(quiet=True): + client.remove_image(image, force=True) diff --git a/test/python/docker/constant.py b/test/python/docker/constant.py new file mode 100644 index 000000000..892293c97 --- /dev/null +++ b/test/python/docker/constant.py @@ -0,0 +1,6 @@ +ALPINE = "quay.io/libpod/alpine:latest" +ALPINE_SHORTNAME = "alpine" +ALPINE_TARBALL = "alpine.tar" +BB = "quay.io/libpod/busybox:latest" +NGINX = "quay.io/libpod/alpine_nginx:latest" +infra = "k8s.gcr.io/pause:3.2" diff --git a/test/python/docker/test_containers.py b/test/python/docker/test_containers.py new file mode 100644 index 000000000..1c4c9ab53 --- /dev/null +++ b/test/python/docker/test_containers.py @@ -0,0 +1,214 @@ +import subprocess +import sys +import time +import unittest + +from docker import APIClient, errors + +from test.python.docker import Podman, common, constant + + +class TestContainers(unittest.TestCase): + podman = None # initialized podman configuration for tests + service = None # podman service instance + topContainerId = "" + + def setUp(self): + super().setUp() + self.client = APIClient(base_url="tcp://127.0.0.1:8080", timeout=15) + TestContainers.podman.restore_image_from_cache(self.client) + TestContainers.topContainerId = common.run_top_container(self.client) + self.assertIsNotNone(TestContainers.topContainerId) + + def tearDown(self): + common.remove_all_containers(self.client) + common.remove_all_images(self.client) + self.client.close() + return super().tearDown() + + @classmethod + def setUpClass(cls): + super().setUpClass() + TestContainers.podman = Podman() + TestContainers.service = TestContainers.podman.open( + "system", "service", "tcp:127.0.0.1:8080", "--time=0" + ) + # give the service some time to be ready... + time.sleep(2) + + rc = TestContainers.service.poll() + if rc is not None: + raise subprocess.CalledProcessError(rc, "podman system service") + + @classmethod + def tearDownClass(cls): + TestContainers.service.terminate() + stdout, stderr = TestContainers.service.communicate(timeout=0.5) + if stdout: + sys.stdout.write("\nContainers Service Stdout:\n" + stdout.decode("utf-8")) + if stderr: + sys.stderr.write("\nContainers Service Stderr:\n" + stderr.decode("utf-8")) + + TestContainers.podman.tear_down() + return super().tearDownClass() + + def test_inspect_container(self): + # Inspect bogus container + with self.assertRaises(errors.NotFound) as error: + self.client.inspect_container("dummy") + self.assertEqual(error.exception.response.status_code, 404) + + # Inspect valid container by Id + container = self.client.inspect_container(TestContainers.topContainerId) + self.assertIn("top", container["Name"]) + + # Inspect valid container by name + container = self.client.inspect_container("top") + self.assertIn(TestContainers.topContainerId, container["Id"]) + + def test_create_container(self): + # Run a container with detach mode + container = self.client.create_container(image="alpine", detach=True) + self.assertEqual(len(container), 2) + + def test_start_container(self): + # Start bogus container + with self.assertRaises(errors.NotFound) as error: + self.client.start("dummy") + self.assertEqual(error.exception.response.status_code, 404) + + # Podman docs says it should give a 304 but returns with no response + # # Start a already started container should return 304 + # response = self.client.start(container=TestContainers.topContainerId) + # self.assertEqual(error.exception.response.status_code, 304) + + # Create a new container and validate the count + self.client.create_container(image=constant.ALPINE, name="container2") + containers = self.client.containers(quiet=True, all=True) + self.assertEqual(len(containers), 2) + + def test_stop_container(self): + # Stop bogus container + with self.assertRaises(errors.NotFound) as error: + self.client.stop("dummy") + self.assertEqual(error.exception.response.status_code, 404) + + # Validate the container state + container = self.client.inspect_container("top") + self.assertEqual(container["State"]["Status"], "running") + + # Stop a running container and validate the state + self.client.stop(TestContainers.topContainerId) + container = self.client.inspect_container("top") + self.assertIn( + container["State"]["Status"], + "stopped exited", + ) + + def test_restart_container(self): + # Restart bogus container + with self.assertRaises(errors.NotFound) as error: + self.client.restart("dummy") + self.assertEqual(error.exception.response.status_code, 404) + + # Validate the container state + self.client.stop(TestContainers.topContainerId) + container = self.client.inspect_container("top") + self.assertEqual(container["State"]["Status"], "stopped") + + # restart a running container and validate the state + self.client.restart(TestContainers.topContainerId) + container = self.client.inspect_container("top") + self.assertEqual(container["State"]["Status"], "running") + + def test_remove_container(self): + # Remove bogus container + with self.assertRaises(errors.NotFound) as error: + self.client.remove_container("dummy") + self.assertEqual(error.exception.response.status_code, 404) + + # Remove container by ID with force + self.client.remove_container(TestContainers.topContainerId, force=True) + containers = self.client.containers() + self.assertEqual(len(containers), 0) + + def test_remove_container_without_force(self): + # Validate current container count + containers = self.client.containers() + self.assertTrue(len(containers), 1) + + # Remove running container should throw error + with self.assertRaises(errors.APIError) as error: + self.client.remove_container(TestContainers.topContainerId) + self.assertEqual(error.exception.response.status_code, 500) + + # Remove container by ID with force + self.client.stop(TestContainers.topContainerId) + self.client.remove_container(TestContainers.topContainerId) + containers = self.client.containers() + self.assertEqual(len(containers), 0) + + def test_pause_container(self): + # Pause bogus container + with self.assertRaises(errors.NotFound) as error: + self.client.pause("dummy") + self.assertEqual(error.exception.response.status_code, 404) + + # Validate the container state + container = self.client.inspect_container("top") + self.assertEqual(container["State"]["Status"], "running") + + # Pause a running container and validate the state + self.client.pause(container["Id"]) + container = self.client.inspect_container("top") + self.assertEqual(container["State"]["Status"], "paused") + + def test_pause_stopped_container(self): + # Stop the container + self.client.stop(TestContainers.topContainerId) + + # Pause exited container should trow error + with self.assertRaises(errors.APIError) as error: + self.client.pause(TestContainers.topContainerId) + self.assertEqual(error.exception.response.status_code, 500) + + def test_unpause_container(self): + # Unpause bogus container + with self.assertRaises(errors.NotFound) as error: + self.client.unpause("dummy") + self.assertEqual(error.exception.response.status_code, 404) + + # Validate the container state + self.client.pause(TestContainers.topContainerId) + container = self.client.inspect_container("top") + self.assertEqual(container["State"]["Status"], "paused") + + # Pause a running container and validate the state + self.client.unpause(TestContainers.topContainerId) + container = self.client.inspect_container("top") + self.assertEqual(container["State"]["Status"], "running") + + def test_list_container(self): + # Add container and validate the count + self.client.create_container(image="alpine", detach=True) + containers = self.client.containers(all=True) + self.assertEqual(len(containers), 2) + + def test_filters(self): + self.skipTest("TODO Endpoint does not yet support filters") + + # List container with filter by id + filters = {"id": TestContainers.topContainerId} + ctnrs = self.client.containers(all=True, filters=filters) + self.assertEqual(len(ctnrs), 1) + + # List container with filter by name + filters = {"name": "top"} + ctnrs = self.client.containers(all=True, filters=filters) + self.assertEqual(len(ctnrs), 1) + + def test_rename_container(self): + # rename bogus container + with self.assertRaises(errors.APIError) as error: + self.client.rename(container="dummy", name="newname") + self.assertEqual(error.exception.response.status_code, 404) diff --git a/test/python/docker/test_images.py b/test/python/docker/test_images.py new file mode 100644 index 000000000..f049da96f --- /dev/null +++ b/test/python/docker/test_images.py @@ -0,0 +1,169 @@ +import collections +import os +import subprocess +import sys +import time +import unittest + +from docker import APIClient, errors + +from test.python.docker import Podman, common, constant + + +class TestImages(unittest.TestCase): + podman = None # initialized podman configuration for tests + service = None # podman service instance + + def setUp(self): + super().setUp() + self.client = APIClient(base_url="tcp://127.0.0.1:8080", timeout=15) + + TestImages.podman.restore_image_from_cache(self.client) + + def tearDown(self): + common.remove_all_images(self.client) + self.client.close() + return super().tearDown() + + @classmethod + def setUpClass(cls): + super().setUpClass() + TestImages.podman = Podman() + TestImages.service = TestImages.podman.open( + "system", "service", "tcp:127.0.0.1:8080", "--time=0" + ) + # give the service some time to be ready... + time.sleep(2) + + returncode = TestImages.service.poll() + if returncode is not None: + raise subprocess.CalledProcessError(returncode, "podman system service") + + @classmethod + def tearDownClass(cls): + TestImages.service.terminate() + stdout, stderr = TestImages.service.communicate(timeout=0.5) + if stdout: + sys.stdout.write("\nImages Service Stdout:\n" + stdout.decode("utf-8")) + if stderr: + sys.stderr.write("\nImAges Service Stderr:\n" + stderr.decode("utf-8")) + + TestImages.podman.tear_down() + return super().tearDownClass() + + def test_inspect_image(self): + """Inspect Image""" + # Check for error with wrong image name + with self.assertRaises(errors.NotFound): + self.client.inspect_image("dummy") + alpine_image = self.client.inspect_image(constant.ALPINE) + self.assertIn(constant.ALPINE, alpine_image["RepoTags"]) + + def test_tag_invalid_image(self): + """Tag Image + + Validates if invalid image name is given a bad response is encountered + """ + with self.assertRaises(errors.NotFound): + self.client.tag("dummy", "demo") + + def test_tag_valid_image(self): + """Validates if the image is tagged successfully""" + self.client.tag(constant.ALPINE, "demo", constant.ALPINE_SHORTNAME) + alpine_image = self.client.inspect_image(constant.ALPINE) + for x in alpine_image["RepoTags"]: + self.assertIn("alpine", x) + + # @unittest.skip("doesn't work now") + def test_retag_valid_image(self): + """Validates if name updates when the image is retagged""" + self.client.tag(constant.ALPINE_SHORTNAME, "demo", "rename") + alpine_image = self.client.inspect_image(constant.ALPINE) + self.assertNotIn("demo:test", alpine_image["RepoTags"]) + + def test_list_images(self): + """List images""" + all_images = self.client.images() + self.assertEqual(len(all_images), 1) + # Add more images + self.client.pull(constant.BB) + all_images = self.client.images() + self.assertEqual(len(all_images), 2) + + # List images with filter + filters = {"reference": "alpine"} + all_images = self.client.images(filters=filters) + self.assertEqual(len(all_images), 1) + + def test_search_image(self): + """Search for image""" + response = self.client.search("libpod/alpine") + for i in response: + self.assertIn("quay.io/libpod/alpine", i["Name"]) + + def test_remove_image(self): + """Remove image""" + # Check for error with wrong image name + with self.assertRaises(errors.NotFound): + self.client.remove_image("dummy") + all_images = self.client.images() + self.assertEqual(len(all_images), 1) + + alpine_image = self.client.inspect_image(constant.ALPINE) + self.client.remove_image(alpine_image["Id"]) + all_images = self.client.images() + self.assertEqual(len(all_images), 0) + + def test_image_history(self): + """Image history""" + # Check for error with wrong image name + with self.assertRaises(errors.NotFound): + self.client.history("dummy") + + # NOTE: history() has incorrect return type hint + history = self.client.history(constant.ALPINE) + alpine_image = self.client.inspect_image(constant.ALPINE) + image_id = ( + alpine_image["Id"][7:] + if alpine_image["Id"].startswith("sha256:") + else alpine_image["Id"] + ) + + found = False + for change in history: + found |= image_id in change.values() + self.assertTrue(found, f"image id {image_id} not found in history") + + def test_get_image_exists_not(self): + """Negative test for get image""" + with self.assertRaises(errors.NotFound): + response = self.client.get_image("image_does_not_exists") + collections.deque(response) + + def test_export_image(self): + """Export Image""" + self.client.pull(constant.BB) + image = self.client.get_image(constant.BB) + + file = os.path.join(TestImages.podman.image_cache, "busybox.tar") + with open(file, mode="wb") as tarball: + for frame in image: + tarball.write(frame) + sz = os.path.getsize(file) + self.assertGreater(sz, 0) + + def test_import_image(self): + """Import|Load Image""" + all_images = self.client.images() + self.assertEqual(len(all_images), 1) + + file = os.path.join(TestImages.podman.image_cache, constant.ALPINE_TARBALL) + self.client.import_image_from_file(filename=file) + + all_images = self.client.images() + self.assertEqual(len(all_images), 2) + + +if __name__ == "__main__": + # Setup temporary space + unittest.main() diff --git a/test/python/docker/test_system.py b/test/python/docker/test_system.py new file mode 100644 index 000000000..f911baee4 --- /dev/null +++ b/test/python/docker/test_system.py @@ -0,0 +1,66 @@ +import subprocess +import sys +import time +import unittest + +from docker import APIClient + +from test.python.docker import Podman, common, constant + + +class TestSystem(unittest.TestCase): + podman = None # initialized podman configuration for tests + service = None # podman service instance + topContainerId = "" + + def setUp(self): + super().setUp() + self.client = APIClient(base_url="tcp://127.0.0.1:8080", timeout=15) + + TestSystem.podman.restore_image_from_cache(self.client) + TestSystem.topContainerId = common.run_top_container(self.client) + + def tearDown(self): + common.remove_all_containers(self.client) + common.remove_all_images(self.client) + self.client.close() + return super().tearDown() + + @classmethod + def setUpClass(cls): + super().setUpClass() + TestSystem.podman = Podman() + TestSystem.service = TestSystem.podman.open( + "system", "service", "tcp:127.0.0.1:8080", "--time=0" + ) + # give the service some time to be ready... + time.sleep(2) + + returncode = TestSystem.service.poll() + if returncode is not None: + raise subprocess.CalledProcessError(returncode, "podman system service") + + @classmethod + def tearDownClass(cls): + TestSystem.service.terminate() + stdout, stderr = TestSystem.service.communicate(timeout=0.5) + if stdout: + sys.stdout.write("\nImages Service Stdout:\n" + stdout.decode("utf-8")) + if stderr: + sys.stderr.write("\nImAges Service Stderr:\n" + stderr.decode("utf-8")) + + TestSystem.podman.tear_down() + return super().tearDownClass() + + def test_Info(self): + self.assertIsNotNone(self.client.info()) + + def test_info_container_details(self): + info = self.client.info() + self.assertEqual(info["Containers"], 1) + self.client.create_container(image=constant.ALPINE) + info = self.client.info() + self.assertEqual(info["Containers"], 2) + + def test_version(self): + self.assertIsNotNone(self.client.version()) diff --git a/test/python/dockerpy/README.md b/test/python/dockerpy/README.md deleted file mode 100644 index 22908afc6..000000000 --- a/test/python/dockerpy/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Dockerpy regression test - -Python test suite to validate Podman endpoints using dockerpy library - -## Running Tests - -To run the tests locally in your sandbox (Fedora 32): - -```shell script -# dnf install python3-docker -``` - -### Run the entire test suite - -```shell -# cd test/python/dockerpy -# PYTHONPATH=/usr/bin/python python -m unittest discover . -``` - -Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, and produce detailed output: - -```shell -# cd test/python/dockerpy -# PYTHONPATH=/usr/bin/python python -m unittest -v discover . -``` - -### Run a specific test class - -```shell -# cd test/python/dockerpy -# PYTHONPATH=/usr/bin/python python -m unittest -v tests.test_images -``` - -### Run a specific test within the test class - -```shell -# cd test/python/dockerpy -# PYTHONPATH=/usr/bin/python python -m unittest tests.test_images.TestImages.test_import_image - -``` diff --git a/test/python/dockerpy/__init__.py b/test/python/dockerpy/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/test/python/dockerpy/__init__.py +++ /dev/null diff --git a/test/python/dockerpy/tests/__init__.py b/test/python/dockerpy/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/test/python/dockerpy/tests/__init__.py +++ /dev/null diff --git a/test/python/dockerpy/tests/common.py b/test/python/dockerpy/tests/common.py deleted file mode 100644 index f83f4076f..000000000 --- a/test/python/dockerpy/tests/common.py +++ /dev/null @@ -1,105 +0,0 @@ -import os -import pathlib -import subprocess -import sys -import time - -from docker import APIClient - -from . import constant - -alpineDict = { - "name": "docker.io/library/alpine:latest", - "shortName": "alpine", - "tarballName": "alpine.tar" -} - - -def get_client(): - client = APIClient(base_url="http://localhost:8080", timeout=15) - return client - - -client = get_client() - - -def podman(): - binary = os.getenv("PODMAN_BINARY") - if binary is None: - binary = "../../../bin/podman" - return binary - - -def restore_image_from_cache(TestClass): - alpineImage = os.path.join(constant.ImageCacheDir, - alpineDict["tarballName"]) - if not os.path.exists(alpineImage): - os.makedirs(constant.ImageCacheDir, exist_ok=True) - client.pull(constant.ALPINE) - image = client.get_image(constant.ALPINE) - tarball = open(alpineImage, mode="wb") - for frame in image: - tarball.write(frame) - tarball.close() - else: - subprocess.run( - [podman(), "load", "-i", alpineImage], - shell=False, - stdin=subprocess.DEVNULL, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - check=True, - ) - - -def flush_image_cache(TestCase): - for f in pathlib.Path(constant.ImageCacheDir).glob("*"): - f.unlink(f) - - -def run_top_container(): - c = client.create_container(image=constant.ALPINE, - command='/bin/sleep 5', - name=constant.TOP) - client.start(container=c.get("Id")) - return c.get("Id") - - -def enable_sock(TestClass): - TestClass.podman = subprocess.Popen( - [ - podman(), "system", "service", "tcp:localhost:8080", - "--log-level=debug", "--time=0" - ], - shell=False, - stdin=subprocess.DEVNULL, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - time.sleep(2) - - -def terminate_connection(TestClass): - TestClass.podman.terminate() - stdout, stderr = TestClass.podman.communicate(timeout=0.5) - if stdout: - print("\nService Stdout:\n" + stdout.decode('utf-8')) - if stderr: - print("\nService Stderr:\n" + stderr.decode('utf-8')) - - if TestClass.podman.returncode > 0: - sys.stderr.write("podman exited with error code {}\n".format( - TestClass.podman.returncode)) - sys.exit(2) - - -def remove_all_containers(): - containers = client.containers(quiet=True) - for c in containers: - client.remove_container(container=c.get("Id"), force=True) - - -def remove_all_images(): - allImages = client.images() - for image in allImages: - client.remove_image(image, force=True) diff --git a/test/python/dockerpy/tests/constant.py b/test/python/dockerpy/tests/constant.py deleted file mode 100644 index b44442d02..000000000 --- a/test/python/dockerpy/tests/constant.py +++ /dev/null @@ -1,13 +0,0 @@ -BB = "docker.io/library/busybox:latest" -NGINX = "docker.io/library/nginx:latest" -ALPINE = "docker.io/library/alpine:latest" -ALPINE_SHORTNAME = "alpine" -ALPINELISTTAG = "docker.io/library/alpine:3.10.2" -ALPINELISTDIGEST = "docker.io/library/alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb" -ALPINEAMD64DIGEST = "docker.io/library/alpine@sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f" -ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4" -ALPINEARM64DIGEST = "docker.io/library/alpine@sha256:db7f3dcef3d586f7dd123f107c93d7911515a5991c4b9e51fa2a43e46335a43e" -ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672" -infra = "k8s.gcr.io/pause:3.2" -TOP = "top" -ImageCacheDir = "/tmp/podman/imagecachedir" diff --git a/test/python/dockerpy/tests/test_containers.py b/test/python/dockerpy/tests/test_containers.py deleted file mode 100644 index 6b89688d4..000000000 --- a/test/python/dockerpy/tests/test_containers.py +++ /dev/null @@ -1,193 +0,0 @@ -import os -import time -import unittest - -import requests - -from . import common, constant - -client = common.get_client() - - -class TestContainers(unittest.TestCase): - topContainerId = "" - - def setUp(self): - super().setUp() - common.restore_image_from_cache(self) - TestContainers.topContainerId = common.run_top_container() - - def tearDown(self): - common.remove_all_containers() - common.remove_all_images() - return super().tearDown() - - @classmethod - def setUpClass(cls): - super().setUpClass() - common.enable_sock(cls) - - @classmethod - def tearDownClass(cls): - common.terminate_connection(cls) - common.flush_image_cache(cls) - return super().tearDownClass() - - def test_inspect_container(self): - # Inspect bogus container - with self.assertRaises(requests.HTTPError) as error: - client.inspect_container("dummy") - self.assertEqual(error.exception.response.status_code, 404) - # Inspect valid container by name - container = client.inspect_container(constant.TOP) - self.assertIn(TestContainers.topContainerId, container["Id"]) - # Inspect valid container by Id - container = client.inspect_container(TestContainers.topContainerId) - self.assertIn(constant.TOP, container["Name"]) - - def test_create_container(self): - # Run a container with detach mode - container = client.create_container(image="alpine", detach=True) - self.assertEqual(len(container), 2) - - def test_start_container(self): - # Start bogus container - with self.assertRaises(requests.HTTPError) as error: - client.start("dummy") - self.assertEqual(error.exception.response.status_code, 404) - - # Podman docs says it should give a 304 but returns with no response - # # Start a already started container should return 304 - # response = client.start(container=TestContainers.topContainerId) - # self.assertEqual(error.exception.response.status_code, 304) - - # Create a new container and validate the count - client.create_container(image=constant.ALPINE, name="container2") - containers = client.containers(quiet=True, all=True) - self.assertEqual(len(containers), 2) - - def test_stop_container(self): - # Stop bogus container - with self.assertRaises(requests.HTTPError) as error: - client.stop("dummy") - self.assertEqual(error.exception.response.status_code, 404) - - # Validate the container state - container = client.inspect_container(constant.TOP) - self.assertEqual(container["State"]["Status"], "running") - - # Stop a running container and validate the state - client.stop(TestContainers.topContainerId) - container = client.inspect_container(constant.TOP) - self.assertIn( - container["State"]["Status"], - "stopped exited", - ) - - def test_restart_container(self): - # Restart bogus container - with self.assertRaises(requests.HTTPError) as error: - client.restart("dummy") - self.assertEqual(error.exception.response.status_code, 404) - - # Validate the container state - client.stop(TestContainers.topContainerId) - container = client.inspect_container(constant.TOP) - self.assertEqual(container["State"]["Status"], "stopped") - - # restart a running container and validate the state - client.restart(TestContainers.topContainerId) - container = client.inspect_container(constant.TOP) - self.assertEqual(container["State"]["Status"], "running") - - def test_remove_container(self): - # Remove bogus container - with self.assertRaises(requests.HTTPError) as error: - client.remove_container("dummy") - self.assertEqual(error.exception.response.status_code, 404) - - # Remove container by ID with force - client.remove_container(TestContainers.topContainerId, force=True) - containers = client.containers() - self.assertEqual(len(containers), 0) - - def test_remove_container_without_force(self): - # Validate current container count - containers = client.containers() - self.assertTrue(len(containers), 1) - - # Remove running container should throw error - with self.assertRaises(requests.HTTPError) as error: - client.remove_container(TestContainers.topContainerId) - self.assertEqual(error.exception.response.status_code, 500) - - # Remove container by ID with force - client.stop(TestContainers.topContainerId) - client.remove_container(TestContainers.topContainerId) - containers = client.containers() - self.assertEqual(len(containers), 0) - - def test_pause_container(self): - # Pause bogus container - with self.assertRaises(requests.HTTPError) as error: - client.pause("dummy") - self.assertEqual(error.exception.response.status_code, 404) - - # Validate the container state - container = client.inspect_container(constant.TOP) - self.assertEqual(container["State"]["Status"], "running") - - # Pause a running container and validate the state - client.pause(container) - container = client.inspect_container(constant.TOP) - self.assertEqual(container["State"]["Status"], "paused") - - def test_pause_stoped_container(self): - # Stop the container - client.stop(TestContainers.topContainerId) - - # Pause exited container should trow error - with self.assertRaises(requests.HTTPError) as error: - client.pause(TestContainers.topContainerId) - self.assertEqual(error.exception.response.status_code, 500) - - def test_unpause_container(self): - # Unpause bogus container - with self.assertRaises(requests.HTTPError) as error: - client.unpause("dummy") - self.assertEqual(error.exception.response.status_code, 404) - - # Validate the container state - client.pause(TestContainers.topContainerId) - container = client.inspect_container(constant.TOP) - self.assertEqual(container["State"]["Status"], "paused") - - # Pause a running container and validate the state - client.unpause(TestContainers.topContainerId) - container = client.inspect_container(constant.TOP) - self.assertEqual(container["State"]["Status"], "running") - - def test_list_container(self): - - # Add container and validate the count - client.create_container(image="alpine", detach=True) - containers = client.containers(all=True) - self.assertEqual(len(containers), 2) - - # Not working for now......checking - # # List container with filter by id - # filters = {'id':TestContainers.topContainerId} - # filteredContainers = client.containers(all=True,filters = filters) - # self.assertEqual(len(filteredContainers) , 1) - - # # List container with filter by name - # filters = {'name':constant.TOP} - # filteredContainers = client.containers(all=True,filters = filters) - # self.assertEqual(len(filteredContainers) , 1) - - @unittest.skip("Not Supported yet") - def test_rename_container(self): - # rename bogus container - with self.assertRaises(requests.HTTPError) as error: - client.rename(container="dummy", name="newname") - self.assertEqual(error.exception.response.status_code, 404) diff --git a/test/python/dockerpy/tests/test_images.py b/test/python/dockerpy/tests/test_images.py deleted file mode 100644 index 602a86de2..000000000 --- a/test/python/dockerpy/tests/test_images.py +++ /dev/null @@ -1,162 +0,0 @@ -import os -import stat -import unittest -from os import remove -from stat import ST_SIZE - -import docker -import requests - -from . import common, constant - -client = common.get_client() - - -class TestImages(unittest.TestCase): - def setUp(self): - super().setUp() - common.restore_image_from_cache(self) - - def tearDown(self): - common.remove_all_images() - return super().tearDown() - - @classmethod - def setUpClass(cls): - super().setUpClass() - common.enable_sock(cls) - - @classmethod - def tearDownClass(cls): - common.terminate_connection(cls) - common.flush_image_cache(cls) - return super().tearDownClass() - -# Inspect Image - - def test_inspect_image(self): - # Check for error with wrong image name - with self.assertRaises(requests.HTTPError): - client.inspect_image("dummy") - alpine_image = client.inspect_image(constant.ALPINE) - self.assertIn(constant.ALPINE, alpine_image["RepoTags"]) - -# Tag Image - -# Validates if invalid image name is given a bad response is encountered. - - def test_tag_invalid_image(self): - with self.assertRaises(requests.HTTPError): - client.tag("dummy", "demo") - - # Validates if the image is tagged successfully. - def test_tag_valid_image(self): - client.tag(constant.ALPINE, "demo", constant.ALPINE_SHORTNAME) - alpine_image = client.inspect_image(constant.ALPINE) - for x in alpine_image["RepoTags"]: - if ("demo:alpine" in x): - self.assertTrue - self.assertFalse - - # Validates if name updates when the image is retagged. - @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) - self.assertNotIn("demo:test", alpine_image["RepoTags"]) - -# List Image -# List All Images - - def test_list_images(self): - allImages = client.images() - self.assertEqual(len(allImages), 1) - # Add more images - client.pull(constant.BB) - allImages = client.images() - self.assertEqual(len(allImages), 2) - - # List images with filter - filters = {'reference': 'alpine'} - allImages = client.images(filters=filters) - self.assertEqual(len(allImages), 1) - -# Search Image - - def test_search_image(self): - response = client.search("alpine") - for i in response: - # Alpine found - if "docker.io/library/alpine" in i["Name"]: - self.assertTrue - self.assertFalse - -# Image Exist (No docker-py support yet) - -# Remove Image - - def test_remove_image(self): - # Check for error with wrong image name - with self.assertRaises(requests.HTTPError): - client.remove_image("dummy") - allImages = client.images() - self.assertEqual(len(allImages), 1) - alpine_image = client.inspect_image(constant.ALPINE) - client.remove_image(alpine_image) - allImages = client.images() - self.assertEqual(len(allImages), 0) - -# Image History - - def test_image_history(self): - # Check for error with wrong image name - with self.assertRaises(requests.HTTPError): - client.history("dummy") - - imageHistory = client.history(constant.ALPINE) - alpine_image = client.inspect_image(constant.ALPINE) - for h in imageHistory: - if h["Id"] in alpine_image["Id"]: - self.assertTrue - self.assertFalse - -# Prune Image (No docker-py support yet) - - def test_get_image_dummy(self): - # FIXME: seems to be an error in the library - self.skipTest("Documentation and library do not match") - # Check for error with wrong image name - with self.assertRaises(docker.errors.ImageNotFound): - client.get_image("dummy") - -# Export Image - - def test_export_image(self): - client.pull(constant.BB) - if not os.path.exists(constant.ImageCacheDir): - os.makedirs(constant.ImageCacheDir) - - image = client.get_image(constant.BB) - - file = os.path.join(constant.ImageCacheDir, "busybox.tar") - tarball = open(file, mode="wb") - for frame in image: - tarball.write(frame) - tarball.close() - sz = os.path.getsize(file) - self.assertGreater(sz, 0) - - -# Import|Load Image - - def test_import_image(self): - allImages = client.images() - self.assertEqual(len(allImages), 1) - file = os.path.join(constant.ImageCacheDir, "alpine.tar") - client.import_image_from_file(filename=file) - allImages = client.images() - self.assertEqual(len(allImages), 2) - -if __name__ == '__main__': - # Setup temporary space - unittest.main() diff --git a/test/python/dockerpy/tests/test_info_version.py b/test/python/dockerpy/tests/test_info_version.py deleted file mode 100644 index e3ee18ec7..000000000 --- a/test/python/dockerpy/tests/test_info_version.py +++ /dev/null @@ -1,44 +0,0 @@ -import unittest - -from . import common, constant - -client = common.get_client() - - -class TestInfo_Version(unittest.TestCase): - - podman = None - topContainerId = "" - - def setUp(self): - super().setUp() - common.restore_image_from_cache(self) - TestInfo_Version.topContainerId = common.run_top_container() - - def tearDown(self): - common.remove_all_containers() - common.remove_all_images() - return super().tearDown() - - @classmethod - def setUpClass(cls): - super().setUpClass() - common.enable_sock(cls) - - @classmethod - def tearDownClass(cls): - common.terminate_connection(cls) - return super().tearDownClass() - - def test_Info(self): - self.assertIsNotNone(client.info()) - - def test_info_container_details(self): - info = client.info() - self.assertEqual(info["Containers"], 1) - client.create_container(image=constant.ALPINE) - info = client.info() - self.assertEqual(info["Containers"], 2) - - def test_version(self): - self.assertIsNotNone(client.version()) diff --git a/test/system/030-run.bats b/test/system/030-run.bats index b0c855d81..12df966e2 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -436,6 +436,16 @@ json-file | f @test "podman run --log-driver journald" { skip_if_remote "We cannot read journalctl over remote." + # We can't use journald on RHEL as rootless, either: rhbz#1895105 + if is_rootless; then + run journalctl -n 1 + if [[ $status -ne 0 ]]; then + if [[ $output =~ permission ]]; then + skip "Cannot use rootless journald on this system" + fi + fi + fi + msg=$(random_string 20) pidfile="${PODMAN_TMPDIR}/$(random_string 20)" diff --git a/test/system/035-logs.bats b/test/system/035-logs.bats index 130bc5243..a3d6a5800 100644 --- a/test/system/035-logs.bats +++ b/test/system/035-logs.bats @@ -51,6 +51,16 @@ ${cid[0]} d" "Sequential output from logs" } @test "podman logs over journald" { + # We can't use journald on RHEL as rootless: rhbz#1895105 + if is_rootless; then + run journalctl -n 1 + if [[ $status -ne 0 ]]; then + if [[ $output =~ permission ]]; then + skip "Cannot use rootless journald on this system" + fi + fi + fi + msg=$(random_string 20) run_podman run --name myctr --log-driver journald $IMAGE echo $msg diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go index 18fab5485..c6a9a660e 100644 --- a/vendor/github.com/containers/common/pkg/config/config.go +++ b/vendor/github.com/containers/common/pkg/config/config.go @@ -282,7 +282,7 @@ type EngineConfig struct { PullPolicy string `toml:"pull_policy,omitempty"` // Indicates whether the application should be running in Remote mode - Remote bool `toml:"-"` + Remote bool `toml:"remote,omitempty"` // RemoteURI is deprecated, see ActiveService // RemoteURI containers connection information used to connect to remote system. diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf index 261cfd1cb..e8519b251 100644 --- a/vendor/github.com/containers/common/pkg/config/containers.conf +++ b/vendor/github.com/containers/common/pkg/config/containers.conf @@ -76,10 +76,10 @@ default_capabilities = [ # A list of sysctls to be set in containers by default, # specified as "name=value", -# for example:"net.ipv4.ping_group_range = 0 1". +# for example:"net.ipv4.ping_group_range = 0 0". # default_sysctls = [ - "net.ipv4.ping_group_range=0 1", + "net.ipv4.ping_group_range=0 0", ] # A list of ulimits to be set in containers by default, specified as @@ -357,6 +357,11 @@ default_sysctls = [ # Whether to pull new image before running a container # pull_policy = "missing" +# Indicates whether the application should be running in remote mode. This flag modifies the +# --remote option on container engines. Setting the flag to true will default +# `podman --remote=true` for access to the remote Podman service. +# remote = false + # Directory for persistent engine files (database, etc) # By default, this will be configured relative to where the containers/storage # stores containers diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index 8e497e7fa..ef7c612e2 100644 --- a/vendor/github.com/containers/common/version/version.go +++ b/vendor/github.com/containers/common/version/version.go @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "0.26.3" +const Version = "0.27.0" diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go index a8e2fbfa8..ee09adc8d 100644 --- a/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go +++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go @@ -24,7 +24,6 @@ import ( type cniNetworkPlugin struct { cniConfig *libcni.CNIConfig - loNetwork *cniNetwork sync.RWMutex defaultNetName netName @@ -217,7 +216,6 @@ func initCNI(exec cniinvoke.Exec, cacheDir, defaultNetName string, confDir strin changeable: defaultNetName == "", }, networks: make(map[string]*cniNetwork), - loNetwork: getLoNetwork(), confDir: confDir, binDirs: binDirs, shutdownChan: make(chan struct{}), @@ -335,31 +333,9 @@ func loadNetworks(confDir string, cni *libcni.CNIConfig) (map[string]*cniNetwork } const ( - loIfname string = "lo" - loNetname string = "cni-loopback" + loIfname string = "lo" ) -func getLoNetwork() *cniNetwork { - loConfig, err := libcni.ConfListFromBytes([]byte(fmt.Sprintf(`{ - "cniVersion": "0.3.1", - "name": "%s", - "plugins": [{ - "type": "loopback" - }] -}`, loNetname))) - if err != nil { - // The hardcoded config above should always be valid and unit tests will - // catch this - panic(err) - } - loNetwork := &cniNetwork{ - name: loIfname, - config: loConfig, - } - - return loNetwork -} - func (plugin *cniNetworkPlugin) syncNetworkConfig() error { networks, defaultNetName, err := loadNetworks(plugin.confDir, plugin.cniConfig) if err != nil { @@ -525,16 +501,11 @@ func (plugin *cniNetworkPlugin) forEachNetwork(podNetwork *PodNetwork, fromCache return nil } -func buildLoopbackRuntimeConf(cacheDir string, podNetwork *PodNetwork) *libcni.RuntimeConf { - return &libcni.RuntimeConf{ - ContainerID: podNetwork.ID, - NetNS: podNetwork.NetNS, - CacheDir: cacheDir, - IfName: loIfname, - } +func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]NetResult, error) { + return plugin.SetUpPodWithContext(context.Background(), podNetwork) } -func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]NetResult, error) { +func (plugin *cniNetworkPlugin) SetUpPodWithContext(ctx context.Context, podNetwork PodNetwork) ([]NetResult, error) { if err := plugin.networksAvailable(&podNetwork); err != nil { return nil, err } @@ -542,15 +513,15 @@ func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]NetResult, er plugin.podLock(podNetwork).Lock() defer plugin.podUnlock(podNetwork) - loRt := buildLoopbackRuntimeConf(plugin.cacheDir, &podNetwork) - if _, err := plugin.loNetwork.addToNetwork(loRt, plugin.cniConfig); err != nil { - logrus.Errorf("Error while adding to cni lo network: %s", err) + // Set up loopback interface + if err := bringUpLoopback(podNetwork.NetNS); err != nil { + logrus.Errorf(err.Error()) return nil, err } results := make([]NetResult, 0) if err := plugin.forEachNetwork(&podNetwork, false, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error { - result, err := network.addToNetwork(rt, plugin.cniConfig) + result, err := network.addToNetwork(ctx, rt, plugin.cniConfig) if err != nil { logrus.Errorf("Error while adding pod to CNI network %q: %s", network.name, err) return err @@ -622,7 +593,7 @@ func (plugin *cniNetworkPlugin) getCachedNetworkInfo(containerID string) ([]NetA continue } // Ignore the loopback interface; it's handled separately - if cachedInfo.IfName == loIfname && cachedInfo.NetName == loNetname { + if cachedInfo.IfName == loIfname && cachedInfo.NetName == "cni-loopback" { continue } if cachedInfo.IfName == "" || cachedInfo.NetName == "" { @@ -641,6 +612,10 @@ func (plugin *cniNetworkPlugin) getCachedNetworkInfo(containerID string) ([]NetA // TearDownPod tears down pod networks. Prefers cached pod attachment information // but falls back to given network attachment information. func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error { + return plugin.TearDownPodWithContext(context.Background(), podNetwork) +} + +func (plugin *cniNetworkPlugin) TearDownPodWithContext(ctx context.Context, podNetwork PodNetwork) error { if len(podNetwork.Networks) == 0 { attachments, err := plugin.getCachedNetworkInfo(podNetwork.ID) if err == nil && len(attachments) > 0 { @@ -652,17 +627,16 @@ func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error { return err } - loRt := buildLoopbackRuntimeConf(plugin.cacheDir, &podNetwork) - if err := plugin.loNetwork.deleteFromNetwork(loRt, plugin.cniConfig); err != nil { - logrus.Errorf("Error while removing pod from CNI lo network: %v", err) - // Loopback teardown errors are not fatal - } - plugin.podLock(podNetwork).Lock() defer plugin.podUnlock(podNetwork) + if err := tearDownLoopback(podNetwork.NetNS); err != nil { + // ignore error + logrus.Errorf("Ignoring error tearing down loopback interface: %v", err) + } + return plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error { - if err := network.deleteFromNetwork(rt, plugin.cniConfig); err != nil { + if err := network.deleteFromNetwork(ctx, rt, plugin.cniConfig); err != nil { logrus.Errorf("Error while removing pod from CNI network %q: %s", network.name, err) return err } @@ -673,12 +647,23 @@ func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error { // GetPodNetworkStatus returns IP addressing and interface details for all // networks attached to the pod. func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]NetResult, error) { + return plugin.GetPodNetworkStatusWithContext(context.Background(), podNetwork) +} + +// GetPodNetworkStatusWithContext returns IP addressing and interface details for all +// networks attached to the pod. +func (plugin *cniNetworkPlugin) GetPodNetworkStatusWithContext(ctx context.Context, podNetwork PodNetwork) ([]NetResult, error) { plugin.podLock(podNetwork).Lock() defer plugin.podUnlock(podNetwork) + if err := checkLoopback(podNetwork.NetNS); err != nil { + logrus.Errorf(err.Error()) + return nil, err + } + results := make([]NetResult, 0) if err := plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error { - result, err := network.checkNetwork(rt, plugin.cniConfig, plugin.nsManager, podNetwork.NetNS) + result, err := network.checkNetwork(ctx, rt, plugin.cniConfig, plugin.nsManager, podNetwork.NetNS) if err != nil { logrus.Errorf("Error while checking pod to CNI network %q: %s", network.name, err) return err @@ -700,9 +685,9 @@ func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]Ne return results, nil } -func (network *cniNetwork) addToNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig) (cnitypes.Result, error) { +func (network *cniNetwork) addToNetwork(ctx context.Context, rt *libcni.RuntimeConf, cni *libcni.CNIConfig) (cnitypes.Result, error) { logrus.Infof("About to add CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type) - res, err := cni.AddNetworkList(context.Background(), network.config, rt) + res, err := cni.AddNetworkList(ctx, network.config, rt) if err != nil { logrus.Errorf("Error adding network: %v", err) return nil, err @@ -711,7 +696,7 @@ func (network *cniNetwork) addToNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIC return res, nil } -func (network *cniNetwork) checkNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig, nsManager *nsManager, netns string) (cnitypes.Result, error) { +func (network *cniNetwork) checkNetwork(ctx context.Context, rt *libcni.RuntimeConf, cni *libcni.CNIConfig, nsManager *nsManager, netns string) (cnitypes.Result, error) { logrus.Infof("About to check CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type) gtet, err := cniversion.GreaterThanOrEqualTo(network.config.CNIVersion, "0.4.0") @@ -723,7 +708,7 @@ func (network *cniNetwork) checkNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIC // When CNIVersion supports Check, use it. Otherwise fall back on what was done initially. if gtet { - err = cni.CheckNetworkList(context.Background(), network.config, rt) + err = cni.CheckNetworkList(ctx, network.config, rt) logrus.Infof("Checking CNI network %s (config version=%v)", network.name, network.config.CNIVersion) if err != nil { logrus.Errorf("Error checking network: %v", err) @@ -783,9 +768,9 @@ func (network *cniNetwork) checkNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIC return converted, nil } -func (network *cniNetwork) deleteFromNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig) error { +func (network *cniNetwork) deleteFromNetwork(ctx context.Context, rt *libcni.RuntimeConf, cni *libcni.CNIConfig) error { logrus.Infof("About to del CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type) - if err := cni.DelNetworkList(context.Background(), network.config, rt); err != nil { + if err := cni.DelNetworkList(ctx, network.config, rt); err != nil { logrus.Errorf("Error deleting network: %v", err) return err } @@ -848,6 +833,10 @@ func buildCNIRuntimeConf(cacheDir string, podNetwork *PodNetwork, ifName string, rt.CapabilityArgs["ipRanges"] = runtimeConfig.IpRanges } + // Set Aliases in Capabilities + if len(podNetwork.Aliases) > 0 { + rt.CapabilityArgs["aliases"] = podNetwork.Aliases + } return rt, nil } diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go index 717ecda33..7326b4b40 100644 --- a/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go +++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go @@ -1,6 +1,8 @@ package ocicni import ( + "context" + "github.com/containernetworking/cni/pkg/types" ) @@ -87,6 +89,11 @@ type PodNetwork struct { // It is optional, and can be omitted for some or all specified networks // without issue. RuntimeConfig map[string]RuntimeConfig + + // Aliases are network-scoped names for resolving a container + // by name. The key value is the network name and the value is + // is a string slice of aliases + Aliases map[string][]string } // NetAttachment describes a container network attachment @@ -122,12 +129,21 @@ type CNIPlugin interface { // pod are launched. SetUpPod(network PodNetwork) ([]NetResult, error) + // SetUpPodWithContext is the same as SetUpPod but takes a context + SetUpPodWithContext(ctx context.Context, network PodNetwork) ([]NetResult, error) + // TearDownPod is the method called before a pod's sandbox container will be deleted TearDownPod(network PodNetwork) error - // Status is the method called to obtain the ipv4 or ipv6 addresses of the pod sandbox + // TearDownPodWithContext is the same as TearDownPod but takes a context + TearDownPodWithContext(ctx context.Context, network PodNetwork) error + + // GetPodNetworkStatus is the method called to obtain the ipv4 or ipv6 addresses of the pod sandbox GetPodNetworkStatus(network PodNetwork) ([]NetResult, error) + // GetPodNetworkStatusWithContext is the same as GetPodNetworkStatus but takes a context + GetPodNetworkStatusWithContext(ctx context.Context, network PodNetwork) ([]NetResult, error) + // NetworkStatus returns error if the network plugin is in error state Status() error diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/util_linux.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/util_linux.go index d263ae4df..53c22f83f 100644 --- a/vendor/github.com/cri-o/ocicni/pkg/ocicni/util_linux.go +++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/util_linux.go @@ -7,6 +7,9 @@ import ( "net" "os/exec" "strings" + + "github.com/containernetworking/plugins/pkg/ns" + "github.com/vishvananda/netlink" ) var defaultNamespaceEnterCommandName = "nsenter" @@ -69,3 +72,79 @@ func getContainerDetails(nsm *nsManager, netnsPath, interfaceName, addrType stri return ipNet, &mac, nil } + +func tearDownLoopback(netns string) error { + return ns.WithNetNSPath(netns, func(_ ns.NetNS) error { + link, err := netlink.LinkByName(loIfname) + if err != nil { + return err // not tested + } + err = netlink.LinkSetDown(link) + if err != nil { + return err // not tested + } + return nil + }) +} + +func bringUpLoopback(netns string) error { + if err := ns.WithNetNSPath(netns, func(_ ns.NetNS) error { + link, err := netlink.LinkByName(loIfname) + if err == nil { + err = netlink.LinkSetUp(link) + } + if err != nil { + return err + } + + v4Addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) + if err != nil { + return err + } + if len(v4Addrs) != 0 { + // sanity check that this is a loopback address + for _, addr := range v4Addrs { + if !addr.IP.IsLoopback() { + return fmt.Errorf("loopback interface found with non-loopback address %q", addr.IP) + } + } + } + + v6Addrs, err := netlink.AddrList(link, netlink.FAMILY_V6) + if err != nil { + return err + } + if len(v6Addrs) != 0 { + // sanity check that this is a loopback address + for _, addr := range v6Addrs { + if !addr.IP.IsLoopback() { + return fmt.Errorf("loopback interface found with non-loopback address %q", addr.IP) + } + } + } + + return nil + }); err != nil { + return fmt.Errorf("error adding loopback interface: %s", err) + } + return nil +} + +func checkLoopback(netns string) error { + // Make sure loopback interface is up + if err := ns.WithNetNSPath(netns, func(_ ns.NetNS) error { + link, err := netlink.LinkByName(loIfname) + if err != nil { + return err + } + + if link.Attrs().Flags&net.FlagUp != net.FlagUp { + return fmt.Errorf("loopback interface is down") + } + + return nil + }); err != nil { + return fmt.Errorf("error checking loopback interface: %v", err) + } + return nil +} diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/util_unsupported.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/util_unsupported.go index 0b1c72208..b87f0d373 100644 --- a/vendor/github.com/cri-o/ocicni/pkg/ocicni/util_unsupported.go +++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/util_unsupported.go @@ -3,17 +3,32 @@ package ocicni import ( - "fmt" + "errors" "net" ) type nsManager struct { } +var errUnsupportedPlatform = errors.New("unsupported platform") + func (nsm *nsManager) init() error { return nil } func getContainerDetails(nsm *nsManager, netnsPath, interfaceName, addrType string) (*net.IPNet, *net.HardwareAddr, error) { - return nil, nil, fmt.Errorf("not supported yet") + return nil, nil, errUnsupportedPlatform +} + +func tearDownLoopback(netns string) error { + return errUnsupportedPlatform +} + +func bringUpLoopback(netns string) error { + return errUnsupportedPlatform +} + +func checkLoopback(netns string) error { + return errUnsupportedPlatform + } diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go index 49252a06d..f6e5e56ed 100644 --- a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go @@ -111,7 +111,7 @@ func annotateEPERM(origErr error, spec port.Spec) error { // origErr is unrelated to ip_unprivileged_port_start return origErr } - text := fmt.Sprintf("cannot expose privileged port %d, you might need to add \"net.ipv4.ip_unprivileged_port_start=0\" (currently %d) to /etc/sysctl.conf", spec.ParentPort, start) + text := fmt.Sprintf("cannot expose privileged port %d, you can add 'net.ipv4.ip_unprivileged_port_start=%d' to /etc/sysctl.conf (currently %d)", spec.ParentPort, spec.ParentPort, start) if filepath.Base(os.Args[0]) == "rootlesskit" { // NOTE: The following sentence is appended only if Args[0] == "rootlesskit", because it does not apply to Podman (as of Podman v1.9). // Podman launches the parent driver in the child user namespace (but in the parent network namespace), which disables the file capability. diff --git a/vendor/modules.txt b/vendor/modules.txt index 79db4807e..6264a8d51 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -87,7 +87,7 @@ github.com/containers/buildah/pkg/secrets github.com/containers/buildah/pkg/supplemented github.com/containers/buildah/pkg/umask github.com/containers/buildah/util -# github.com/containers/common v0.26.3 +# github.com/containers/common v0.27.0 github.com/containers/common/pkg/apparmor github.com/containers/common/pkg/apparmor/internal/supported github.com/containers/common/pkg/auth @@ -216,7 +216,7 @@ github.com/coreos/go-systemd/v22/dbus github.com/coreos/go-systemd/v22/internal/dlopen github.com/coreos/go-systemd/v22/journal github.com/coreos/go-systemd/v22/sdjournal -# github.com/cri-o/ocicni v0.2.0 +# github.com/cri-o/ocicni v0.2.1-0.20201102180012-75c612fda1a2 => github.com/cri-o/ocicni v0.2.1-0.20201109200316-afdc16ba66df github.com/cri-o/ocicni/pkg/ocicni # github.com/cyphar/filepath-securejoin v0.2.2 github.com/cyphar/filepath-securejoin @@ -478,7 +478,7 @@ github.com/prometheus/common/model # github.com/prometheus/procfs v0.0.3 github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs -# github.com/rootless-containers/rootlesskit v0.11.0 +# github.com/rootless-containers/rootlesskit v0.11.1 github.com/rootless-containers/rootlesskit/pkg/msgutil github.com/rootless-containers/rootlesskit/pkg/port github.com/rootless-containers/rootlesskit/pkg/port/builtin |