summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/specgen.go20
-rw-r--r--completions/bash/podman24
-rw-r--r--docs/source/markdown/podman-untag.1.md8
-rw-r--r--libpod/define/errors.go3
-rw-r--r--libpod/image/errors.go2
-rw-r--r--libpod/image/image.go13
-rw-r--r--libpod/runtime_ctr.go4
-rw-r--r--pkg/api/handlers/compat/exec.go3
-rw-r--r--pkg/specgen/generate/container_create.go3
-rw-r--r--pkg/specgen/specgen.go2
-rw-r--r--pkg/util/utils.go6
-rw-r--r--test/e2e/create_test.go13
-rw-r--r--test/e2e/untag_test.go76
-rw-r--r--test/system/020-tag.bats35
14 files changed, 147 insertions, 65 deletions
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index 599e003e8..1f6fbbe98 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -520,7 +520,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
case "label":
// TODO selinux opts and label opts are the same thing
s.ContainerSecurityConfig.SelinuxOpts = append(s.ContainerSecurityConfig.SelinuxOpts, con[1])
- s.Annotations[define.InspectAnnotationLabel] = con[1]
+ s.Annotations[define.InspectAnnotationLabel] = strings.Join(s.ContainerSecurityConfig.SelinuxOpts, ",label=")
case "apparmor":
s.ContainerSecurityConfig.ApparmorProfile = con[1]
s.Annotations[define.InspectAnnotationApparmor] = con[1]
@@ -535,7 +535,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.SeccompPolicy = c.SeccompPolicy
- // TODO: should parse out options
s.VolumesFrom = c.VolumesFrom
// Only add read-only tmpfs mounts in case that we are read-only and the
@@ -547,22 +546,10 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.Mounts = mounts
s.Volumes = volumes
- // TODO any idea why this was done
- // devices := rtc.Containers.Devices
- // TODO conflict on populate?
- //
- // if c.Changed("device") {
- // devices = append(devices, c.StringSlice("device")...)
- // }
-
for _, dev := range c.Devices {
s.Devices = append(s.Devices, specs.LinuxDevice{Path: dev})
}
- // TODO things i cannot find in spec
- // we dont think these are in the spec
- // init - initbinary
- // initpath
s.Init = c.Init
s.InitPath = c.InitPath
s.Stdin = c.Interactive
@@ -587,11 +574,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.Rlimits = append(s.Rlimits, rl)
}
- // Tmpfs: c.StringArray("tmpfs"),
-
- // TODO how to handle this?
- // Syslog: c.Bool("syslog"),
-
logOpts := make(map[string]string)
for _, o := range c.LogOptions {
split := strings.SplitN(o, "=", 2)
diff --git a/completions/bash/podman b/completions/bash/podman
index cb4e86156..c0d9560ed 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1572,6 +1572,11 @@ _podman_image_tag() {
_podman_tag
}
+
+_podman_image_untag() {
+ _podman_untag
+}
+
_podman_image() {
local boolean_options="
--help
@@ -1593,6 +1598,7 @@ _podman_image() {
sign
tag
trust
+ untag
"
local aliases="
list
@@ -2460,6 +2466,23 @@ _podman_tag() {
esac
}
+_podman_untag() {
+ local options_with_args="
+ "
+ local boolean_options="
+ --help
+ -h
+ "
+ case "$cur" in
+ -*)
+ COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
+ ;;
+ *)
+ __podman_complete_images
+ ;;
+ esac
+}
+
__podman_top_descriptors() {
podman top --list-descriptors
}
@@ -3588,6 +3611,7 @@ _podman_podman() {
umount
unmount
unpause
+ untag
varlink
version
volume
diff --git a/docs/source/markdown/podman-untag.1.md b/docs/source/markdown/podman-untag.1.md
index 3a54283d6..c83a0544c 100644
--- a/docs/source/markdown/podman-untag.1.md
+++ b/docs/source/markdown/podman-untag.1.md
@@ -4,14 +4,12 @@
podman\-untag - Removes one or more names from a locally-stored image
## SYNOPSIS
-**podman untag** *image*[:*tag*] [*target-names*[:*tag*]] [*options*]
+**podman untag** [*options*] *image* [*name*[:*tag*]...]
-**podman image untag** *image*[:*tag*] [target-names[:*tag*]] [*options*]
+**podman image untag** [*options*] *image* [*name*[:*tag*]...]
## DESCRIPTION
-Removes one or all names of an image. A name refers to the entire image name,
-including the optional *tag* after the `:`. If no target image names are
-specified, `untag` will remove all tags for the image at once.
+Remove one or more names from an image in the local storage. The image can be referred to by ID or reference. If a no name is specified, all names are removed the image. If a specified name is a short name and does not include a registry `localhost/` will be prefixed (e.g., `fedora` -> `localhost/fedora`). If a specified name does not include a tag `:latest` will be appended (e.g., `localhost/fedora` -> `localhost/fedora:latest`).
## OPTIONS
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index e0c9811fe..98dc603d1 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -17,6 +17,9 @@ var (
// ErrNoSuchImage indicates the requested image does not exist
ErrNoSuchImage = image.ErrNoSuchImage
+ // ErrNoSuchTag indicates the requested image tag does not exist
+ ErrNoSuchTag = image.ErrNoSuchTag
+
// ErrNoSuchVolume indicates the requested volume does not exist
ErrNoSuchVolume = errors.New("no such volume")
diff --git a/libpod/image/errors.go b/libpod/image/errors.go
index 4088946cb..ddbf7be4b 100644
--- a/libpod/image/errors.go
+++ b/libpod/image/errors.go
@@ -12,4 +12,6 @@ var (
ErrNoSuchPod = errors.New("no such pod")
// ErrNoSuchImage indicates the requested image does not exist
ErrNoSuchImage = errors.New("no such image")
+ // ErrNoSuchTag indicates the requested image tag does not exist
+ ErrNoSuchTag = errors.New("no such tag")
)
diff --git a/libpod/image/image.go b/libpod/image/image.go
index d81f7e911..83e7467e9 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -559,15 +559,24 @@ func (i *Image) TagImage(tag string) error {
return nil
}
-// UntagImage removes a tag from the given image
+// UntagImage removes the specified tag from the image.
+// If the tag does not exist, ErrNoSuchTag is returned.
func (i *Image) UntagImage(tag string) error {
if err := i.reloadImage(); err != nil {
return err
}
+
+ // Normalize the tag as we do with TagImage.
+ ref, err := NormalizedTag(tag)
+ if err != nil {
+ return err
+ }
+ tag = ref.String()
+
var newTags []string
tags := i.Names()
if !util.StringInSlice(tag, tags) {
- return nil
+ return errors.Wrapf(ErrNoSuchTag, "%q", tag)
}
for _, t := range tags {
if tag != t {
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 0431861b5..f1752cbeb 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -83,6 +83,8 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf
return nil, errors.Wrapf(err, "converting containers.conf ShmSize %s to an int", r.config.Containers.ShmSize)
}
ctr.config.ShmSize = size
+ ctr.config.StopSignal = 15
+ ctr.config.StopTimeout = r.config.Engine.StopTimeout
} else {
// This is a restore from an imported checkpoint
ctr.restoreFromCheckpoint = true
@@ -107,8 +109,6 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf
ctr.state.BindMounts = make(map[string]string)
- ctr.config.StopTimeout = r.config.Engine.StopTimeout
-
ctr.config.OCIRuntime = r.defaultOCIRuntime.Name()
// Set namespace based on current runtime namespace
diff --git a/pkg/api/handlers/compat/exec.go b/pkg/api/handlers/compat/exec.go
index 8f7016903..dae76c061 100644
--- a/pkg/api/handlers/compat/exec.go
+++ b/pkg/api/handlers/compat/exec.go
@@ -62,7 +62,8 @@ func ExecCreateHandler(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- exitCommandArgs, err := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, false, true, true)
+ // Automatically log to syslog if the server has log-level=debug set
+ exitCommandArgs, err := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), true, true)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index ea6f938a8..7b4fbebf4 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -114,8 +114,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
}
options = append(options, opts...)
- // TODO: Enable syslog support - we'll need to put this in SpecGen.
- exitCommandArgs, err := CreateExitCommandArgs(rt.StorageConfig(), rtc, false, s.Remove, false)
+ exitCommandArgs, err := CreateExitCommandArgs(rt.StorageConfig(), rtc, logrus.IsLevelEnabled(logrus.DebugLevel), s.Remove, false)
if err != nil {
return nil, err
}
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 46ff8c716..3d5bf03e5 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -129,7 +129,7 @@ type ContainerBasicConfig struct {
Sysctl map[string]string `json:"sysctl,omitempty"`
// Remove indicates if the container should be removed once it has been started
// and exits
- Remove bool `json:"remove"`
+ Remove bool `json:"remove,omitempty"`
// PreserveFDs is a number of additional file descriptors (in addition
// to 0, 1, 2) that will be passed to the executed process. The total FDs
// passed will be 3 + PreserveFDs.
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 917f57742..1d8941b4d 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -419,12 +419,6 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin
if len(uidMapSlice) == 0 && len(gidMapSlice) != 0 {
uidMapSlice = gidMapSlice
}
- if len(uidMapSlice) == 0 && subUIDMap == "" && os.Getuid() != 0 {
- uidMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getuid())}
- }
- if len(gidMapSlice) == 0 && subGIDMap == "" && os.Getuid() != 0 {
- gidMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getgid())}
- }
if subUIDMap != "" && subGIDMap != "" {
mappings, err := idtools.NewIDMappings(subUIDMap, subGIDMap)
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 52ce0b46a..44bb5c45f 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -458,4 +458,17 @@ var _ = Describe("Podman create", func() {
Expect(session.ExitCode()).To(Equal(0))
}
})
+
+ It("podman create sets default stop signal 15", func() {
+ ctrName := "testCtr"
+ session := podmanTest.Podman([]string{"create", "--name", ctrName, ALPINE, "/bin/sh"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", ctrName})
+ inspect.WaitWithDefaultTimeout()
+ data := inspect.InspectContainerToJSON()
+ Expect(len(data)).To(Equal(1))
+ Expect(data[0].Config.StopSignal).To(Equal(uint(15)))
+ })
})
diff --git a/test/e2e/untag_test.go b/test/e2e/untag_test.go
index dc1a6208e..8a1c8091d 100644
--- a/test/e2e/untag_test.go
+++ b/test/e2e/untag_test.go
@@ -23,13 +23,6 @@ var _ = Describe("Podman untag", func() {
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
podmanTest.RestoreAllArtifacts()
-
- for _, tag := range []string{"test", "foo", "bar"} {
- session := podmanTest.PodmanNoCache([]string{"tag", ALPINE, tag})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- }
-
})
AfterEach(func() {
@@ -40,34 +33,63 @@ var _ = Describe("Podman untag", func() {
})
It("podman untag all", func() {
- session := podmanTest.PodmanNoCache([]string{"untag", ALPINE})
+ tags := []string{ALPINE, "registry.com/foo:bar", "localhost/foo:bar"}
+
+ cmd := []string{"tag"}
+ cmd = append(cmd, tags...)
+ session := podmanTest.PodmanNoCache(cmd)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- results := podmanTest.PodmanNoCache([]string{"images", ALPINE})
- results.WaitWithDefaultTimeout()
- Expect(results.ExitCode()).To(Equal(0))
- Expect(results.OutputToStringArray()).To(HaveLen(1))
- })
+ // Make sure that all tags exists.
+ for _, t := range tags {
+ session = podmanTest.PodmanNoCache([]string{"image", "exists", t})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ }
- It("podman untag single", func() {
- session := podmanTest.PodmanNoCache([]string{"untag", ALPINE, "localhost/test:latest"})
+ // No arguments -> remove all tags.
+ session = podmanTest.PodmanNoCache([]string{"untag", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- results := podmanTest.PodmanNoCache([]string{"images"})
- results.WaitWithDefaultTimeout()
- Expect(results.ExitCode()).To(Equal(0))
- Expect(results.OutputToStringArray()).To(HaveLen(6))
- Expect(results.LineInOuputStartsWith("docker.io/library/alpine")).To(BeTrue())
- Expect(results.LineInOuputStartsWith("localhost/foo")).To(BeTrue())
- Expect(results.LineInOuputStartsWith("localhost/bar")).To(BeTrue())
- Expect(results.LineInOuputStartsWith("localhost/test")).To(BeFalse())
+ // Make sure that none of tags exists anymore.
+ for _, t := range tags {
+ session = podmanTest.PodmanNoCache([]string{"image", "exists", t})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(1))
+ }
})
- It("podman untag not enough arguments", func() {
- session := podmanTest.PodmanNoCache([]string{"untag"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).NotTo(Equal(0))
+ It("podman tag/untag - tag normalization", func() {
+ tests := []struct {
+ tag, normalized string
+ }{
+ {"registry.com/image:latest", "registry.com/image:latest"},
+ {"registry.com/image", "registry.com/image:latest"},
+ {"image:latest", "localhost/image:latest"},
+ {"image", "localhost/image:latest"},
+ }
+
+ // Make sure that the user input is normalized correctly for
+ // `podman tag` and `podman untag`.
+ for _, tt := range tests {
+ session := podmanTest.PodmanNoCache([]string{"tag", ALPINE, tt.tag})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.PodmanNoCache([]string{"image", "exists", tt.normalized})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.PodmanNoCache([]string{"untag", ALPINE, tt.tag})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.PodmanNoCache([]string{"image", "exists", tt.normalized})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(1))
+ }
})
+
})
diff --git a/test/system/020-tag.bats b/test/system/020-tag.bats
new file mode 100644
index 000000000..7593ad68f
--- /dev/null
+++ b/test/system/020-tag.bats
@@ -0,0 +1,35 @@
+#!/usr/bin/env bats
+
+load helpers
+
+# helper function for "podman tag/untag" test
+function _tag_and_check() {
+ local tag_as="$1"
+ local check_as="$2"
+
+ run_podman tag $IMAGE $tag_as
+ run_podman image exists $check_as
+ run_podman untag $IMAGE $check_as
+ run_podman 1 image exists $check_as
+}
+
+@test "podman tag/untag" {
+ # Test a fully-qualified image reference.
+ _tag_and_check registry.com/image:latest registry.com/image:latest
+
+ # Test a reference without tag and make sure ":latest" is appended.
+ _tag_and_check registry.com/image registry.com/image:latest
+
+ # Test a tagged short image and make sure "localhost/" is prepended.
+ _tag_and_check image:latest localhost/image:latest
+
+ # Test a short image without tag and make sure "localhost/" is
+ # prepended and ":latest" is appended.
+ _tag_and_check image localhost/image:latest
+
+ # Test error case.
+ run_podman 125 untag $IMAGE registry.com/foo:bar
+ is "$output" "Error: \"registry.com/foo:bar\": no such tag"
+}
+
+# vim: filetype=sh