diff options
-rw-r--r-- | cmd/podman/common/create_opts.go | 5 | ||||
-rw-r--r-- | docs/source/markdown/podman-save.1.md | 3 | ||||
-rw-r--r-- | docs/tutorials/basic_networking.md | 2 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 19 | ||||
-rw-r--r-- | libpod/pod_internal.go | 7 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 5 | ||||
-rw-r--r-- | libpod/runtime_pod_linux.go | 25 | ||||
-rw-r--r-- | pkg/bindings/images/build.go | 7 | ||||
-rw-r--r-- | pkg/bindings/images/build_test.go | 17 | ||||
-rw-r--r-- | pkg/channel/writer.go | 20 | ||||
-rw-r--r-- | test/compose/ipam_set_ip/docker-compose.yml | 17 | ||||
-rw-r--r-- | test/compose/ipam_set_ip/tests.sh | 4 |
12 files changed, 96 insertions, 35 deletions
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index ca36d751e..77ac781a5 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -302,6 +302,11 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup staticIP := net.ParseIP(ep.IPAddress) netInfo.StaticIP = &staticIP } + // if IPAMConfig.IPv4Address is provided + if ep.IPAMConfig != nil && ep.IPAMConfig.IPv4Address != "" { + staticIP := net.ParseIP(ep.IPAMConfig.IPv4Address) + netInfo.StaticIP = &staticIP + } // If MAC address is provided if len(ep.MacAddress) > 0 { staticMac, err := net.ParseMAC(ep.MacAddress) diff --git a/docs/source/markdown/podman-save.1.md b/docs/source/markdown/podman-save.1.md index 0036a9379..cae0c4b05 100644 --- a/docs/source/markdown/podman-save.1.md +++ b/docs/source/markdown/podman-save.1.md @@ -45,6 +45,7 @@ Save image to **oci-archive, oci-dir** (directory with oci manifest type), or ** #### **\-\-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**. +The default for this option can be modified via the `multi_image_archive="true"|"false"` flag in containers.conf. #### **\-\-quiet**, **-q** @@ -99,7 +100,7 @@ Storing signatures ``` ## SEE ALSO -podman(1), podman-load(1) +podman(1), podman-load(1), containers.conf(5) ## HISTORY July 2017, Originally compiled by Urvashi Mohnani <umohnani@redhat.com> diff --git a/docs/tutorials/basic_networking.md b/docs/tutorials/basic_networking.md index 7544c1cfd..51dfa7564 100644 --- a/docs/tutorials/basic_networking.md +++ b/docs/tutorials/basic_networking.md @@ -151,7 +151,7 @@ host. This interface can configure multiple subinterfaces. And each subinterfac is capable of having its own MAC and IP address. In the case of Podman containers, the container will present itself as if it is on the same network as the host. -![macvlan_network](podman_bridge.png) +![macvlan_network](podman_macvlan.png) In the illustration, outside clients will be able to access the web container by its IP address directly. Usually the network information, including IP address, diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index f87e845cb..f0608e2b2 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -2216,6 +2216,17 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) { return passwdPath, groupPath, nil } +func isRootlessCgroupSet(cgroup string) bool { + // old versions of podman were setting the CgroupParent to CgroupfsDefaultCgroupParent + // by default. Avoid breaking these versions and check whether the cgroup parent is + // set to the default and in this case enable the old behavior. It should not be a real + // problem because the default CgroupParent is usually owned by root so rootless users + // cannot access it. + // This check might be lifted in a future version of Podman. + // Check both that the cgroup or its parent is set to the default value (used by pods). + return cgroup != CgroupfsDefaultCgroupParent && filepath.Dir(cgroup) != CgroupfsDefaultCgroupParent +} + // Get cgroup path in a format suitable for the OCI spec func (c *Container) getOCICgroupPath() (string, error) { unified, err := cgroups.IsCgroup2UnifiedMode() @@ -2227,13 +2238,7 @@ func (c *Container) getOCICgroupPath() (string, error) { case c.config.NoCgroups: return "", nil case (rootless.IsRootless() && (cgroupManager == config.CgroupfsCgroupsManager || !unified)): - if c.config.CgroupParent == CgroupfsDefaultCgroupParent { - // old versions of podman were setting the CgroupParent to CgroupfsDefaultCgroupParent - // by default. Avoid breaking these versions and check whether the cgroup parent is - // set to the default and in this case enable the old behavior. It should not be a real - // problem because the default CgroupParent is usually owned by root so rootless users - // cannot access it. - // This check might be lifted in a future version of Podman. + if !isRootlessCgroupSet(c.config.CgroupParent) { return "", nil } return c.config.CgroupParent, nil diff --git a/libpod/pod_internal.go b/libpod/pod_internal.go index 31b4ba443..e81bd7b16 100644 --- a/libpod/pod_internal.go +++ b/libpod/pod_internal.go @@ -7,6 +7,7 @@ import ( "github.com/containers/common/pkg/config" "github.com/containers/podman/v3/libpod/define" + "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/storage/pkg/stringid" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -74,9 +75,11 @@ func (p *Pod) refresh() error { } p.state.CgroupPath = cgroupPath case config.CgroupfsCgroupsManager: - p.state.CgroupPath = filepath.Join(p.config.CgroupParent, p.ID()) + if rootless.IsRootless() && isRootlessCgroupSet(p.config.CgroupParent) { + p.state.CgroupPath = filepath.Join(p.config.CgroupParent, p.ID()) - logrus.Debugf("setting pod cgroup to %s", p.state.CgroupPath) + logrus.Debugf("setting pod cgroup to %s", p.state.CgroupPath) + } default: return errors.Wrapf(define.ErrInvalidArg, "unknown cgroups manager %s specified", p.runtime.config.Engine.CgroupManager) } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 328f47c12..7d31e392f 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -295,7 +295,10 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai if podCgroup == "" { return nil, errors.Wrapf(define.ErrInternal, "pod %s cgroup is not set", pod.ID()) } - ctr.config.CgroupParent = podCgroup + canUseCgroup := !rootless.IsRootless() || isRootlessCgroupSet(podCgroup) + if canUseCgroup { + ctr.config.CgroupParent = podCgroup + } } else if !rootless.IsRootless() { ctr.config.CgroupParent = CgroupfsDefaultCgroupParent } diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index cf48a9453..4ede23cac 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -75,17 +75,20 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po // Check CGroup parent sanity, and set it if it was not set switch r.config.Engine.CgroupManager { case config.CgroupfsCgroupsManager: - if pod.config.CgroupParent == "" { - pod.config.CgroupParent = CgroupfsDefaultCgroupParent - } else if strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") { - return nil, errors.Wrapf(define.ErrInvalidArg, "systemd slice received as cgroup parent when using cgroupfs") - } - // If we are set to use pod cgroups, set the cgroup parent that - // all containers in the pod will share - // No need to create it with cgroupfs - the first container to - // launch should do it for us - if pod.config.UsePodCgroup { - pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID()) + canUseCgroup := !rootless.IsRootless() || isRootlessCgroupSet(pod.config.CgroupParent) + if canUseCgroup { + if pod.config.CgroupParent == "" { + pod.config.CgroupParent = CgroupfsDefaultCgroupParent + } else if strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") { + return nil, errors.Wrapf(define.ErrInvalidArg, "systemd slice received as cgroup parent when using cgroupfs") + } + // If we are set to use pod cgroups, set the cgroup parent that + // all containers in the pod will share + // No need to create it with cgroupfs - the first container to + // launch should do it for us + if pod.config.UsePodCgroup { + pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID()) + } } case config.SystemdCgroupsManager: if pod.config.CgroupParent == "" { diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index c0e5706a5..6acfcc1c8 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -28,6 +28,10 @@ import ( "github.com/sirupsen/logrus" ) +var ( + iidRegex = regexp.MustCompile(`^[0-9a-f]{12}`) +) + // Build creates an image using a containerfile reference func Build(ctx context.Context, containerFiles []string, options entities.BuildOptions) (*entities.BuildReport, error) { params := url.Values{} @@ -337,7 +341,6 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } dec := json.NewDecoder(body) - re := regexp.MustCompile(`[0-9a-f]{12}`) var id string var mErr error @@ -366,7 +369,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO switch { case s.Stream != "": stdout.Write([]byte(s.Stream)) - if re.Match([]byte(s.Stream)) { + if iidRegex.Match([]byte(s.Stream)) { id = strings.TrimSuffix(s.Stream, "\n") } case s.Error != "": diff --git a/pkg/bindings/images/build_test.go b/pkg/bindings/images/build_test.go new file mode 100644 index 000000000..e4035d5f8 --- /dev/null +++ b/pkg/bindings/images/build_test.go @@ -0,0 +1,17 @@ +package images + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuildMatchIID(t *testing.T) { + assert.True(t, iidRegex.MatchString("a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4")) + assert.True(t, iidRegex.MatchString("3da3a8f95d42")) + assert.False(t, iidRegex.MatchString("3da3")) +} + +func TestBuildNotMatchStatusMessage(t *testing.T) { + assert.False(t, iidRegex.MatchString("Copying config a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4")) +} diff --git a/pkg/channel/writer.go b/pkg/channel/writer.go index 28c9d7de5..ecb68e906 100644 --- a/pkg/channel/writer.go +++ b/pkg/channel/writer.go @@ -1,7 +1,6 @@ package channel import ( - "fmt" "io" "sync" @@ -34,20 +33,17 @@ func (w *writeCloser) Chan() <-chan []byte { // Write method for WriteCloser func (w *writeCloser) Write(b []byte) (bLen int, err error) { - // https://github.com/containers/podman/issues/7896 - // when podman-remote pull image, if it was killed, the server will panic: send on closed channel - // so handle it - defer func() { - if rErr := recover(); rErr != nil { - err = fmt.Errorf("%s", rErr) - } - }() - if w == nil || w.ch == nil { + if w == nil { return 0, errors.New("use channel.NewWriter() to initialize a WriteCloser") } w.mux.Lock() defer w.mux.Unlock() + + if w.ch == nil { + return 0, errors.New("the channel is closed for Write") + } + buf := make([]byte, len(b)) copy(buf, b) w.ch <- buf @@ -57,6 +53,10 @@ func (w *writeCloser) Write(b []byte) (bLen int, err error) { // Close method for WriteCloser func (w *writeCloser) Close() error { + w.mux.Lock() + defer w.mux.Unlock() + close(w.ch) + w.ch = nil return nil } diff --git a/test/compose/ipam_set_ip/docker-compose.yml b/test/compose/ipam_set_ip/docker-compose.yml new file mode 100644 index 000000000..d220c02c0 --- /dev/null +++ b/test/compose/ipam_set_ip/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3.2" +services: + test: + image: alpine + networks: + net1: + ipv4_address: 10.123.0.253 + tty: true + command: ["top"] + +networks: + net1: + driver: bridge + ipam: + driver: default + config: + - subnet: 10.123.0.0/24 diff --git a/test/compose/ipam_set_ip/tests.sh b/test/compose/ipam_set_ip/tests.sh new file mode 100644 index 000000000..ecaf3167e --- /dev/null +++ b/test/compose/ipam_set_ip/tests.sh @@ -0,0 +1,4 @@ +# -*- bash -*- + +podman container inspect ipam_set_ip_test_1 --format '{{ .NetworkSettings.Networks.ipam_set_ip_net1.IPAddress }}' +like "$output" "10.123.0.253" "$testname : ip address is set" |