Merge pull request #50646 from rickypai/rpai/hostalias_hostnetwork
Automatic merge from submit-queue Support HostAlias for HostNetwork Pods **What this PR does / why we need it**: Currently, HostAlias does not support HostNetwork pods because historically, kubelet only manages hosts file for non-HostNetwork pods. With the recent change in https://github.com/kubernetes/kubernetes/pull/49140, kubelet now manages hosts file for all Pods, which enables HostAlias support also. **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #48398 **Special notes for your reviewer**: might be easier to review commit-by-commit **Release note**: ```release-note HostAlias is now supported for both non-HostNetwork Pods and HostNetwork Pods. ``` @yujuhong @hongchaodeng @thockin
This commit is contained in:
commit
ef1b835220
@ -2103,16 +2103,6 @@ func validateHostNetwork(hostNetwork bool, containers []api.Container, fldPath *
|
|||||||
return allErrors
|
return allErrors
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateHostNetworkNoHostAliases(hostNetwork bool, hostAliases []api.HostAlias, fldPath *field.Path) field.ErrorList {
|
|
||||||
allErrors := field.ErrorList{}
|
|
||||||
if hostNetwork {
|
|
||||||
if len(hostAliases) > 0 {
|
|
||||||
allErrors = append(allErrors, field.Forbidden(fldPath, "may not be set when `hostNetwork` is true"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return allErrors
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateImagePullSecrets checks to make sure the pull secrets are well
|
// validateImagePullSecrets checks to make sure the pull secrets are well
|
||||||
// formed. Right now, we only expect name to be set (it's the only field). If
|
// formed. Right now, we only expect name to be set (it's the only field). If
|
||||||
// this ever changes and someone decides to set those fields, we'd like to
|
// this ever changes and someone decides to set those fields, we'd like to
|
||||||
@ -2649,7 +2639,6 @@ func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *a
|
|||||||
|
|
||||||
if securityContext != nil {
|
if securityContext != nil {
|
||||||
allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers, specPath.Child("containers"))...)
|
allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers, specPath.Child("containers"))...)
|
||||||
allErrs = append(allErrs, validateHostNetworkNoHostAliases(securityContext.HostNetwork, spec.HostAliases, specPath)...)
|
|
||||||
if securityContext.FSGroup != nil {
|
if securityContext.FSGroup != nil {
|
||||||
for _, msg := range validation.IsValidGroupID(*securityContext.FSGroup) {
|
for _, msg := range validation.IsValidGroupID(*securityContext.FSGroup) {
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("fsGroup"), *(securityContext.FSGroup), msg))
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("fsGroup"), *(securityContext.FSGroup), msg))
|
||||||
|
@ -3984,6 +3984,15 @@ func TestValidatePodSpec(t *testing.T) {
|
|||||||
RestartPolicy: api.RestartPolicyAlways,
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
|
{ // Populate HostAliases with HostNetwork.
|
||||||
|
HostAliases: []api.HostAlias{{IP: "12.34.56.78", Hostnames: []string{"host1.foo", "host2.bar"}}},
|
||||||
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
SecurityContext: &api.PodSecurityContext{
|
||||||
|
HostNetwork: true,
|
||||||
|
},
|
||||||
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
{ // Populate PriorityClassName.
|
{ // Populate PriorityClassName.
|
||||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
@ -4056,12 +4065,6 @@ func TestValidatePodSpec(t *testing.T) {
|
|||||||
RestartPolicy: api.RestartPolicyAlways,
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
"with hostNetwork and hostAliases": {
|
|
||||||
SecurityContext: &api.PodSecurityContext{
|
|
||||||
HostNetwork: true,
|
|
||||||
},
|
|
||||||
HostAliases: []api.HostAlias{{IP: "12.34.56.78", Hostnames: []string{"host1", "host2"}}},
|
|
||||||
},
|
|
||||||
"with hostAliases with invalid IP": {
|
"with hostAliases with invalid IP": {
|
||||||
SecurityContext: &api.PodSecurityContext{
|
SecurityContext: &api.PodSecurityContext{
|
||||||
HostNetwork: false,
|
HostNetwork: false,
|
||||||
|
@ -233,7 +233,7 @@ func ensureHostsFile(fileName, hostIP, hostName, hostDomainName string, hostAlia
|
|||||||
// if Pod is using host network, read hosts file from the node's filesystem.
|
// if Pod is using host network, read hosts file from the node's filesystem.
|
||||||
// `etcHostsPath` references the location of the hosts file on the node.
|
// `etcHostsPath` references the location of the hosts file on the node.
|
||||||
// `/etc/hosts` for *nix systems.
|
// `/etc/hosts` for *nix systems.
|
||||||
hostsFileContent, err = nodeHostsFileContent(etcHostsPath)
|
hostsFileContent, err = nodeHostsFileContent(etcHostsPath, hostAliases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -246,8 +246,13 @@ func ensureHostsFile(fileName, hostIP, hostName, hostDomainName string, hostAlia
|
|||||||
}
|
}
|
||||||
|
|
||||||
// nodeHostsFileContent reads the content of node's hosts file.
|
// nodeHostsFileContent reads the content of node's hosts file.
|
||||||
func nodeHostsFileContent(hostsFilePath string) ([]byte, error) {
|
func nodeHostsFileContent(hostsFilePath string, hostAliases []v1.HostAlias) ([]byte, error) {
|
||||||
return ioutil.ReadFile(hostsFilePath)
|
hostsFileContent, err := ioutil.ReadFile(hostsFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hostsFileContent = append(hostsFileContent, hostsEntriesFromHostAliases(hostAliases)...)
|
||||||
|
return hostsFileContent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// managedHostsFileContent generates the content of the managed etc hosts based on Pod IP and other
|
// managedHostsFileContent generates the content of the managed etc hosts based on Pod IP and other
|
||||||
@ -266,6 +271,19 @@ func managedHostsFileContent(hostIP, hostName, hostDomainName string, hostAliase
|
|||||||
} else {
|
} else {
|
||||||
buffer.WriteString(fmt.Sprintf("%s\t%s\n", hostIP, hostName))
|
buffer.WriteString(fmt.Sprintf("%s\t%s\n", hostIP, hostName))
|
||||||
}
|
}
|
||||||
|
hostsFileContent := buffer.Bytes()
|
||||||
|
hostsFileContent = append(hostsFileContent, hostsEntriesFromHostAliases(hostAliases)...)
|
||||||
|
return hostsFileContent
|
||||||
|
}
|
||||||
|
|
||||||
|
func hostsEntriesFromHostAliases(hostAliases []v1.HostAlias) []byte {
|
||||||
|
if len(hostAliases) == 0 {
|
||||||
|
return []byte{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
buffer.WriteString("\n")
|
||||||
|
buffer.WriteString("# Entries added by HostAliases.\n")
|
||||||
// write each IP/hostname pair as an entry into hosts file
|
// write each IP/hostname pair as an entry into hosts file
|
||||||
for _, hostAlias := range hostAliases {
|
for _, hostAlias := range hostAliases {
|
||||||
for _, hostname := range hostAlias.Hostnames {
|
for _, hostname := range hostAlias.Hostnames {
|
||||||
|
@ -185,10 +185,22 @@ func TestMakeMounts(t *testing.T) {
|
|||||||
func TestNodeHostsFileContent(t *testing.T) {
|
func TestNodeHostsFileContent(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
hostsFileName string
|
hostsFileName string
|
||||||
expectedContent string
|
hostAliases []v1.HostAlias
|
||||||
|
rawHostsFileContent string
|
||||||
|
expectedHostsFileContent string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"hosts_test_file1",
|
"hosts_test_file1",
|
||||||
|
[]v1.HostAlias{},
|
||||||
|
`# hosts file for testing.
|
||||||
|
127.0.0.1 localhost
|
||||||
|
::1 localhost ip6-localhost ip6-loopback
|
||||||
|
fe00::0 ip6-localnet
|
||||||
|
fe00::0 ip6-mcastprefix
|
||||||
|
fe00::1 ip6-allnodes
|
||||||
|
fe00::2 ip6-allrouters
|
||||||
|
123.45.67.89 some.domain
|
||||||
|
`,
|
||||||
`# hosts file for testing.
|
`# hosts file for testing.
|
||||||
127.0.0.1 localhost
|
127.0.0.1 localhost
|
||||||
::1 localhost ip6-localhost ip6-loopback
|
::1 localhost ip6-localhost ip6-loopback
|
||||||
@ -201,6 +213,16 @@ fe00::2 ip6-allrouters
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"hosts_test_file2",
|
"hosts_test_file2",
|
||||||
|
[]v1.HostAlias{},
|
||||||
|
`# another hosts file for testing.
|
||||||
|
127.0.0.1 localhost
|
||||||
|
::1 localhost ip6-localhost ip6-loopback
|
||||||
|
fe00::0 ip6-localnet
|
||||||
|
fe00::0 ip6-mcastprefix
|
||||||
|
fe00::1 ip6-allnodes
|
||||||
|
fe00::2 ip6-allrouters
|
||||||
|
12.34.56.78 another.domain
|
||||||
|
`,
|
||||||
`# another hosts file for testing.
|
`# another hosts file for testing.
|
||||||
127.0.0.1 localhost
|
127.0.0.1 localhost
|
||||||
::1 localhost ip6-localhost ip6-loopback
|
::1 localhost ip6-localhost ip6-loopback
|
||||||
@ -209,18 +231,80 @@ fe00::0 ip6-mcastprefix
|
|||||||
fe00::1 ip6-allnodes
|
fe00::1 ip6-allnodes
|
||||||
fe00::2 ip6-allrouters
|
fe00::2 ip6-allrouters
|
||||||
12.34.56.78 another.domain
|
12.34.56.78 another.domain
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hosts_test_file1_with_host_aliases",
|
||||||
|
[]v1.HostAlias{
|
||||||
|
{IP: "123.45.67.89", Hostnames: []string{"foo", "bar", "baz"}},
|
||||||
|
},
|
||||||
|
`# hosts file for testing.
|
||||||
|
127.0.0.1 localhost
|
||||||
|
::1 localhost ip6-localhost ip6-loopback
|
||||||
|
fe00::0 ip6-localnet
|
||||||
|
fe00::0 ip6-mcastprefix
|
||||||
|
fe00::1 ip6-allnodes
|
||||||
|
fe00::2 ip6-allrouters
|
||||||
|
123.45.67.89 some.domain
|
||||||
|
`,
|
||||||
|
`# hosts file for testing.
|
||||||
|
127.0.0.1 localhost
|
||||||
|
::1 localhost ip6-localhost ip6-loopback
|
||||||
|
fe00::0 ip6-localnet
|
||||||
|
fe00::0 ip6-mcastprefix
|
||||||
|
fe00::1 ip6-allnodes
|
||||||
|
fe00::2 ip6-allrouters
|
||||||
|
123.45.67.89 some.domain
|
||||||
|
|
||||||
|
# Entries added by HostAliases.
|
||||||
|
123.45.67.89 foo
|
||||||
|
123.45.67.89 bar
|
||||||
|
123.45.67.89 baz
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hosts_test_file2_with_host_aliases",
|
||||||
|
[]v1.HostAlias{
|
||||||
|
{IP: "123.45.67.89", Hostnames: []string{"foo", "bar", "baz"}},
|
||||||
|
{IP: "456.78.90.123", Hostnames: []string{"park", "doo", "boo"}},
|
||||||
|
},
|
||||||
|
`# another hosts file for testing.
|
||||||
|
127.0.0.1 localhost
|
||||||
|
::1 localhost ip6-localhost ip6-loopback
|
||||||
|
fe00::0 ip6-localnet
|
||||||
|
fe00::0 ip6-mcastprefix
|
||||||
|
fe00::1 ip6-allnodes
|
||||||
|
fe00::2 ip6-allrouters
|
||||||
|
12.34.56.78 another.domain
|
||||||
|
`,
|
||||||
|
`# another hosts file for testing.
|
||||||
|
127.0.0.1 localhost
|
||||||
|
::1 localhost ip6-localhost ip6-loopback
|
||||||
|
fe00::0 ip6-localnet
|
||||||
|
fe00::0 ip6-mcastprefix
|
||||||
|
fe00::1 ip6-allnodes
|
||||||
|
fe00::2 ip6-allrouters
|
||||||
|
12.34.56.78 another.domain
|
||||||
|
|
||||||
|
# Entries added by HostAliases.
|
||||||
|
123.45.67.89 foo
|
||||||
|
123.45.67.89 bar
|
||||||
|
123.45.67.89 baz
|
||||||
|
456.78.90.123 park
|
||||||
|
456.78.90.123 doo
|
||||||
|
456.78.90.123 boo
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
tmpdir, err := writeHostsFile(testCase.hostsFileName, testCase.expectedContent)
|
tmpdir, err := writeHostsFile(testCase.hostsFileName, testCase.rawHostsFileContent)
|
||||||
require.NoError(t, err, "could not create a temp hosts file")
|
require.NoError(t, err, "could not create a temp hosts file")
|
||||||
defer os.RemoveAll(tmpdir)
|
defer os.RemoveAll(tmpdir)
|
||||||
|
|
||||||
actualContent, fileReadErr := nodeHostsFileContent(filepath.Join(tmpdir, testCase.hostsFileName))
|
actualContent, fileReadErr := nodeHostsFileContent(filepath.Join(tmpdir, testCase.hostsFileName), testCase.hostAliases)
|
||||||
require.NoError(t, fileReadErr, "could not create read hosts file")
|
require.NoError(t, fileReadErr, "could not create read hosts file")
|
||||||
assert.Equal(t, testCase.expectedContent, string(actualContent), "hosts file content not expected")
|
assert.Equal(t, testCase.expectedHostsFileContent, string(actualContent), "hosts file content not expected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +371,8 @@ fe00::0 ip6-mcastprefix
|
|||||||
fe00::1 ip6-allnodes
|
fe00::1 ip6-allnodes
|
||||||
fe00::2 ip6-allrouters
|
fe00::2 ip6-allrouters
|
||||||
203.0.113.1 podFoo.domainFoo podFoo
|
203.0.113.1 podFoo.domainFoo podFoo
|
||||||
|
|
||||||
|
# Entries added by HostAliases.
|
||||||
123.45.67.89 foo
|
123.45.67.89 foo
|
||||||
123.45.67.89 bar
|
123.45.67.89 bar
|
||||||
123.45.67.89 baz
|
123.45.67.89 baz
|
||||||
@ -308,6 +394,8 @@ fe00::0 ip6-mcastprefix
|
|||||||
fe00::1 ip6-allnodes
|
fe00::1 ip6-allnodes
|
||||||
fe00::2 ip6-allrouters
|
fe00::2 ip6-allrouters
|
||||||
203.0.113.1 podFoo.domainFoo podFoo
|
203.0.113.1 podFoo.domainFoo podFoo
|
||||||
|
|
||||||
|
# Entries added by HostAliases.
|
||||||
123.45.67.89 foo
|
123.45.67.89 foo
|
||||||
123.45.67.89 bar
|
123.45.67.89 bar
|
||||||
123.45.67.89 baz
|
123.45.67.89 baz
|
||||||
|
Loading…
Reference in New Issue
Block a user