Set /etc/hostname.
Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
parent
7c2498d2e6
commit
089d4fbfb8
@ -28,7 +28,7 @@ import (
|
|||||||
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
|
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPodHostnameEnv(t *testing.T) {
|
func TestPodHostname(t *testing.T) {
|
||||||
hostname, err := os.Hostname()
|
hostname, err := os.Hostname()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for name, test := range map[string]struct {
|
for name, test := range map[string]struct {
|
||||||
@ -56,13 +56,13 @@ func TestPodHostnameEnv(t *testing.T) {
|
|||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
testPodLogDir, err := ioutil.TempDir("/tmp", "hostname-env")
|
testPodLogDir, err := ioutil.TempDir("/tmp", "hostname")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer os.RemoveAll(testPodLogDir)
|
defer os.RemoveAll(testPodLogDir)
|
||||||
|
|
||||||
opts := append(test.opts, WithPodLogDirectory(testPodLogDir))
|
opts := append(test.opts, WithPodLogDirectory(testPodLogDir))
|
||||||
t.Log("Create a sandbox with hostname")
|
t.Log("Create a sandbox with hostname")
|
||||||
sbConfig := PodSandboxConfig("sandbox", "hostname-env", opts...)
|
sbConfig := PodSandboxConfig("sandbox", "hostname", opts...)
|
||||||
sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler)
|
sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -85,7 +85,8 @@ func TestPodHostnameEnv(t *testing.T) {
|
|||||||
cnConfig := ContainerConfig(
|
cnConfig := ContainerConfig(
|
||||||
containerName,
|
containerName,
|
||||||
testImage,
|
testImage,
|
||||||
WithCommand("env"),
|
WithCommand("sh", "-c",
|
||||||
|
"echo -n /etc/hostname= && cat /etc/hostname && env"),
|
||||||
WithLogPath(containerName),
|
WithLogPath(containerName),
|
||||||
)
|
)
|
||||||
cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig)
|
cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig)
|
||||||
@ -106,10 +107,14 @@ func TestPodHostnameEnv(t *testing.T) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}, time.Second, 30*time.Second))
|
}, time.Second, 30*time.Second))
|
||||||
|
|
||||||
t.Log("Search hostname env in container log")
|
|
||||||
content, err := ioutil.ReadFile(filepath.Join(testPodLogDir, containerName))
|
content, err := ioutil.ReadFile(filepath.Join(testPodLogDir, containerName))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("Search hostname env in container log")
|
||||||
assert.Contains(t, string(content), "HOSTNAME="+test.expectedHostname)
|
assert.Contains(t, string(content), "HOSTNAME="+test.expectedHostname)
|
||||||
|
|
||||||
|
t.Log("Search /etc/hostname content in container log")
|
||||||
|
assert.Contains(t, string(content), "/etc/hostname="+test.expectedHostname)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -339,8 +339,7 @@ func (c *criService) generateContainerSpec(id string, sandboxID string, sandboxP
|
|||||||
|
|
||||||
// Add HOSTNAME env.
|
// Add HOSTNAME env.
|
||||||
hostname := sandboxConfig.GetHostname()
|
hostname := sandboxConfig.GetHostname()
|
||||||
if sandboxConfig.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE &&
|
if sandboxConfig.GetHostname() == "" {
|
||||||
hostname == "" {
|
|
||||||
hostname, err = c.os.Hostname()
|
hostname, err = c.os.Hostname()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -483,6 +482,14 @@ func (c *criService) generateVolumeMounts(containerRootDir string, criMounts []*
|
|||||||
func (c *criService) generateContainerMounts(sandboxID string, config *runtime.ContainerConfig) []*runtime.Mount {
|
func (c *criService) generateContainerMounts(sandboxID string, config *runtime.ContainerConfig) []*runtime.Mount {
|
||||||
var mounts []*runtime.Mount
|
var mounts []*runtime.Mount
|
||||||
securityContext := config.GetLinux().GetSecurityContext()
|
securityContext := config.GetLinux().GetSecurityContext()
|
||||||
|
if !isInCRIMounts(etcHostname, config.GetMounts()) {
|
||||||
|
mounts = append(mounts, &runtime.Mount{
|
||||||
|
ContainerPath: etcHostname,
|
||||||
|
HostPath: c.getSandboxHostname(sandboxID),
|
||||||
|
Readonly: securityContext.GetReadonlyRootfs(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if !isInCRIMounts(etcHosts, config.GetMounts()) {
|
if !isInCRIMounts(etcHosts, config.GetMounts()) {
|
||||||
mounts = append(mounts, &runtime.Mount{
|
mounts = append(mounts, &runtime.Mount{
|
||||||
ContainerPath: etcHosts,
|
ContainerPath: etcHosts,
|
||||||
|
@ -534,6 +534,11 @@ func TestGenerateContainerMounts(t *testing.T) {
|
|||||||
ReadonlyRootfs: true,
|
ReadonlyRootfs: true,
|
||||||
},
|
},
|
||||||
expectedMounts: []*runtime.Mount{
|
expectedMounts: []*runtime.Mount{
|
||||||
|
{
|
||||||
|
ContainerPath: "/etc/hostname",
|
||||||
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hostname"),
|
||||||
|
Readonly: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ContainerPath: "/etc/hosts",
|
ContainerPath: "/etc/hosts",
|
||||||
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"),
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"),
|
||||||
@ -554,6 +559,11 @@ func TestGenerateContainerMounts(t *testing.T) {
|
|||||||
"should setup rw mount when rootfs is read-write": {
|
"should setup rw mount when rootfs is read-write": {
|
||||||
securityContext: &runtime.LinuxContainerSecurityContext{},
|
securityContext: &runtime.LinuxContainerSecurityContext{},
|
||||||
expectedMounts: []*runtime.Mount{
|
expectedMounts: []*runtime.Mount{
|
||||||
|
{
|
||||||
|
ContainerPath: "/etc/hostname",
|
||||||
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hostname"),
|
||||||
|
Readonly: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ContainerPath: "/etc/hosts",
|
ContainerPath: "/etc/hosts",
|
||||||
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"),
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"),
|
||||||
@ -576,6 +586,11 @@ func TestGenerateContainerMounts(t *testing.T) {
|
|||||||
NamespaceOptions: &runtime.NamespaceOption{Ipc: runtime.NamespaceMode_NODE},
|
NamespaceOptions: &runtime.NamespaceOption{Ipc: runtime.NamespaceMode_NODE},
|
||||||
},
|
},
|
||||||
expectedMounts: []*runtime.Mount{
|
expectedMounts: []*runtime.Mount{
|
||||||
|
{
|
||||||
|
ContainerPath: "/etc/hostname",
|
||||||
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hostname"),
|
||||||
|
Readonly: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ContainerPath: "/etc/hosts",
|
ContainerPath: "/etc/hosts",
|
||||||
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"),
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"),
|
||||||
@ -595,6 +610,10 @@ func TestGenerateContainerMounts(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"should skip container mounts if already mounted by CRI": {
|
"should skip container mounts if already mounted by CRI": {
|
||||||
criMounts: []*runtime.Mount{
|
criMounts: []*runtime.Mount{
|
||||||
|
{
|
||||||
|
ContainerPath: "/etc/hostname",
|
||||||
|
HostPath: "/test-etc-hostname",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ContainerPath: "/etc/hosts",
|
ContainerPath: "/etc/hosts",
|
||||||
HostPath: "/test-etc-host",
|
HostPath: "/test-etc-host",
|
||||||
|
@ -99,6 +99,8 @@ const (
|
|||||||
devShm = "/dev/shm"
|
devShm = "/dev/shm"
|
||||||
// etcHosts is the default path of /etc/hosts file.
|
// etcHosts is the default path of /etc/hosts file.
|
||||||
etcHosts = "/etc/hosts"
|
etcHosts = "/etc/hosts"
|
||||||
|
// etcHostname is the default path of /etc/hostname file.
|
||||||
|
etcHostname = "/etc/hostname"
|
||||||
// resolvConfPath is the abs path of resolv.conf on host or container.
|
// resolvConfPath is the abs path of resolv.conf on host or container.
|
||||||
resolvConfPath = "/etc/resolv.conf"
|
resolvConfPath = "/etc/resolv.conf"
|
||||||
// hostnameEnv is the key for HOSTNAME env.
|
// hostnameEnv is the key for HOSTNAME env.
|
||||||
@ -199,6 +201,11 @@ func (c *criService) getVolatileContainerRootDir(id string) string {
|
|||||||
return filepath.Join(c.config.StateDir, containersDir, id)
|
return filepath.Join(c.config.StateDir, containersDir, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getSandboxHostname returns the hostname file path inside the sandbox root directory.
|
||||||
|
func (c *criService) getSandboxHostname(id string) string {
|
||||||
|
return filepath.Join(c.getSandboxRootDir(id), "hostname")
|
||||||
|
}
|
||||||
|
|
||||||
// getSandboxHosts returns the hosts file path inside the sandbox root directory.
|
// getSandboxHosts returns the hosts file path inside the sandbox root directory.
|
||||||
func (c *criService) getSandboxHosts(id string) string {
|
func (c *criService) getSandboxHosts(id string) string {
|
||||||
return filepath.Join(c.getSandboxRootDir(id), "hosts")
|
return filepath.Join(c.getSandboxRootDir(id), "hosts")
|
||||||
|
@ -233,7 +233,7 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Setup sandbox /dev/shm, /etc/hosts and /etc/resolv.conf.
|
// Setup sandbox /dev/shm, /etc/hosts, /etc/resolv.conf and /etc/hostname.
|
||||||
if err = c.setupSandboxFiles(id, config); err != nil {
|
if err = c.setupSandboxFiles(id, config); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to setup sandbox files")
|
return nil, errors.Wrapf(err, "failed to setup sandbox files")
|
||||||
}
|
}
|
||||||
@ -456,9 +456,22 @@ func (c *criService) generateSandboxContainerSpec(id string, config *runtime.Pod
|
|||||||
return g.Config, nil
|
return g.Config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts
|
// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts,
|
||||||
// and /etc/resolv.conf.
|
// /etc/resolv.conf and /etc/hostname.
|
||||||
func (c *criService) setupSandboxFiles(id string, config *runtime.PodSandboxConfig) error {
|
func (c *criService) setupSandboxFiles(id string, config *runtime.PodSandboxConfig) error {
|
||||||
|
sandboxEtcHostname := c.getSandboxHostname(id)
|
||||||
|
hostname := config.GetHostname()
|
||||||
|
if hostname == "" {
|
||||||
|
var err error
|
||||||
|
hostname, err = c.os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to get hostname")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := c.os.WriteFile(sandboxEtcHostname, []byte(hostname+"\n"), 0644); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to write hostname to %q", sandboxEtcHostname)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(random-liu): Consider whether we should maintain /etc/hosts and /etc/resolv.conf in kubelet.
|
// TODO(random-liu): Consider whether we should maintain /etc/hosts and /etc/resolv.conf in kubelet.
|
||||||
sandboxEtcHosts := c.getSandboxHosts(id)
|
sandboxEtcHosts := c.getSandboxHosts(id)
|
||||||
if err := c.os.CopyFile(etcHosts, sandboxEtcHosts, 0644); err != nil {
|
if err := c.os.CopyFile(etcHosts, sandboxEtcHosts, 0644); err != nil {
|
||||||
|
@ -180,15 +180,30 @@ func TestGenerateSandboxContainerSpec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSetupSandboxFiles(t *testing.T) {
|
func TestSetupSandboxFiles(t *testing.T) {
|
||||||
const testID = "test-id"
|
const (
|
||||||
|
testID = "test-id"
|
||||||
|
realhostname = "test-real-hostname"
|
||||||
|
)
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
dnsConfig *runtime.DNSConfig
|
dnsConfig *runtime.DNSConfig
|
||||||
|
hostname string
|
||||||
ipcMode runtime.NamespaceMode
|
ipcMode runtime.NamespaceMode
|
||||||
expectedCalls []ostesting.CalledDetail
|
expectedCalls []ostesting.CalledDetail
|
||||||
}{
|
}{
|
||||||
"should check host /dev/shm existence when ipc mode is NODE": {
|
"should check host /dev/shm existence when ipc mode is NODE": {
|
||||||
ipcMode: runtime.NamespaceMode_NODE,
|
ipcMode: runtime.NamespaceMode_NODE,
|
||||||
expectedCalls: []ostesting.CalledDetail{
|
expectedCalls: []ostesting.CalledDetail{
|
||||||
|
{
|
||||||
|
Name: "Hostname",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WriteFile",
|
||||||
|
Arguments: []interface{}{
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "hostname"),
|
||||||
|
[]byte(realhostname + "\n"),
|
||||||
|
os.FileMode(0644),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "CopyFile",
|
Name: "CopyFile",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
@ -219,6 +234,17 @@ func TestSetupSandboxFiles(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ipcMode: runtime.NamespaceMode_NODE,
|
ipcMode: runtime.NamespaceMode_NODE,
|
||||||
expectedCalls: []ostesting.CalledDetail{
|
expectedCalls: []ostesting.CalledDetail{
|
||||||
|
{
|
||||||
|
Name: "Hostname",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WriteFile",
|
||||||
|
Arguments: []interface{}{
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "hostname"),
|
||||||
|
[]byte(realhostname + "\n"),
|
||||||
|
os.FileMode(0644),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "CopyFile",
|
Name: "CopyFile",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
@ -246,6 +272,17 @@ options timeout:1
|
|||||||
"should create sandbox shm when ipc namespace mode is not NODE": {
|
"should create sandbox shm when ipc namespace mode is not NODE": {
|
||||||
ipcMode: runtime.NamespaceMode_POD,
|
ipcMode: runtime.NamespaceMode_POD,
|
||||||
expectedCalls: []ostesting.CalledDetail{
|
expectedCalls: []ostesting.CalledDetail{
|
||||||
|
{
|
||||||
|
Name: "Hostname",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WriteFile",
|
||||||
|
Arguments: []interface{}{
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "hostname"),
|
||||||
|
[]byte(realhostname + "\n"),
|
||||||
|
os.FileMode(0644),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "CopyFile",
|
Name: "CopyFile",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
@ -275,10 +312,48 @@ options timeout:1
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"should create /etc/hostname when hostname is set": {
|
||||||
|
hostname: "test-hostname",
|
||||||
|
ipcMode: runtime.NamespaceMode_NODE,
|
||||||
|
expectedCalls: []ostesting.CalledDetail{
|
||||||
|
{
|
||||||
|
Name: "WriteFile",
|
||||||
|
Arguments: []interface{}{
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "hostname"),
|
||||||
|
[]byte("test-hostname\n"),
|
||||||
|
os.FileMode(0644),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "CopyFile",
|
||||||
|
Arguments: []interface{}{
|
||||||
|
"/etc/hosts",
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "hosts"),
|
||||||
|
os.FileMode(0644),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "CopyFile",
|
||||||
|
Arguments: []interface{}{
|
||||||
|
"/etc/resolv.conf",
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "resolv.conf"),
|
||||||
|
os.FileMode(0644),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Stat",
|
||||||
|
Arguments: []interface{}{"/dev/shm"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
t.Logf("TestCase %q", desc)
|
t.Logf("TestCase %q", desc)
|
||||||
c := newTestCRIService()
|
c := newTestCRIService()
|
||||||
|
c.os.(*ostesting.FakeOS).HostnameFn = func() (string, error) {
|
||||||
|
return realhostname, nil
|
||||||
|
}
|
||||||
cfg := &runtime.PodSandboxConfig{
|
cfg := &runtime.PodSandboxConfig{
|
||||||
|
Hostname: test.hostname,
|
||||||
DnsConfig: test.dnsConfig,
|
DnsConfig: test.dnsConfig,
|
||||||
Linux: &runtime.LinuxPodSandboxConfig{
|
Linux: &runtime.LinuxPodSandboxConfig{
|
||||||
SecurityContext: &runtime.LinuxSandboxSecurityContext{
|
SecurityContext: &runtime.LinuxSandboxSecurityContext{
|
||||||
|
Loading…
Reference in New Issue
Block a user