Skip to content

Commit

Permalink
Merge pull request #24675 from gtjoseph/main-pass-hostname-to-netavark
Browse files Browse the repository at this point in the history
Pass container hostname to netavark
  • Loading branch information
openshift-merge-bot[bot] authored Jan 6, 2025
2 parents 04bc545 + 6fa234a commit e79686e
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 7 deletions.
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 {
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]))
})
})

0 comments on commit e79686e

Please sign in to comment.