diff options
author | Peter Hunt <pehunt@redhat.com> | 2019-03-03 22:54:41 -0500 |
---|---|---|
committer | Peter Hunt <pehunt@redhat.com> | 2019-03-05 13:15:25 -0500 |
commit | 6c8f2072aaa3e0b46b2f8d94331fcc88ec6bff11 (patch) | |
tree | 1189b9992d002a641ae8cb00f72d39e3bfceb171 | |
parent | 3614764b70b8541444e8e9966075ccef082535b0 (diff) | |
download | podman-6c8f2072aaa3e0b46b2f8d94331fcc88ec6bff11.tar.gz podman-6c8f2072aaa3e0b46b2f8d94331fcc88ec6bff11.tar.bz2 podman-6c8f2072aaa3e0b46b2f8d94331fcc88ec6bff11.zip |
Append hosts to dependency container's /etc/hosts file
Before, any container with a netNS dependency simply used its dependency container's hosts file, and didn't abide its configuration (mainly --add-host). Fix this by always appending to the dependency container's hosts file, creating one if necessary.
Signed-off-by: Peter Hunt <pehunt@redhat.com>
-rw-r--r-- | libpod/container_internal.go | 17 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 48 | ||||
-rw-r--r-- | test/e2e/pod_infra_container_test.go | 17 |
3 files changed, 74 insertions, 8 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go index e3753d825..08945c410 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -1231,6 +1231,23 @@ func (c *Container) writeStringToRundir(destFile, output string) (string, error) return filepath.Join(c.state.DestinationRunDir, destFile), nil } +// appendStringToRundir appends the provided string to the runtimedir file +func (c *Container) appendStringToRundir(destFile, output string) (string, error) { + destFileName := filepath.Join(c.state.RunDir, destFile) + + f, err := os.OpenFile(destFileName, os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + return "", errors.Wrapf(err, "unable to open %s", destFileName) + } + defer f.Close() + + if _, err := f.WriteString(output); err != nil { + return "", errors.Wrapf(err, "unable to write %s", destFileName) + } + + return filepath.Join(c.state.DestinationRunDir, destFile), nil +} + // Save OCI spec to disk, replacing any existing specs for the container func (c *Container) saveSpec(spec *spec.Spec) error { // If the OCI spec already exists, we need to replace it diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 0e9a5124e..5f9e5a20c 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -698,13 +698,29 @@ func (c *Container) makeBindMounts() error { // If it doesn't, don't copy them resolvPath, exists := bindMounts["/etc/resolv.conf"] if exists { - c.state.BindMounts["/etc/resolv.conf"] = resolvPath } + + // check if dependency container has an /etc/hosts file hostsPath, exists := bindMounts["/etc/hosts"] - if exists { - c.state.BindMounts["/etc/hosts"] = hostsPath + if !exists { + return errors.Errorf("error finding hosts file of dependency container %s for container %s", depCtr.ID(), c.ID()) + } + + depCtr.lock.Lock() + // generate a hosts file for the dependency container, + // based on either its old hosts file, or the default, + // and add the relevant information from the new container (hosts and IP) + hostsPath, err = depCtr.appendHosts(hostsPath, c) + + if err != nil { + depCtr.lock.Unlock() + return errors.Wrapf(err, "error creating hosts file for container %s which depends on container %s", c.ID(), depCtr.ID()) } + depCtr.lock.Unlock() + + // finally, save it in the new container + c.state.BindMounts["/etc/hosts"] = hostsPath } else { newResolv, err := c.generateResolvConf() if err != nil { @@ -712,7 +728,7 @@ func (c *Container) makeBindMounts() error { } c.state.BindMounts["/etc/resolv.conf"] = newResolv - newHosts, err := c.generateHosts() + newHosts, err := c.generateHosts("/etc/hosts") if err != nil { return errors.Wrapf(err, "error creating hosts file for container %s", c.ID()) } @@ -854,12 +870,28 @@ func (c *Container) generateResolvConf() (string, error) { } // generateHosts creates a containers hosts file -func (c *Container) generateHosts() (string, error) { - orig, err := ioutil.ReadFile("/etc/hosts") +func (c *Container) generateHosts(path string) (string, error) { + orig, err := ioutil.ReadFile(path) if err != nil { - return "", errors.Wrapf(err, "unable to read /etc/hosts") + return "", errors.Wrapf(err, "unable to read %s", path) } hosts := string(orig) + hosts += c.getHosts() + return c.writeStringToRundir("hosts", hosts) +} + +// appendHosts appends a container's config and state pertaining to hosts to a container's +// local hosts file. netCtr is the container from which the netNS information is +// taken. +// path is the basis of the hosts file, into which netCtr's netNS information will be appended. +func (c *Container) appendHosts(path string, netCtr *Container) (string, error) { + return c.appendStringToRundir("hosts", netCtr.getHosts()) +} + +// getHosts finds the pertinent information for a container's host file in its config and state +// and returns a string in a format that can be written to the host file +func (c *Container) getHosts() string { + var hosts string if len(c.config.HostAdd) > 0 { for _, host := range c.config.HostAdd { // the host format has already been verified at this point @@ -871,7 +903,7 @@ func (c *Container) generateHosts() (string, error) { ipAddress := strings.Split(c.state.NetworkStatus[0].IPs[0].Address.String(), "/")[0] hosts += fmt.Sprintf("%s\t%s\n", ipAddress, c.Hostname()) } - return c.writeStringToRundir("hosts", hosts) + return hosts } // generatePasswd generates a container specific passwd file, diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go index ed5002ca7..d9e5d380a 100644 --- a/test/e2e/pod_infra_container_test.go +++ b/test/e2e/pod_infra_container_test.go @@ -360,4 +360,21 @@ var _ = Describe("Podman pod create", func() { Expect(result.OutputToString()).To(ContainSubstring(infraID)) }) + + It("podman run --add-host in pod", func() { + session := podmanTest.Podman([]string{"pod", "create"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podID := session.OutputToString() + + // verify we can add a host to the infra's /etc/hosts + session = podmanTest.Podman([]string{"run", "--pod", podID, "--add-host", "foobar:127.0.0.1", BB, "ping", "-c", "1", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + // verify we can see the other hosts of infra's /etc/hosts + session = podmanTest.Podman([]string{"run", "--pod", podID, BB, "ping", "-c", "1", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) }) |