Skip to content

Commit

Permalink
Merge pull request #3917 from Luap99/hosts
Browse files Browse the repository at this point in the history
use etchosts package from c/common
  • Loading branch information
openshift-merge-robot authored Apr 21, 2022
2 parents ee076c0 + 5de32ad commit d93a4eb
Show file tree
Hide file tree
Showing 15 changed files with 591 additions and 83 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.16
require (
github.com/containerd/containerd v1.6.2
github.com/containernetworking/cni v1.0.1
github.com/containers/common v0.47.5-0.20220420095823-d822f53650b2
github.com/containers/common v0.47.5-0.20220421103500-7309411777c5
github.com/containers/image/v5 v5.21.1-0.20220414071450-d2d961d5d324
github.com/containers/ocicrypt v1.1.3
github.com/containers/storage v1.39.1-0.20220419114238-1be409aec551
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,8 @@ github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRD
github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE=
github.com/containernetworking/plugins v1.1.1 h1:+AGfFigZ5TiQH00vhR8qPeSatj53eNGz0C1d3wVYlHE=
github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8=
github.com/containers/common v0.47.5-0.20220420095823-d822f53650b2 h1:J5uPUMXvYxGBCthUVSYChh1lGMH/XgsZLeJAZCs+zgo=
github.com/containers/common v0.47.5-0.20220420095823-d822f53650b2/go.mod h1:BBq6jdyjXvJh69YzQPvIuZjBho0MRdA0XGaqBnsO+1Y=
github.com/containers/common v0.47.5-0.20220421103500-7309411777c5 h1:kV9caDLhPbjW8aYk/uwtyPaGweE4cr1/OR/eZK9dFWY=
github.com/containers/common v0.47.5-0.20220421103500-7309411777c5/go.mod h1:BBq6jdyjXvJh69YzQPvIuZjBho0MRdA0XGaqBnsO+1Y=
github.com/containers/image/v5 v5.19.2-0.20220224100137-1045fb70b094/go.mod h1:XoYK6kE0dpazFNcuS+a8lra+QfbC6s8tzv+cUuCrZpE=
github.com/containers/image/v5 v5.21.1-0.20220414071450-d2d961d5d324 h1:AJOJpnXm0wfyKr113QMTCfjvnZ17IIDxvqMpKofuvZw=
github.com/containers/image/v5 v5.21.1-0.20220414071450-d2d961d5d324/go.mod h1:VM69F9d4EU1B9FXvpHH0nrgj0Vc6NMPI39SojiYjw1o=
Expand Down
100 changes: 51 additions & 49 deletions run_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/containers/buildah/pkg/parse"
"github.com/containers/buildah/pkg/sshagent"
"github.com/containers/buildah/util"
"github.com/containers/common/libnetwork/etchosts"
"github.com/containers/common/libnetwork/network"
nettypes "github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/capabilities"
Expand Down Expand Up @@ -221,15 +222,13 @@ func (b *Builder) Run(command []string, options RunOptions) error {
}
rootIDPair := &idtools.IDPair{UID: int(rootUID), GID: int(rootGID)}

if !options.NoHosts && !contains(volumes, "/etc/hosts") {
hostFile, err := b.generateHosts(path, spec.Hostname, b.CommonBuildOpts.AddHost, rootIDPair)
hostFile := ""
if !options.NoHosts && !contains(volumes, config.DefaultHostsFile) && options.ConfigureNetwork != define.NetworkDisabled {
hostFile, err = b.generateHosts(path, rootIDPair, mountPoint)
if err != nil {
return err
}
// Only bind /etc/hosts if there's a network
if options.ConfigureNetwork != define.NetworkDisabled {
bindFiles["/etc/hosts"] = hostFile
}
bindFiles[config.DefaultHostsFile] = hostFile
}

// generate /etc/hostname if the user intentionally did not override
Expand Down Expand Up @@ -314,15 +313,17 @@ rootless=%d
if options.NoPivot {
moreCreateArgs = append(moreCreateArgs, "--no-pivot")
}
err = b.runUsingRuntimeSubproc(isolation, options, configureNetwork, configureNetworks, moreCreateArgs, spec, mountPoint, path, define.Package+"-"+filepath.Base(path))
err = b.runUsingRuntimeSubproc(isolation, options, configureNetwork, configureNetworks, moreCreateArgs, spec,
mountPoint, path, define.Package+"-"+filepath.Base(path), b.Container, hostFile)
case IsolationChroot:
err = chroot.RunUsingChroot(spec, path, homeDir, options.Stdin, options.Stdout, options.Stderr)
case IsolationOCIRootless:
moreCreateArgs := []string{"--no-new-keyring"}
if options.NoPivot {
moreCreateArgs = append(moreCreateArgs, "--no-pivot")
}
err = b.runUsingRuntimeSubproc(isolation, options, configureNetwork, configureNetworks, moreCreateArgs, spec, mountPoint, path, define.Package+"-"+filepath.Base(path))
err = b.runUsingRuntimeSubproc(isolation, options, configureNetwork, configureNetworks, moreCreateArgs, spec,
mountPoint, path, define.Package+"-"+filepath.Base(path), b.Container, hostFile)
default:
err = errors.Errorf("don't know how to run this command")
}
Expand Down Expand Up @@ -643,58 +644,41 @@ func (b *Builder) addResolvConf(rdir string, chownOpts *idtools.IDPair, dnsServe
}

// generateHosts creates a containers hosts file
func (b *Builder) generateHosts(rdir, hostname string, addHosts []string, chownOpts *idtools.IDPair) (string, error) {
hostPath := "/etc/hosts"
stat, err := os.Stat(hostPath)
func (b *Builder) generateHosts(rdir string, chownOpts *idtools.IDPair, imageRoot string) (string, error) {
conf, err := config.Default()
if err != nil {
return "", err
}

hosts := bytes.NewBufferString("# Generated by Buildah\n")
orig, err := ioutil.ReadFile(hostPath)
path, err := etchosts.GetBaseHostFile(conf.Containers.BaseHostsFile, imageRoot)
if err != nil {
return "", err
}
hosts.Write(orig)
for _, host := range addHosts {
// verify the host format
values := strings.SplitN(host, ":", 2)
if len(values) != 2 {
return "", errors.Errorf("unable to parse host entry %q: incorrect format", host)
}
if values[0] == "" {
return "", errors.Errorf("hostname in host entry %q is empty", host)
}
if values[1] == "" {
return "", errors.Errorf("IP address in host entry %q is empty", host)
}
hosts.Write([]byte(fmt.Sprintf("%s\t%s\n", values[1], values[0])))
}
hosts.Write([]byte(fmt.Sprintf("127.0.0.1 %s %s\n", b.Container, hostname)))
hosts.Write([]byte(fmt.Sprintf("::1 %s %s\n", b.Container, hostname)))

if ip := util.LocalIP(); ip != "" {
hosts.Write([]byte(fmt.Sprintf("%s %s\n", ip, "host.containers.internal")))
targetfile := filepath.Join(rdir, "hosts")
if err := etchosts.New(&etchosts.Params{
BaseFile: path,
ExtraHosts: b.CommonBuildOpts.AddHost,
HostContainersInternalIP: etchosts.GetHostContainersInternalIP(conf, nil, nil),
TargetFile: targetfile,
}); err != nil {
return "", err
}

cfile := filepath.Join(rdir, filepath.Base(hostPath))
if err = ioutils.AtomicWriteFile(cfile, hosts.Bytes(), stat.Mode().Perm()); err != nil {
return "", errors.Wrapf(err, "error writing /etc/hosts into the container")
}
uid := int(stat.Sys().(*syscall.Stat_t).Uid)
gid := int(stat.Sys().(*syscall.Stat_t).Gid)
uid := 0
gid := 0
if chownOpts != nil {
uid = chownOpts.UID
gid = chownOpts.GID
}
if err = os.Chown(cfile, uid, gid); err != nil {
if err = os.Chown(targetfile, uid, gid); err != nil {
return "", err
}
if err := label.Relabel(cfile, b.MountLabel, false); err != nil {
if err := label.Relabel(targetfile, b.MountLabel, false); err != nil {
return "", err
}

return cfile, nil
return targetfile, nil
}

// generateHostname creates a containers /etc/hostname file
Expand Down Expand Up @@ -1146,9 +1130,10 @@ func setupRootlessNetwork(pid int) (teardown func(), err error) {
}, nil
}

func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, options RunOptions, configureNetworks []string, containerName string) (teardown func(), err error) {
func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, options RunOptions, configureNetworks []string, containerName string) (teardown func(), netStatus map[string]nettypes.StatusBlock, err error) {
if isolation == IsolationOCIRootless {
return setupRootlessNetwork(pid)
teardown, err = setupRootlessNetwork(pid)
return teardown, nil, err
}

if len(configureNetworks) == 0 {
Expand All @@ -1163,7 +1148,7 @@ func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, optio
netns := fmt.Sprintf("/proc/%d/ns/net", pid)
netFD, err := unix.Open(netns, unix.O_RDONLY, 0)
if err != nil {
return nil, errors.Wrapf(err, "error opening network namespace")
return nil, nil, errors.Wrapf(err, "error opening network namespace")
}
mynetns := fmt.Sprintf("/proc/%d/fd/%d", unix.Getpid(), netFD)

Expand All @@ -1179,9 +1164,9 @@ func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, optio
ContainerName: containerName,
Networks: networks,
}
_, err = b.NetworkInterface.Setup(mynetns, nettypes.SetupOptions{NetworkOptions: opts})
netStatus, err = b.NetworkInterface.Setup(mynetns, nettypes.SetupOptions{NetworkOptions: opts})
if err != nil {
return nil, err
return nil, nil, err
}

teardown = func() {
Expand All @@ -1191,7 +1176,7 @@ func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, optio
}
}

return teardown, nil
return teardown, netStatus, nil
}

func setNonblock(logger *logrus.Logger, fd int, description string, nonblocking bool) (bool, error) { //nolint:interfacer
Expand Down Expand Up @@ -2249,7 +2234,8 @@ func checkIdsGreaterThan5(ids []spec.LinuxIDMapping) bool {
return false
}

func (b *Builder) runUsingRuntimeSubproc(isolation define.Isolation, options RunOptions, configureNetwork bool, configureNetworks, moreCreateArgs []string, spec *specs.Spec, rootPath, bundlePath, containerName string) (err error) {
func (b *Builder) runUsingRuntimeSubproc(isolation define.Isolation, options RunOptions, configureNetwork bool, configureNetworks,
moreCreateArgs []string, spec *specs.Spec, rootPath, bundlePath, containerName, buildContainerName, hostsFile string) (err error) {
var confwg sync.WaitGroup
config, conferr := json.Marshal(runUsingRuntimeSubprocOptions{
Options: options,
Expand Down Expand Up @@ -2350,14 +2336,30 @@ func (b *Builder) runUsingRuntimeSubproc(isolation define.Isolation, options Run
return errors.Wrapf(err, "error parsing pid %s as a number", string(pidValue))
}

teardown, err := b.runConfigureNetwork(pid, isolation, options, configureNetworks, containerName)
teardown, netstatus, err := b.runConfigureNetwork(pid, isolation, options, configureNetworks, containerName)
if teardown != nil {
defer teardown()
}
if err != nil {
return err
}

// only add hosts if we manage the hosts file
if hostsFile != "" {
var entries etchosts.HostEntries
if netstatus != nil {
entries = etchosts.GetNetworkHostEntries(netstatus, spec.Hostname, buildContainerName)
} else {
// we have slirp4netns, default to slirp4netns ip since this is not configurable in buildah
entries = etchosts.HostEntries{{IP: "10.0.2.100", Names: []string{spec.Hostname, buildContainerName}}}
}
// make sure to sync this with (b *Builder) generateHosts()
err = etchosts.Add(hostsFile, entries)
if err != nil {
return err
}
}

logrus.Debug("network namespace successfully setup, send start message to child")
_, err = containerStartW.file.Write([]byte{1})
if err != nil {
Expand Down
13 changes: 9 additions & 4 deletions tests/from.bats
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ load helpers
run_buildah from --quiet --add-host=localhost:127.0.0.1 --pull --signature-policy ${TESTSDIR}/policy.json alpine
cid=$output
run_buildah run --net=container $cid -- cat /etc/hosts
expect_output --substring "127.0.0.1 +localhost"
expect_output --substring "127.0.0.1[[:blank:]]*localhost"
}

@test "from name test" {
Expand Down Expand Up @@ -649,6 +649,9 @@ load helpers
}

@test "from-image-by-id" {
skip_if_chroot
skip_if_no_runtime

_prefetch busybox
run_buildah from --cidfile ${TESTDIR}/cid busybox
cid=$(cat ${TESTDIR}/cid)
Expand All @@ -658,8 +661,10 @@ load helpers
iid=$(cat ${TESTDIR}/iid)
run_buildah from --cidfile ${TESTDIR}/cid2 ${iid}
cid2=$(cat ${TESTDIR}/cid2)
run_buildah run ${cid2} hostname -f
run_buildah run ${cid2} cat /etc/hosts
truncated=${iid##*:}
truncated=$(echo ${truncated} | cut -c-12)
expect_output ${truncated}-working-container
truncated="${truncated:0:12}"
expect_output --substring ${truncated}-working-container
run_buildah run ${cid2} hostname -f
expect_output "${cid2:0:12}"
}
12 changes: 12 additions & 0 deletions tests/helpers.bash
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ function createrandom() {
dd if=/dev/urandom bs=1 count=${2:-256} of=${1:-${BATS_TMPDIR}/randomfile} status=none
}

###################
# random_string # Returns a pseudorandom human-readable string
###################
#
# Numeric argument, if present, is desired length of string
#
function random_string() {
local length=${1:-10}

head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length
}

function buildah() {
${BUILDAH_BINARY} ${BUILDAH_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@"
}
Expand Down
27 changes: 22 additions & 5 deletions tests/run.bats
Original file line number Diff line number Diff line change
Expand Up @@ -605,18 +605,36 @@ function configure_and_check_user() {
${OCI} --version
_prefetch debian

local hostname=h-$(random_string)

run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json debian
cid=$output
run_buildah 125 run --network=bogus $cid cat /etc/hosts
expect_output --substring "unable to find network with name or ID bogus: network not found"
run_buildah run $cid cat /etc/hosts
expect_output --substring "127.0.0.1.*$cid"
expect_output --substring "::1.*$cid"
run_buildah run --hostname $hostname $cid cat /etc/hosts
expect_output --substring "(10.88.*|10.0.2.100)[[:blank:]]$hostname $cid"
ip=$(hostname -I | cut -f 1 -d " ")
expect_output --substring "$ip.*host.containers.internal"

hosts="127.0.0.5 host1
127.0.0.6 host2"
base_hosts_file="$TESTDIR/base_hosts"
echo "$hosts" > "$base_hosts_file"
containers_conf_file="$TESTDIR/containers.conf"
echo -e "[containers]\nbase_hosts_file = \"$base_hosts_file\"" > "$containers_conf_file"
CONTAINERS_CONF="$containers_conf_file" run_buildah run --hostname $hostname $cid cat /etc/hosts
expect_output --substring "127.0.0.5[[:blank:]]host1"
expect_output --substring "127.0.0.6[[:blank:]]host2"
expect_output --substring "(10.88.*|10.0.2.100)[[:blank:]]$hostname $cid"

# now check that hostname from base file is not overwritten
CONTAINERS_CONF="$containers_conf_file" run_buildah run --hostname host1 $cid cat /etc/hosts
expect_output --substring "127.0.0.5[[:blank:]]host1"
expect_output --substring "127.0.0.6[[:blank:]]host2"
expect_output --substring "(10.88.*|10.0.2.100)[[:blank:]]$cid"
assert "$output" !~ "(10.88.*|10.0.2.100)[[:blank:]]host1 $cid" "Container IP should not contain host1"

run_buildah run --network=container $cid cat /etc/hosts
expect_output --substring "# Generated by Buildah"
m=$(buildah mount $cid)
run cat $m/etc/hosts
[ "$status" -eq 0 ]
Expand All @@ -627,7 +645,6 @@ function configure_and_check_user() {
cid=$output
run_buildah run --network=host $cid cat /etc/hosts
hostOutput=$output
expect_output --substring "# Generated by Buildah"
m=$(buildah mount $cid)
run cat $m/etc/hosts
[ "$status" -eq 0 ]
Expand Down
18 changes: 0 additions & 18 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package util
import (
"fmt"
"io"
"net"
"net/url"
"os"
"path/filepath"
Expand Down Expand Up @@ -466,20 +465,3 @@ func VerifyTagName(imageSpec string) (types.ImageReference, error) {
}
return ref, nil
}

// LocalIP returns the non loopback local IP of the host
func LocalIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return ""
}
for _, address := range addrs {
// check the address type and if it is not a loopback the display it
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
return ipnet.IP.String()
}
}
}
return ""
}
Loading

0 comments on commit d93a4eb

Please sign in to comment.