Skip to content

Commit

Permalink
Support the containers.conf container_name_as_hostname option
Browse files Browse the repository at this point in the history
When containers.conf has the "container_name_as_hostname" option set,
use that value, with values that don't fit `[A-Za-z0-9][A-Za-z0-9.-]+`
stripped out.

Signed-off-by: Nalin Dahyabhai <[email protected]>
  • Loading branch information
nalind committed Feb 18, 2025
1 parent 7fea494 commit 455f9d0
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 2 deletions.
23 changes: 23 additions & 0 deletions run_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/containers/storage/pkg/lockfile"
"github.com/containers/storage/pkg/mount"
"github.com/containers/storage/pkg/reexec"
"github.com/containers/storage/pkg/regexp"
"github.com/containers/storage/pkg/unshare"
"github.com/opencontainers/go-digest"
"github.com/opencontainers/runtime-spec/specs-go"
Expand All @@ -57,6 +58,10 @@ import (
"golang.org/x/term"
)

const maxHostnameLen = 64

var validHostnames = regexp.Delayed("[A-Za-z0-9][A-Za-z0-9.-]+")

func (b *Builder) createResolvConf(rdir string, chownOpts *idtools.IDPair) (string, error) {
cfile := filepath.Join(rdir, "resolv.conf")
f, err := os.Create(cfile)
Expand Down Expand Up @@ -2092,3 +2097,21 @@ func relabel(path, mountLabel string, shared bool) error {
}
return nil
}

// mapContainerNameToHostname returns the passed-in string with characters that
// don't match validHostnames (defined above) stripped out.
func mapContainerNameToHostname(containerName string) string {
match := validHostnames.FindStringIndex(containerName)
if match == nil {
return ""
}
trimmed := containerName[match[0]:]
match[1] -= match[0]
match[0] = 0
for match[1] != len(trimmed) && match[1] < match[0]+maxHostnameLen {
trimmed = trimmed[:match[1]] + trimmed[match[1]+1:]
match = validHostnames.FindStringIndex(trimmed)
match[1] = min(match[1], maxHostnameLen)
}
return trimmed[:match[1]]
}
31 changes: 31 additions & 0 deletions run_common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package buildah

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestMapContainerNameToHostname(t *testing.T) {
cases := [][2]string{
{"trivial", "trivial"},
{"Nottrivial", "Nottrivial"},
{"0Nottrivial", "0Nottrivial"},
{"0Nottrivi-al", "0Nottrivi-al"},
{"-0Nottrivi-al", "0Nottrivi-al"},
{".-0Nottrivi-.al", "0Nottrivi-.al"},
{".-0Nottrivi-.al0123456789", "0Nottrivi-.al0123456789"},
{".-0Nottrivi-.al0123456789+0123456789", "0Nottrivi-.al01234567890123456789"},
{".-0Nottrivi-.al0123456789+0123456789/0123456789", "0Nottrivi-.al012345678901234567890123456789"},
{".-0Nottrivi-.al0123456789+0123456789/0123456789%0123456789", "0Nottrivi-.al0123456789012345678901234567890123456789"},
{".-0Nottrivi-.al0123456789+0123456789/0123456789%0123456789_0123456789", "0Nottrivi-.al01234567890123456789012345678901234567890123456789"},
{".-0Nottrivi-.al0123456789+0123456789/0123456789%0123456789_0123456789:0123456", "0Nottrivi-.al012345678901234567890123456789012345678901234567890"},
{".-0Nottrivi-.al0123456789+0123456789/0123456789%0123456789_0123456789:0123456789", "0Nottrivi-.al012345678901234567890123456789012345678901234567890"},
}
for i := range cases {
t.Run(cases[i][0], func(t *testing.T) {
sanitized := mapContainerNameToHostname(cases[i][0])
assert.Equalf(t, cases[i][1], sanitized, "mapping container name %q to a valid hostname", cases[i][0])
})
}
}
12 changes: 11 additions & 1 deletion run_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,17 @@ func (b *Builder) configureNamespaces(g *generate.Generator, options *RunOptions
} else if b.Hostname() != "" {
g.SetHostname(b.Hostname())
} else {
g.SetHostname(stringid.TruncateID(b.ContainerID))
hostname := stringid.TruncateID(b.ContainerID)
defConfig, err := config.Default()
if err != nil {
return false, "", fmt.Errorf("failed to get container config: %w", err)
}
if defConfig.Containers.ContainerNameAsHostName {
if mapped := mapContainerNameToHostname(b.Container); mapped != "" {
hostname = mapped
}
}
g.SetHostname(hostname)
}
} else {
g.SetHostname("")
Expand Down
12 changes: 11 additions & 1 deletion run_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,17 @@ func (b *Builder) configureNamespaces(g *generate.Generator, options *RunOptions
} else if b.Hostname() != "" {
g.SetHostname(b.Hostname())
} else {
g.SetHostname(stringid.TruncateID(b.ContainerID))
hostname := stringid.TruncateID(b.ContainerID)
defConfig, err := config.Default()
if err != nil {
return false, "", fmt.Errorf("failed to get container config: %w", err)
}
if defConfig.Containers.ContainerNameAsHostName {
if mapped := mapContainerNameToHostname(b.Container); mapped != "" {
hostname = mapped
}
}
g.SetHostname(hostname)
}
} else {
g.SetHostname("")
Expand Down
18 changes: 18 additions & 0 deletions tests/run.bats
Original file line number Diff line number Diff line change
Expand Up @@ -997,3 +997,21 @@ _EOF
run_buildah ? bud --pull=false --layers .
expect_output --substring -- "-c requires an argument"
}

@test "container_name_as_hostname" {
skip_if_no_runtime

_prefetch alpine
echo '[containers]' > ${TEST_SCRATCH_DIR}/containers.conf
echo container_name_as_hostname = true >> ${TEST_SCRATCH_DIR}/containers.conf
name=alpine-working_containeR-4-test
sanitizedname=alpine-workingcontaineR-4-test
run_buildah from --name :"$name": --cidfile ${TEST_SCRATCH_DIR}/cid alpine
cname="$output"
run_buildah run "$cname" hostname
assert "$output" = $(cut -c1-12 < ${TEST_SCRATCH_DIR}/cid)
CONTAINERS_CONF=${TEST_SCRATCH_DIR}/containers.conf run_buildah run "$cname" hostname
expect_output "$sanitizedname"
CONTAINERS_CONF=${TEST_SCRATCH_DIR}/containers.conf run_buildah run "$(cat ${TEST_SCRATCH_DIR}/cid)" hostname
expect_output "$sanitizedname"
}

0 comments on commit 455f9d0

Please sign in to comment.