diff options
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | cmd/podman/common/create_opts.go | 13 | ||||
-rw-r--r-- | cmd/podman/diff/diff.go | 2 | ||||
-rw-r--r-- | cmd/podman/root.go | 10 | ||||
-rwxr-xr-x | docs/dckrman.sh | 2 | ||||
-rw-r--r-- | docs/source/markdown/podman-build.1.md | 42 | ||||
-rw-r--r-- | docs/source/markdown/podman-remote.1.md | 22 | ||||
-rw-r--r-- | docs/source/markdown/podman-search.1.md | 2 | ||||
-rw-r--r-- | docs/source/markdown/podman.1.md | 57 | ||||
-rw-r--r-- | libpod/container_copy_linux.go | 2 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 5 | ||||
-rw-r--r-- | libpod/kube.go | 21 | ||||
-rw-r--r-- | libpod/network/cni/cni_types.go | 2 | ||||
-rw-r--r-- | libpod/network/cni/config_test.go | 18 | ||||
-rw-r--r-- | pkg/machine/pull.go | 2 | ||||
-rw-r--r-- | pkg/specgen/specgen.go | 2 | ||||
-rw-r--r-- | test/apiv2/20-containers.at | 18 | ||||
-rw-r--r-- | test/e2e/checkpoint_test.go | 11 | ||||
-rw-r--r-- | test/e2e/generate_kube_test.go | 113 | ||||
-rw-r--r-- | test/e2e/network_create_test.go | 6 | ||||
-rw-r--r-- | test/e2e/run_volume_test.go | 12 | ||||
-rw-r--r-- | test/system/001-basic.bats | 9 | ||||
-rw-r--r-- | troubleshooting.md | 2 |
23 files changed, 301 insertions, 83 deletions
@@ -176,6 +176,15 @@ define go-get $(GO) get -u ${1} endef +# Need to use CGO for mDNS resolution, but cross builds need CGO disabled +# See https://github.com/golang/go/issues/12524 for details +DARWIN_GCO := 0 +ifeq ($(NATIVE_GOOS),darwin) +ifdef HOMEBREW_PREFIX + DARWIN_GCO := 1 +endif +endif + ### ### Primary entry-point targets ### @@ -351,7 +360,7 @@ podman-remote-windows: ## Build podman-remote for Windows .PHONY: podman-remote-darwin podman-remote-darwin: ## Build podman-remote for macOS $(MAKE) \ - CGO_ENABLED=0 \ + CGO_ENABLED=$(DARWIN_GCO) \ GOOS=darwin \ GOARCH=$(GOARCH) \ bin/darwin/podman diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index 09ac61f2e..50d7c446d 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -104,15 +104,18 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c addField(&builder, "target", m.Target) addField(&builder, "ro", strconv.FormatBool(m.ReadOnly)) addField(&builder, "consistency", string(m.Consistency)) - // Map any specialized mount options that intersect between *Options and cli options switch m.Type { case mount.TypeBind: - addField(&builder, "bind-propagation", string(m.BindOptions.Propagation)) - addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive)) + if m.BindOptions != nil { + addField(&builder, "bind-propagation", string(m.BindOptions.Propagation)) + addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive)) + } case mount.TypeTmpfs: - addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10)) - addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 10)) + if m.TmpfsOptions != nil { + addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10)) + addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 10)) + } case mount.TypeVolume: // All current VolumeOpts are handled above // See vendor/github.com/containers/common/pkg/parse/parse.go:ValidateVolumeOpts() diff --git a/cmd/podman/diff/diff.go b/cmd/podman/diff/diff.go index 81bbb6c43..fba4ea540 100644 --- a/cmd/podman/diff/diff.go +++ b/cmd/podman/diff/diff.go @@ -8,7 +8,7 @@ import ( "github.com/containers/common/pkg/report" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/pkg/domain/entities" - "github.com/docker/docker/pkg/archive" + "github.com/containers/storage/pkg/archive" "github.com/pkg/errors" "github.com/spf13/cobra" ) diff --git a/cmd/podman/root.go b/cmd/podman/root.go index eb30f1ef6..734636646 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -314,7 +314,15 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { lFlags.StringVar(&opts.Identity, identityFlagName, ident, "path to SSH identity file, (CONTAINER_SSHKEY)") _ = cmd.RegisterFlagCompletionFunc(identityFlagName, completion.AutocompleteDefault) - lFlags.BoolVarP(&opts.Remote, "remote", "r", false, "Access remote Podman service (default false)") + remote := false + if env, ok := os.LookupEnv("CONTAINER_HOST"); ok { + logrus.Infof("CONTAINER_HOST==%q, defaulting to '--remote=true'", env) + remote = true + } else if env, ok := os.LookupEnv("CONTAINER_CONNECTION"); ok { + logrus.Infof("CONTAINER_CONNECTION==%q, defaulting to '--remote=true'", env) + remote = true + } + lFlags.BoolVarP(&opts.Remote, "remote", "r", remote, "Access remote Podman service") pFlags := cmd.PersistentFlags() if registry.IsRemote() { if err := lFlags.MarkHidden("remote"); err != nil { diff --git a/docs/dckrman.sh b/docs/dckrman.sh index 18fb364bf..48685a14b 100755 --- a/docs/dckrman.sh +++ b/docs/dckrman.sh @@ -5,3 +5,5 @@ for i in $@; do echo .so man1/$b > $filename done echo .so man5/containerfile.5 > $(dirname $1)/dockerfile.5 +echo .so man5/containerignore.5 > $(dirname $1)/.dockerignore.5 +echo .so man5/containerignore.5 > $(dirname $1)/dockerignore.5 diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md index 15d936d17..fd36166b6 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -35,8 +35,8 @@ location. 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 +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` @@ -256,7 +256,7 @@ specifying **--disable-compression=false**. #### **--disable-content-trust** -This is a Docker specific option to disable image verification to a Docker +This is a Docker specific option to disable image verification to a container registry and is not supported by Podman. This flag is a NOOP and provided solely for scripting compatibility. (This option is not available with the remote Podman client) @@ -328,7 +328,7 @@ than once, attempting to use this option will trigger an error. #### **--ignorefile** -Path to an alternative .dockerignore file. +Path to an alternative .containerignore file. #### **--ipc**=*how* @@ -845,15 +845,15 @@ $ podman build . $ podman build -f Containerfile.simple . -$ cat $HOME/Dockerfile | podman build -f - . +$ cat $HOME/Containerfile | podman build -f - . -$ podman build -f Dockerfile.simple -f Containerfile.notsosimple . +$ podman build -f Containerfile.simple -f Containerfile.notsosimple . -$ podman build -f Dockerfile.in $HOME +$ podman build -f Containerfile.in $HOME $ podman build -t imageName . -$ podman build --tls-verify=true -t imageName -f Dockerfile.simple . +$ podman build --tls-verify=true -t imageName -f Containerfile.simple . $ podman build --tls-verify=false -t imageName . @@ -861,7 +861,7 @@ $ podman build --runtime-flag log-format=json . $ podman build --runtime-flag debug . -$ podman build --authfile /tmp/auths/myauths.json --cert-dir $HOME/auth --tls-verify=true --creds=username:password -t imageName -f Dockerfile.simple . +$ podman build --authfile /tmp/auths/myauths.json --cert-dir $HOME/auth --tls-verify=true --creds=username:password -t imageName -f Containerfile.simple . $ podman build --memory 40m --cpu-period 10000 --cpu-quota 50000 --ulimit nofile=1024:1028 -t imageName . @@ -940,22 +940,26 @@ $ podman build -f dev/Containerfile https://10.10.10.1/podman/context.tar.gz ## Files -### `.dockerignore` +### .containerignore/.dockerignore -If the file .dockerignore exists in the context directory, `buildah copy` reads -its contents. Use the `--ignorefile` flag to override .dockerignore path location. +If the file *.containerignore* or *.dockerignore* exists in the context directory, +`podman build` reads its contents. Use the `--ignorefile` flag to override the +.containerignore path location. Podman uses the content to exclude files and directories from the context directory, when executing COPY and ADD directives in the Containerfile/Dockerfile -Users can specify a series of Unix shell globals in a .dockerignore file to +The .containerignore and .dockerignore files use the same syntax; if both +are in the context directory, podman build will only use .containerignore. + +Users can specify a series of Unix shell globs in a .containerignore file to identify files/directories to exclude. Podman supports a special wildcard string `**` which matches any number of directories (including zero). For example, **/*.go will exclude all files that end with .go that are found in all directories. -Example .dockerignore file: +Example .containerignore file: ``` # exclude this content for image @@ -975,7 +979,7 @@ Excludes files and directories starting with `output` from any directory. Excludes files named src and the directory src as well as any content in it. Lines starting with ! (exclamation mark) can be used to make exceptions to -exclusions. The following is an example .dockerignore file that uses this +exclusions. The following is an example .containerignore file that uses this mechanism: ``` *.doc @@ -984,10 +988,10 @@ mechanism: Exclude all doc files except Help.doc from the image. -This functionality is compatible with the handling of .dockerignore files +This functionality is compatible with the handling of .containerignore files described here: -https://docs.docker.com/engine/reference/builder/#dockerignore-file +https://github.com/containers/buildah/blob/main/docs/containerignore.5.md **registries.conf** (`/etc/containers/registries.conf`) @@ -1009,10 +1013,10 @@ If you are using `useradd` within your build script, you should pass the useradd to stop creating the lastlog file. ## SEE ALSO -podman(1), buildah(1), containers-certs.d(5), containers-registries.conf(5), crun(8), runc(8), useradd(8), podman-ps(1), podman-rm(1) +podman(1), buildah(1), containers-certs.d(5), containers-registries.conf(5), crun(8), runc(8), useradd(8), podman-ps(1), podman-rm(1), Containerfile(5), containerignore(5) ## HISTORY -Aug 2020, Additional options and .dockerignore added by Dan Walsh `<dwalsh@redhat.com>` +Aug 2020, Additional options and .containerignore added by Dan Walsh `<dwalsh@redhat.com>` May 2018, Minor revisions added by Joe Doss `<joe@solidadmin.com>` diff --git a/docs/source/markdown/podman-remote.1.md b/docs/source/markdown/podman-remote.1.md index 1a6c7d3cc..fb77f3300 100644 --- a/docs/source/markdown/podman-remote.1.md +++ b/docs/source/markdown/podman-remote.1.md @@ -29,6 +29,8 @@ The `containers.conf` file should be placed under `$HOME/.config/containers/cont Remote connection name +Overrides environment variable `CONTAINER_CONNECTION` if set. + #### **--help**, **-h** Print usage statement @@ -71,6 +73,26 @@ URL value resolution precedence: Print the version +## Environment Variables + +Podman can set up environment variables from env of [engine] table in containers.conf. These variables can be overridden by passing environment variables before the `podman` commands. + +#### **CONTAINERS_CONF** + +Set default locations of containers.conf file + +#### **CONTAINER_CONNECTION** + +Set default `--connection` value to access Podman service. + +#### **CONTAINER_HOST** + +Set default `--url` value to access Podman service. + +#### **CONTAINER_SSHKEY** + +Set default `--identity` path to ssh key file value used to access Podman service. + ## Exit Status The exit code from `podman` gives information about why the container diff --git a/docs/source/markdown/podman-search.1.md b/docs/source/markdown/podman-search.1.md index 7c37e389c..911bbcb4b 100644 --- a/docs/source/markdown/podman-search.1.md +++ b/docs/source/markdown/podman-search.1.md @@ -40,7 +40,7 @@ environment variable. `export REGISTRY_AUTH_FILE=path` #### **--compatible** After the name and the description, also show the stars, official and automated descriptors as Docker does. -Podman does not show these decsriptors by default since they are not supported by most public container registries. +Podman does not show these descriptors by default since they are not supported by most public container registries. #### **--filter**, **-f**=*filter* diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 4de8b6ea6..beb6e26d8 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -93,8 +93,9 @@ When namespace is set, created containers and pods will join the given namespace 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** -Access Podman service will be remote -Remote connections use local containers.conf for default. +When true, access to the Podman service will be remote. Defaults to false. +Settings can be modified in the containers.conf file. If the CONTAINER_HOST +environment variable is set, the remote option defaults to true. #### **--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`). @@ -172,6 +173,58 @@ Print the version Podman can set up environment variables from env of [engine] table in containers.conf. These variables can be overridden by passing environment variables before the `podman` commands. +#### **CONTAINERS_CONF** + +Set default locations of containers.conf file + +#### **CONTAINERS_REGISTRIES_CONF** + +Set default location of the registries.conf file. + +#### **CONTAINERS_STORAGE_CONF** + +Set default location of the storage.conf file. + +#### **CONTAINER_CONNECTION** + +Override default `--connection` value to access Podman service. Also enabled --remote option. + +#### **CONTAINER_HOST** + +Set default `--url` value to access Podman service. Also enabled --remote option. + +#### **CONTAINER_SSHKEY** + +Set default `--identity` path to ssh key file value used to access Podman service. + +#### **STORAGE_DRIVER** + +Set default `--storage-driver` value. + +#### **STORAGE_OPTS** + +Set default `--storage-opts` value. + +#### **TMPDIR** + +Set the the temporary storage location of downloaded container images. Podman defaults to use `/var/tmp`. + +#### **XDG_CONFIG_HOME** + +In Rootless mode configuration files are read from `XDG_CONFIG_HOME` when +specified, otherwise in the home directory of the user under +`$HOME/.config/containers`. + +#### **XDG_DATA_HOME** + +In Rootless mode images are pulled under `XDG_DATA_HOME` when specified, +otherwise in the home directory of the user under +`$HOME/.local/share/containers/storage`. + +#### **XDG_RUNTIME_DIR** + +In Rootless mode temporary configuration data is stored in `${XDG_RUNTIME_DIR}/containers`. + ## Remote Access The Podman command can be used with remote services using the `--remote` flag. Connections can diff --git a/libpod/container_copy_linux.go b/libpod/container_copy_linux.go index 7d4dd0d46..954d54a1d 100644 --- a/libpod/container_copy_linux.go +++ b/libpod/container_copy_linux.go @@ -15,8 +15,8 @@ import ( "github.com/containers/buildah/util" "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/rootless" + "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/idtools" - "github.com/docker/docker/pkg/archive" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index f652a3ebb..d8385961f 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -1008,12 +1008,15 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error { includeFiles := []string{ "artifacts", - "ctr.log", metadata.ConfigDumpFile, metadata.SpecDumpFile, metadata.NetworkStatusFile, } + if c.LogDriver() == define.KubernetesLogging || + c.LogDriver() == define.JSONLogging { + includeFiles = append(includeFiles, "ctr.log") + } if options.PreCheckPoint { includeFiles = append(includeFiles, preCheckpointDir) } else { diff --git a/libpod/kube.go b/libpod/kube.go index eb7743886..d47f47f1c 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -25,6 +25,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" v12 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" ) // GenerateForKube takes a slice of libpod containers and generates @@ -196,10 +197,11 @@ func containerPortsToServicePorts(containerPorts []v1.ContainerPort) []v1.Servic for _, cp := range containerPorts { nodePort := 30000 + rand.Intn(32767-30000+1) servicePort := v1.ServicePort{ - Protocol: cp.Protocol, - Port: cp.ContainerPort, - NodePort: int32(nodePort), - Name: strconv.Itoa(int(cp.ContainerPort)), + Protocol: cp.Protocol, + Port: cp.ContainerPort, + NodePort: int32(nodePort), + Name: strconv.Itoa(int(cp.ContainerPort)), + TargetPort: intstr.Parse(strconv.Itoa(int(cp.ContainerPort))), } sps = append(sps, servicePort) } @@ -481,10 +483,16 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, [] if err != nil { return kubeContainer, kubeVolumes, nil, annotations, err } - if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) { + // If the user doesn't set a command/entrypoint when creating the container with podman and + // is using the image command or entrypoint from the image, don't add it to the generated kube yaml + if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) || reflect.DeepEqual(imgData.Config.Entrypoint, kubeContainer.Command) { kubeContainer.Command = nil } + if imgData.User == c.User() { + kubeSec.RunAsGroup, kubeSec.RunAsUser = nil, nil + } + kubeContainer.WorkingDir = c.WorkingDir() kubeContainer.Ports = ports // This should not be applicable @@ -572,7 +580,8 @@ func ocicniPortMappingToContainerPort(portMappings []types.OCICNIPortMapping) ([ var protocol v1.Protocol switch strings.ToUpper(p.Protocol) { case "TCP": - protocol = v1.ProtocolTCP + // do nothing as it is the default protocol in k8s, there is no need to explicitly + // add it to the generated yaml case "UDP": protocol = v1.ProtocolUDP default: diff --git a/libpod/network/cni/cni_types.go b/libpod/network/cni/cni_types.go index fbf917c2d..87beceff3 100644 --- a/libpod/network/cni/cni_types.go +++ b/libpod/network/cni/cni_types.go @@ -182,7 +182,7 @@ func newIPAMLocalHostRange(subnet types.IPNet, leaseRange *types.LeaseRange, gw hostRange.RangeStart = leaseRange.StartIP.String() } if leaseRange.EndIP != nil { - hostRange.RangeStart = leaseRange.EndIP.String() + hostRange.RangeEnd = leaseRange.EndIP.String() } } diff --git a/libpod/network/cni/config_test.go b/libpod/network/cni/config_test.go index 5181cd900..0dfc6173c 100644 --- a/libpod/network/cni/config_test.go +++ b/libpod/network/cni/config_test.go @@ -621,7 +621,7 @@ var _ = Describe("Config", func() { err = libpodNet.NetworkRemove(network1.Name) Expect(err).To(BeNil()) - endIP := "10.0.0.10" + endIP := "10.0.0.30" network = types.Network{ Driver: "bridge", Subnets: []types.Subnet{ @@ -665,6 +665,22 @@ var _ = Describe("Config", func() { Expect(network1.Subnets[0].Gateway.String()).To(Equal("10.0.0.1")) Expect(network1.Subnets[0].LeaseRange.StartIP.String()).To(Equal(startIP)) Expect(network1.Subnets[0].LeaseRange.EndIP.String()).To(Equal(endIP)) + + // create a new interface to force a config load from disk + libpodNet, err = getNetworkInterface(cniConfDir, false) + Expect(err).To(BeNil()) + + network1, err = libpodNet.NetworkInspect(network1.Name) + Expect(err).To(BeNil()) + Expect(network1.Name).ToNot(BeEmpty()) + Expect(network1.ID).ToNot(BeEmpty()) + Expect(network1.NetworkInterface).ToNot(BeEmpty()) + Expect(network1.Driver).To(Equal("bridge")) + Expect(network1.Subnets).To(HaveLen(1)) + Expect(network1.Subnets[0].Subnet.String()).To(Equal(subnet)) + Expect(network1.Subnets[0].Gateway.String()).To(Equal("10.0.0.1")) + Expect(network1.Subnets[0].LeaseRange.StartIP.String()).To(Equal(startIP)) + Expect(network1.Subnets[0].LeaseRange.EndIP.String()).To(Equal(endIP)) }) It("create bridge with subnet and invalid lease range", func() { diff --git a/pkg/machine/pull.go b/pkg/machine/pull.go index f79ac6ec4..3c8422a30 100644 --- a/pkg/machine/pull.go +++ b/pkg/machine/pull.go @@ -15,7 +15,7 @@ import ( "time" "github.com/containers/image/v5/pkg/compression" - "github.com/docker/docker/pkg/archive" + "github.com/containers/storage/pkg/archive" "github.com/sirupsen/logrus" "github.com/vbauerster/mpb/v6" "github.com/vbauerster/mpb/v6/decor" diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index 07995b2df..79185db04 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -551,7 +551,7 @@ func NewSpecGenerator(arg string, rootfs bool) *SpecGenerator { csc := ContainerStorageConfig{} if rootfs { csc.Rootfs = arg - // check if rootfs is actually overlayed + // check if rootfs should use overlay lastColonIndex := strings.LastIndex(csc.Rootfs, ":") if lastColonIndex != -1 && lastColonIndex+1 < len(csc.Rootfs) && csc.Rootfs[lastColonIndex+1:] == "O" { csc.RootfsOverlay = true diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at index afff68c22..748a0750f 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -379,3 +379,21 @@ t GET containers/$cid/json 200 \ .HostConfig.Tmpfs['"/mnt/scratch"']~.*mode=755.* t DELETE containers/$cid?v=true 204 + +# compat api: tmpfs without mount options +payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch"}]}' +t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\} +cid=$(jq -r '.Id' <<<"$output") +t GET containers/$cid/json 200 \ + .HostConfig.Tmpfs['"/mnt/scratch"']~.*tmpcopyup.* \ + +t DELETE containers/$cid?v=true 204 + +# compat api: bind mount without mount options +payload='{"Mounts":[{"Type":"bind","Source":"/tmp","Target":"/mnt"}]}' +t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\} +cid=$(jq -r '.Id' <<<"$output") +t GET containers/$cid/json 200 \ + .HostConfig.Binds[0]~/tmp:/mnt:.* \ + +t DELETE containers/$cid?v=true 204 diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index 993987f34..770a7c7bd 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -249,16 +249,19 @@ var _ = Describe("Podman checkpoint", func() { session := podmanTest.Podman(localRunString) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + cid := session.OutputToString() + if !WaitContainerReady(podmanTest, cid, "Ready to accept connections", 20, 1) { + Fail("Container failed to get ready") + } IP := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.IPAddress}}"}) IP.WaitWithDefaultTimeout() Expect(IP).Should(Exit(0)) // Open a network connection to the redis server - conn, err := net.Dial("tcp", IP.OutputToString()+":6379") - if err != nil { - os.Exit(1) - } + conn, err := net.DialTimeout("tcp4", IP.OutputToString()+":6379", time.Duration(3)*time.Second) + Expect(err).To(BeNil()) + // This should fail as the container has established TCP connections result := podmanTest.Podman([]string{"container", "checkpoint", "-l"}) result.WaitWithDefaultTimeout() diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 3e6f1e8c4..69941494b 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "github.com/containers/podman/v3/libpod/define" @@ -119,20 +120,28 @@ var _ = Describe("Podman generate kube", func() { Expect(kube.OutputToString()).To(ContainSubstring("type: foo_bar_t")) }) - It("podman generate service kube on container", func() { - session := podmanTest.RunTopContainer("top") + It("podman generate service kube on container - targetPort should match port name", func() { + session := podmanTest.Podman([]string{"create", "--name", "test-ctr", "-p", "3890:3890", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - kube := podmanTest.Podman([]string{"generate", "kube", "-s", "top"}) + kube := podmanTest.Podman([]string{"generate", "kube", "-s", "test-ctr"}) kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // TODO - test generated YAML - service produces multiple - // structs. - // pod := new(v1.Pod) - // err := yaml.Unmarshal([]byte(kube.OutputToString()), pod) - // Expect(err).To(BeNil()) + // Separate out the Service and Pod yaml + arr := strings.Split(string(kube.Out.Contents()), "---") + Expect(len(arr)).To(Equal(2)) + + svc := new(v1.Service) + err := yaml.Unmarshal([]byte(arr[0]), svc) + Expect(err).To(BeNil()) + Expect(len(svc.Spec.Ports)).To(Equal(1)) + Expect(svc.Spec.Ports[0].TargetPort.IntValue()).To(Equal(3890)) + + pod := new(v1.Pod) + err = yaml.Unmarshal([]byte(arr[1]), pod) + Expect(err).To(BeNil()) }) It("podman generate kube on pod", func() { @@ -315,21 +324,28 @@ var _ = Describe("Podman generate kube", func() { }) It("podman generate service kube on pod", func() { - _, rc, _ := podmanTest.CreatePod(map[string][]string{"--name": {"toppod"}}) - Expect(rc).To(Equal(0)) - - session := podmanTest.RunTopContainerInPod("topcontainer", "toppod") + session := podmanTest.Podman([]string{"create", "--pod", "new:test-pod", "-p", "4000:4000/udp", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - kube := podmanTest.Podman([]string{"generate", "kube", "-s", "toppod"}) + kube := podmanTest.Podman([]string{"generate", "kube", "-s", "test-pod"}) kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // TODO: How do we test unmarshal with a service? We have two - // structs that need to be unmarshalled... - // _, err := yaml.Marshal(kube.OutputToString()) - // Expect(err).To(BeNil()) + // Separate out the Service and Pod yaml + arr := strings.Split(string(kube.Out.Contents()), "---") + Expect(len(arr)).To(Equal(2)) + + svc := new(v1.Service) + err := yaml.Unmarshal([]byte(arr[0]), svc) + Expect(err).To(BeNil()) + Expect(len(svc.Spec.Ports)).To(Equal(1)) + Expect(svc.Spec.Ports[0].TargetPort.IntValue()).To(Equal(4000)) + Expect(svc.Spec.Ports[0].Protocol).To(Equal(v1.ProtocolUDP)) + + pod := new(v1.Pod) + err = yaml.Unmarshal([]byte(arr[1]), pod) + Expect(err).To(BeNil()) }) It("podman generate kube on pod with restartPolicy", func() { @@ -451,6 +467,10 @@ var _ = Describe("Podman generate kube", func() { foundOtherPort := 0 for _, ctr := range pod.Spec.Containers { for _, port := range ctr.Ports { + // Since we are using tcp here, the generated kube yaml shouldn't + // have anything for protocol under the ports as tcp is the default + // for k8s + Expect(port.Protocol).To(BeEmpty()) if port.HostPort == 4000 { foundPort4000 = foundPort4000 + 1 } else if port.HostPort == 5000 { @@ -463,6 +483,24 @@ var _ = Describe("Podman generate kube", func() { Expect(foundPort4000).To(Equal(1)) Expect(foundPort5000).To(Equal(1)) Expect(foundOtherPort).To(Equal(0)) + + // Create container with UDP port and check the generated kube yaml + ctrWithUDP := podmanTest.Podman([]string{"create", "--pod", "new:test-pod", "-p", "6666:66/udp", ALPINE, "top"}) + ctrWithUDP.WaitWithDefaultTimeout() + Expect(ctrWithUDP).Should(Exit(0)) + + kube = podmanTest.Podman([]string{"generate", "kube", "test-pod"}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + pod = new(v1.Pod) + err = yaml.Unmarshal(kube.Out.Contents(), pod) + Expect(err).To(BeNil()) + + containers := pod.Spec.Containers + Expect(len(containers)).To(Equal(1)) + Expect(len(containers[0].Ports)).To(Equal(1)) + Expect(containers[0].Ports[0].Protocol).To(Equal(v1.ProtocolUDP)) }) It("podman generate and reimport kube on pod", func() { @@ -803,7 +841,7 @@ var _ = Describe("Podman generate kube", func() { Expect(containers[0].Args).To(Equal([]string{"10s"})) }) - It("podman generate kube - no command", func() { + It("podman generate kube - use command from image unless explicitly set in the podman command", func() { session := podmanTest.Podman([]string{"create", "--name", "test", ALPINE}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -812,8 +850,8 @@ var _ = Describe("Podman generate kube", func() { kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // Now make sure that the container's command is not set to the - // entrypoint and it's arguments to "10s". + // Now make sure that the container's command in the kube yaml is not set to the + // image command. pod := new(v1.Pod) err := yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) @@ -831,8 +869,8 @@ var _ = Describe("Podman generate kube", func() { kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // Now make sure that the container's command is not set to the - // entrypoint and it's arguments to "10s". + // Now make sure that the container's command in the kube yaml is set to the + // command passed via the cli to podman create. pod = new(v1.Pod) err = yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) @@ -842,10 +880,10 @@ var _ = Describe("Podman generate kube", func() { Expect(containers[0].Command).To(Equal(cmd)) }) - It("podman generate kube - use entrypoint from image", func() { + It("podman generate kube - use entrypoint from image unless --entrypoint is set", func() { // Build an image with an entrypoint. containerfile := `FROM quay.io/libpod/alpine:latest -ENTRYPOINT /bin/sleep` +ENTRYPOINT ["sleep"]` targetPath, err := CreateTempDirInTempDir() Expect(err).To(BeNil()) @@ -866,17 +904,34 @@ ENTRYPOINT /bin/sleep` kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // Now make sure that the container's command is set to the - // entrypoint and it's arguments to "10s". + // Now make sure that the container's command in the kube yaml is NOT set to the + // entrypoint but the arguments should be set to "10s". pod := new(v1.Pod) err = yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) containers := pod.Spec.Containers Expect(len(containers)).To(Equal(1)) - - Expect(containers[0].Command).To(Equal([]string{"/bin/sh", "-c", "/bin/sleep"})) Expect(containers[0].Args).To(Equal([]string{"10s"})) + + session = podmanTest.Podman([]string{"create", "--pod", "new:testpod-2", "--entrypoint", "echo", image, "hello"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + kube = podmanTest.Podman([]string{"generate", "kube", "testpod-2"}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + // Now make sure that the container's command in the kube yaml is set to the + // entrypoint defined by the --entrypoint flag and the arguments should be set to "hello". + pod = new(v1.Pod) + err = yaml.Unmarshal(kube.Out.Contents(), pod) + Expect(err).To(BeNil()) + + containers = pod.Spec.Containers + Expect(len(containers)).To(Equal(1)) + Expect(containers[0].Command).To(Equal([]string{"echo"})) + Expect(containers[0].Args).To(Equal([]string{"hello"})) }) It("podman generate kube - --privileged container", func() { @@ -942,7 +997,7 @@ USER test1` pod := new(v1.Pod) err = yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) - Expect(*pod.Spec.Containers[0].SecurityContext.RunAsUser).To(Equal(int64(10001))) + Expect(pod.Spec.Containers[0].SecurityContext.RunAsUser).To(BeNil()) }) It("podman generate kube on named volume", func() { diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index ae9f112b5..c9e13e7d2 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -43,7 +43,7 @@ var _ = Describe("Podman network create", func() { It("podman network create with name and subnet", func() { netName := "subnet-" + stringid.GenerateNonCryptoID() - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", netName}) + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--ip-range", "10.11.12.0/26", netName}) nc.WaitWithDefaultTimeout() defer podmanTest.removeCNINetwork(netName) Expect(nc).Should(Exit(0)) @@ -61,7 +61,11 @@ var _ = Describe("Podman network create", func() { result := results[0] Expect(result.Name).To(Equal(netName)) Expect(result.Subnets).To(HaveLen(1)) + Expect(result.Subnets[0].Subnet.String()).To(Equal("10.11.12.0/24")) Expect(result.Subnets[0].Gateway.String()).To(Equal("10.11.12.1")) + Expect(result.Subnets[0].LeaseRange).ToNot(BeNil()) + Expect(result.Subnets[0].LeaseRange.StartIP.String()).To(Equal("10.11.12.1")) + Expect(result.Subnets[0].LeaseRange.EndIP.String()).To(Equal("10.11.12.63")) // Once a container executes a new network, the nic will be created. We should clean those up // best we can diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index f1baa7780..634a498b9 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -222,7 +222,7 @@ var _ = Describe("Podman run with volumes", func() { Expect(matches[0]).To(Not(ContainSubstring("nosuid"))) }) - // Container should start when workdir is overlayed volume + // Container should start when workdir is overlay volume It("podman run with volume mounted as overlay and used as workdir", func() { SkipIfRemote("Overlay volumes only work locally") if os.Getenv("container") != "" { @@ -236,7 +236,7 @@ var _ = Describe("Podman run with volumes", func() { mountPath := filepath.Join(podmanTest.TempDir, "secrets") os.Mkdir(mountPath, 0755) - //Container should be able to start with custom overlayed volume + //Container should be able to start with custom overlay volume session := podmanTest.Podman([]string{"run", "--rm", "-v", mountPath + ":/data:O", "--workdir=/data", ALPINE, "echo", "hello"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -262,15 +262,15 @@ var _ = Describe("Podman run with volumes", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - // create file on overlayed volume - session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O", ALPINE, "sh", "-c", "echo hello >> " + "/data/overlayed"}) + // create file on overlay volume + session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O", ALPINE, "sh", "-c", "echo hello >> " + "/data/overlay"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - // volume should contain only `test` not `overlayed` + // volume should contain only `test` not `overlay` session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data", ALPINE, "sh", "-c", "ls /data"}) session.WaitWithDefaultTimeout() - Expect(session.OutputToString()).To(Not(ContainSubstring("overlayed"))) + Expect(session.OutputToString()).To(Not(ContainSubstring("overlay"))) Expect(session.OutputToString()).To(ContainSubstring("test")) }) diff --git a/test/system/001-basic.bats b/test/system/001-basic.bats index 2e5ebe4a3..2de96a01a 100644 --- a/test/system/001-basic.bats +++ b/test/system/001-basic.bats @@ -93,6 +93,15 @@ function setup() { is "$output" "Error: unknown flag: --remote" "podman version --remote" } +@test "podman-remote: defaults" { + if is_remote; then + skip "only applicable on a local run" + fi + + CONTAINER_HOST=foobar run_podman --log-level=info --help + is "$output" ".*defaulting to '--remote=true'" "CONTAINER_HOST sets --remote true" +} + # Check that just calling "podman-remote" prints the usage message even # without a running endpoint. Use "podman --remote" for this as this works the same. @test "podman-remote: check for command usage message without a running endpoint" { diff --git a/troubleshooting.md b/troubleshooting.md index a6c014625..b335eaaa8 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -875,7 +875,7 @@ def signal_listener(): sys.exit(0) except Exception as e: loop.quit() - sys.stderr.write(f"Error occured {e}") + sys.stderr.write(f"Error occurred {e}") sys.exit(1) if __name__ == "__main__": |