summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/cirrus/logformatter6
-rw-r--r--libpod/container_internal_linux.go48
-rw-r--r--pkg/api/handlers/types.go11
-rw-r--r--pkg/bindings/test/containers_test.go1
-rw-r--r--pkg/specgen/generate/ports.go15
-rw-r--r--test/e2e/run_networking_test.go16
-rw-r--r--test/e2e/run_passwd_test.go8
-rw-r--r--test/e2e/run_userns_test.go25
8 files changed, 101 insertions, 29 deletions
diff --git a/contrib/cirrus/logformatter b/contrib/cirrus/logformatter
index b56a829c5..f97638b6f 100755
--- a/contrib/cirrus/logformatter
+++ b/contrib/cirrus/logformatter
@@ -208,13 +208,13 @@ END_HTML
}
# Try to identify the git commit we're working with...
- if ($line =~ m!libpod/define.gitCommit=([0-9a-f]+)!) {
+ if ($line =~ m!/define.gitCommit=([0-9a-f]+)!) {
$git_commit = $1;
}
# ...so we can link to specific lines in source files
if ($git_commit) {
- # 1 12 3 34 4 5 526 6
- $line =~ s{^(.*)(\/(containers\/libpod)(\/\S+):(\d+))(.*)$}
+ # 1 12 3 34 4 5 526 6
+ $line =~ s{^(.*)(\/(containers\/[^/]+)(\/\S+):(\d+))(.*)$}
{$1<a class="codelink" href='https://github.com/$3/blob/$git_commit$4#L$5'>$2</a>$6};
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 795611596..4cfe992ea 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -1480,11 +1480,26 @@ func (c *Container) generateCurrentUserPasswdEntry() (string, error) {
if uid == 0 {
return "", nil
}
+
u, err := user.LookupId(strconv.Itoa(rootless.GetRootlessUID()))
if err != nil {
return "", errors.Wrapf(err, "failed to get current user")
}
- return fmt.Sprintf("%s:x:%s:%s:%s:%s:/bin/sh\n", u.Username, u.Uid, u.Gid, u.Username, c.WorkingDir()), nil
+
+ // Lookup the user to see if it exists in the container image.
+ _, err = lookup.GetUser(c.state.Mountpoint, u.Username)
+ if err != User.ErrNoPasswdEntries {
+ return "", err
+ }
+
+ // If the user's actual home directory exists, or was mounted in - use
+ // that.
+ homeDir := c.WorkingDir()
+ if MountExists(c.config.Spec.Mounts, u.HomeDir) {
+ homeDir = u.HomeDir
+ }
+
+ return fmt.Sprintf("%s:x:%s:%s:%s:%s:/bin/sh\n", u.Username, u.Uid, u.Gid, u.Username, homeDir), nil
}
// generateUserPasswdEntry generates an /etc/passwd entry for the container user
@@ -1510,12 +1525,9 @@ func (c *Container) generateUserPasswdEntry() (string, error) {
// Lookup the user to see if it exists in the container image
_, err = lookup.GetUser(c.state.Mountpoint, userspec)
- if err != nil && err != User.ErrNoPasswdEntries {
+ if err != User.ErrNoPasswdEntries {
return "", err
}
- if err == nil {
- return "", nil
- }
if groupspec != "" {
ugid, err := strconv.ParseUint(groupspec, 10, 32)
@@ -1564,6 +1576,32 @@ func (c *Container) generatePasswd() (string, error) {
if pwd == "" {
return "", nil
}
+
+ // If we are *not* read-only - edit /etc/passwd in the container.
+ // This is *gross* (shows up in changes to the container, will be
+ // committed to images based on the container) but it actually allows us
+ // to add users to the container (a bind mount breaks useradd).
+ // We should never get here twice, because generateUserPasswdEntry will
+ // not return anything if the user already exists in /etc/passwd.
+ if !c.IsReadOnly() {
+ containerPasswd, err := securejoin.SecureJoin(c.state.Mountpoint, "/etc/passwd")
+ if err != nil {
+ return "", errors.Wrapf(err, "error looking up location of container %s /etc/passwd", c.ID())
+ }
+
+ f, err := os.OpenFile(containerPasswd, os.O_APPEND|os.O_WRONLY, 0600)
+ if err != nil {
+ return "", errors.Wrapf(err, "error opening container %s /etc/passwd", c.ID())
+ }
+ defer f.Close()
+
+ if _, err := f.WriteString(pwd); err != nil {
+ return "", errors.Wrapf(err, "unable to append to container %s /etc/passwd", c.ID())
+ }
+
+ return "", nil
+ }
+
originPasswdFile := filepath.Join(c.state.Mountpoint, "/etc/passwd")
orig, err := ioutil.ReadFile(originPasswdFile)
if err != nil && !os.IsNotExist(err) {
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index a17f5df56..0ccaa95bb 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -203,15 +203,6 @@ func ImageToImageSummary(l *libpodImage.Image) (*entities.ImageSummary, error) {
return nil, errors.Wrapf(err, "Failed to obtain RepoTags for image %s", l.ID())
}
- history, err := l.History(context.TODO())
- if err != nil {
- return nil, errors.Wrapf(err, "Failed to obtain History for image %s", l.ID())
- }
- historyIds := make([]string, len(history))
- for i, h := range history {
- historyIds[i] = h.ID
- }
-
digests := make([]string, len(l.Digests()))
for i, d := range l.Digests() {
digests[i] = string(d)
@@ -233,7 +224,7 @@ func ImageToImageSummary(l *libpodImage.Image) (*entities.ImageSummary, error) {
Digest: string(l.Digest()),
Digests: digests,
ConfigDigest: string(l.ConfigDigest),
- History: historyIds,
+ History: l.NamesHistory(),
}
return &is, nil
}
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index c1a01c280..9a188e5da 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -280,6 +280,7 @@ var _ = Describe("Podman containers ", func() {
})
It("podman wait to pause|unpause condition", func() {
+ Skip("FIXME: https://github.com/containers/podman/issues/6518")
var (
name = "top"
exitCode int32 = -1
diff --git a/pkg/specgen/generate/ports.go b/pkg/specgen/generate/ports.go
index 1ad7e6f4d..7dd50ac0d 100644
--- a/pkg/specgen/generate/ports.go
+++ b/pkg/specgen/generate/ports.go
@@ -123,19 +123,20 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
postAssignHostPort = true
}
} else {
- testCPort := ctrPortMap[cPort]
- if testCPort != 0 && testCPort != hPort {
- // This is an attempt to redefine a port
- return nil, nil, nil, errors.Errorf("conflicting port mappings for container port %d (protocol %s)", cPort, p)
- }
- ctrPortMap[cPort] = hPort
-
testHPort := hostPortMap[hPort]
if testHPort != 0 && testHPort != cPort {
return nil, nil, nil, errors.Errorf("conflicting port mappings for host port %d (protocol %s)", hPort, p)
}
hostPortMap[hPort] = cPort
+ // Mapping a container port to multiple
+ // host ports is allowed.
+ // We only store the latest of these in
+ // the container port map - we don't
+ // need to know all of them, just one.
+ testCPort := ctrPortMap[cPort]
+ ctrPortMap[cPort] = hPort
+
// If we have an exact duplicate, just continue
if testCPort == hPort && testHPort == cPort {
continue
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index bf96db197..87b74052a 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -220,6 +220,22 @@ var _ = Describe("Podman run networking", func() {
Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostIP).To(Equal(""))
})
+ It("podman run -p 8080:8080 -p 8081:8080", func() {
+ name := "testctr"
+ session := podmanTest.Podman([]string{"create", "-t", "-p", "4000:8080", "-p", "8000:8080", "--name", name, ALPINE, "/bin/sh"})
+ session.WaitWithDefaultTimeout()
+ inspectOut := podmanTest.InspectContainer(name)
+ Expect(len(inspectOut)).To(Equal(1))
+ Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1))
+ Expect(len(inspectOut[0].NetworkSettings.Ports["8080/tcp"])).To(Equal(2))
+
+ hp1 := inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostPort
+ hp2 := inspectOut[0].NetworkSettings.Ports["8080/tcp"][1].HostPort
+
+ // We can't guarantee order
+ Expect((hp1 == "4000" && hp2 == "8000") || (hp1 == "8000" && hp2 == "4000")).To(BeTrue())
+ })
+
It("podman run network expose host port 80 to container port 8000", func() {
SkipIfRootless()
session := podmanTest.Podman([]string{"run", "-dt", "-p", "80:8000", ALPINE, "/bin/sh"})
diff --git a/test/e2e/run_passwd_test.go b/test/e2e/run_passwd_test.go
index a1414e313..8dea7d39b 100644
--- a/test/e2e/run_passwd_test.go
+++ b/test/e2e/run_passwd_test.go
@@ -33,27 +33,27 @@ var _ = Describe("Podman run passwd", func() {
})
It("podman run no user specified ", func() {
- session := podmanTest.Podman([]string{"run", BB, "mount"})
+ session := podmanTest.Podman([]string{"run", "--read-only", BB, "mount"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.LineInOutputContains("passwd")).To(BeFalse())
})
It("podman run user specified in container", func() {
- session := podmanTest.Podman([]string{"run", "-u", "bin", BB, "mount"})
+ session := podmanTest.Podman([]string{"run", "--read-only", "-u", "bin", BB, "mount"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.LineInOutputContains("passwd")).To(BeFalse())
})
It("podman run UID specified in container", func() {
- session := podmanTest.Podman([]string{"run", "-u", "2:1", BB, "mount"})
+ session := podmanTest.Podman([]string{"run", "--read-only", "-u", "2:1", BB, "mount"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.LineInOutputContains("passwd")).To(BeFalse())
})
It("podman run UID not specified in container", func() {
- session := podmanTest.Podman([]string{"run", "-u", "20001:1", BB, "mount"})
+ session := podmanTest.Podman([]string{"run", "--read-only", "-u", "20001:1", BB, "mount"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.LineInOutputContains("passwd")).To(BeTrue())
diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go
index 198217433..25f8d0d15 100644
--- a/test/e2e/run_userns_test.go
+++ b/test/e2e/run_userns_test.go
@@ -111,6 +111,31 @@ var _ = Describe("Podman UserNS support", func() {
Expect(session.OutputToString()).To(Equal("0"))
})
+ It("podman run --userns=keep-id can add users", func() {
+ if os.Geteuid() == 0 {
+ Skip("Test only runs without root")
+ }
+
+ userName := os.Getenv("USER")
+ if userName == "" {
+ Skip("Can't complete test if no username available")
+ }
+
+ ctrName := "ctr-name"
+ session := podmanTest.Podman([]string{"run", "--userns=keep-id", "--user", "root:root", "-d", "--stop-signal", "9", "--name", ctrName, fedoraMinimal, "sleep", "600"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ exec1 := podmanTest.Podman([]string{"exec", "-t", "-i", ctrName, "cat", "/etc/passwd"})
+ exec1.WaitWithDefaultTimeout()
+ Expect(exec1.ExitCode()).To(Equal(0))
+ Expect(exec1.OutputToString()).To(ContainSubstring(userName))
+
+ exec2 := podmanTest.Podman([]string{"exec", "-t", "-i", ctrName, "useradd", "testuser"})
+ exec2.WaitWithDefaultTimeout()
+ Expect(exec2.ExitCode()).To(Equal(0))
+ })
+
It("podman --userns=auto", func() {
u, err := user.Current()
Expect(err).To(BeNil())