Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass container hostname to netavark #24675

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 49 additions & 4 deletions libpod/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,8 +666,12 @@ func (c *Container) RuntimeName() string {
// Runtime spec accessors
// Unlocked

// Hostname gets the container's hostname
func (c *Container) Hostname() string {
// hostname determines the container's hostname.
// If 'network' is true and the container isn't running in a
// private UTS namespoace, an empty string will be returned
// instead of the host's hostname because we never want to
// send the host's hostname to a DHCP or DNS server.
func (c *Container) hostname(network bool) string {
if c.config.UTSNsCtr != "" {
utsNsCtr, err := c.runtime.GetContainer(c.config.UTSNsCtr)
if err != nil {
Expand All @@ -677,25 +681,66 @@ func (c *Container) Hostname() string {
}
return utsNsCtr.Hostname()
}

if c.config.Spec.Hostname != "" {
return c.config.Spec.Hostname
}

// if the container is not running in a private UTS namespace,
// return the host's hostname.
// If the container is not running in a private UTS namespace,
// return the host's hostname unless 'network' is true in which
// case we return an empty string.
privateUTS := c.hasPrivateUTS()
if !privateUTS {
hostname, err := os.Hostname()
if err == nil {
if network {
return ""
}
return hostname
}
logrus.Errorf("unable to get host's hostname for container %s: %v", c.ID(), err)
return ""
}

// If container_name_as_hostname is set in the CONTAINERS table in
// containers.conf, use a sanitized version of the container's name
// as the hostname. Since the container name must already match
// the set '[a-zA-Z0-9][a-zA-Z0-9_.-]*', we can just remove any
// underscores and limit it to 253 characters to make it a valid
// hostname.
if c.runtime.config.Containers.ContainerNameAsHostName {
sanitizedHostname := strings.ReplaceAll(c.Name(), "_", "")
if len(sanitizedHostname) <= 253 {
return sanitizedHostname
}
return sanitizedHostname[:253]
}

// Otherwise use the container's short ID as the hostname.
if len(c.ID()) < 11 {
return c.ID()
}
return c.ID()[:12]
}

// Hostname gets the container's hostname
func (c *Container) Hostname() string {
return c.hostname(false)
}

// If the container isn't running in a private UTS namespace, Hostname()
// will return the host's hostname as the container's hostname. If netavark
// were to try and obtain a DHCP lease with the host's hostname in an environment
// where DDNS was active, bad things could happen. NetworkHostname() on the
// other hand, will return an empty string if the container isn't running
// in a private UTS namespace.
//
// This function should only be used to populate the ContainerHostname member
// of the common.libnetwork.types.NetworkOptions struct.
func (c *Container) NetworkHostname() string {
gtjoseph marked this conversation as resolved.
Show resolved Hide resolved
return c.hostname(true)
}

// WorkingDir returns the containers working dir
func (c *Container) WorkingDir() string {
if c.config.Spec.Process != nil {
Expand Down
7 changes: 4 additions & 3 deletions libpod/networking_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ func (c *Container) getNetworkOptions(networkOpts map[string]types.PerNetworkOpt
nameservers = append(nameservers, ip.String())
}
opts := types.NetworkOptions{
ContainerID: c.config.ID,
ContainerName: getNetworkPodName(c),
DNSServers: nameservers,
ContainerID: c.config.ID,
ContainerName: getNetworkPodName(c),
DNSServers: nameservers,
ContainerHostname: c.NetworkHostname(),
}
opts.PortMappings = c.convertPortMappings()

Expand Down
105 changes: 105 additions & 0 deletions test/e2e/containers_conf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -763,4 +763,109 @@ var _ = Describe("Verify podman containers.conf usage", func() {
Expect(inspect.OutputToString()).Should(Equal(mode))
}
})

startContainer := func(params ...string) string {
args := []string{"create"}
for _, param := range params {
if param == "--name" {
args = append(args, "--replace")
break
}
}
args = append(args, params...)
args = append(args, ALPINE, "true")

result := podmanTest.Podman(args)
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
containerID := result.OutputToString()

return containerID
}

getContainerConfig := func(containerID string, formatParam string) string {
inspect := podmanTest.Podman([]string{"inspect", "--format", formatParam, containerID})
inspect.WaitWithDefaultTimeout()
value := inspect.OutputToString()
return value
}

It("podman containers.conf container_name_as_hostname", func() {

// With default containers.conf

// Start container with no options
containerID := startContainer()
hostname := getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should be the first 12 characters of the containerID
Expect(hostname).To(Equal(containerID[:12]))

// Start container with name
containerID = startContainer("--name", "cname1")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should still be the first 12 characters of the containerID
Expect(hostname).To(Equal(containerID[:12]))

// Start container with just hostname
containerID = startContainer("--hostname", "cname1.dev")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should now be "cname1.dev"
Expect(hostname).To(Equal("cname1.dev"))

// Start container with name and hostname
containerID = startContainer("--name", "cname1", "--hostname", "cname1.dev")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should now be "cname1.dev"
Expect(hostname).To(Equal("cname1.dev"))

// Create containers.conf override with container_name_as_hostname=true
conffile := filepath.Join(podmanTest.TempDir, "container.conf")
err := os.WriteFile(conffile, []byte("[containers]\ncontainer_name_as_hostname=true\n"), 0755)
Expect(err).ToNot(HaveOccurred())
os.Setenv("CONTAINERS_CONF_OVERRIDE", conffile)
if IsRemote() {
podmanTest.RestartRemoteService()
}

// Start container with no options
containerID = startContainer()
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
name := getContainerConfig(containerID, "{{ .Name }}")
// Hostname should be the auto generated container name with '_' removed
Expect(hostname).To(Equal(strings.ReplaceAll(name, "_", "")))

// Start container with name
containerID = startContainer("--name", "cname1")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should be the container name
Expect(hostname).To(Equal("cname1"))

// Start container with name containing '_'
containerID = startContainer("--name", "cname1_2_3")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should be the set container name with all '_' removed
Expect(hostname).To(Equal("cname123"))

// Start container with just hostname
containerID = startContainer("--hostname", "cname1.dev")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should now be "cname1.dev"
Expect(hostname).To(Equal("cname1.dev"))

// Start container with name and hostname
containerID = startContainer("--name", "cname1", "--hostname", "cname1.dev")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should still be "cname1.dev"
Expect(hostname).To(Equal("cname1.dev"))

// Start container with name = 260 characters
longHostname := "cnabcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890"
containerID = startContainer("--name", longHostname)
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
name = getContainerConfig(containerID, "{{ .Name }}")
// Double check that name actually got set correctly
Expect(name).To(Equal(longHostname))
// Hostname should be the container name truncated to 253 characters
Expect(hostname).To(Equal(name[:253]))
})
})
Loading