From ceb33bde29f54a33a6d51efdb3a8669023d31f02 Mon Sep 17 00:00:00 2001 From: Ricky Pai Date: Mon, 14 Aug 2017 14:37:27 -0700 Subject: [PATCH 1/3] refactor entries added by hostAlias into a separate method and be explicit about the source --- pkg/kubelet/kubelet_pods.go | 13 +++++++++++++ pkg/kubelet/kubelet_pods_test.go | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/pkg/kubelet/kubelet_pods.go b/pkg/kubelet/kubelet_pods.go index c7588e30f9..34847d8488 100644 --- a/pkg/kubelet/kubelet_pods.go +++ b/pkg/kubelet/kubelet_pods.go @@ -266,6 +266,19 @@ func managedHostsFileContent(hostIP, hostName, hostDomainName string, hostAliase } else { 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 for _, hostAlias := range hostAliases { for _, hostname := range hostAlias.Hostnames { diff --git a/pkg/kubelet/kubelet_pods_test.go b/pkg/kubelet/kubelet_pods_test.go index eb9558706a..83a48fde14 100644 --- a/pkg/kubelet/kubelet_pods_test.go +++ b/pkg/kubelet/kubelet_pods_test.go @@ -287,6 +287,8 @@ fe00::0 ip6-mcastprefix fe00::1 ip6-allnodes fe00::2 ip6-allrouters 203.0.113.1 podFoo.domainFoo podFoo + +# Entries added by HostAliases. 123.45.67.89 foo 123.45.67.89 bar 123.45.67.89 baz @@ -308,6 +310,8 @@ fe00::0 ip6-mcastprefix fe00::1 ip6-allnodes fe00::2 ip6-allrouters 203.0.113.1 podFoo.domainFoo podFoo + +# Entries added by HostAliases. 123.45.67.89 foo 123.45.67.89 bar 123.45.67.89 baz From 4edd92f26d812c2bc7b7442e6a553ca3f60a4a8e Mon Sep 17 00:00:00 2001 From: Ricky Pai Date: Mon, 14 Aug 2017 14:44:21 -0700 Subject: [PATCH 2/3] add HostAlias support for HostNetwork pods --- pkg/kubelet/kubelet_pods.go | 11 +++- pkg/kubelet/kubelet_pods_test.go | 94 ++++++++++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 8 deletions(-) diff --git a/pkg/kubelet/kubelet_pods.go b/pkg/kubelet/kubelet_pods.go index 34847d8488..11a65313a6 100644 --- a/pkg/kubelet/kubelet_pods.go +++ b/pkg/kubelet/kubelet_pods.go @@ -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. // `etcHostsPath` references the location of the hosts file on the node. // `/etc/hosts` for *nix systems. - hostsFileContent, err = nodeHostsFileContent(etcHostsPath) + hostsFileContent, err = nodeHostsFileContent(etcHostsPath, hostAliases) if err != nil { return err } @@ -246,8 +246,13 @@ func ensureHostsFile(fileName, hostIP, hostName, hostDomainName string, hostAlia } // nodeHostsFileContent reads the content of node's hosts file. -func nodeHostsFileContent(hostsFilePath string) ([]byte, error) { - return ioutil.ReadFile(hostsFilePath) +func nodeHostsFileContent(hostsFilePath string, hostAliases []v1.HostAlias) ([]byte, error) { + 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 diff --git a/pkg/kubelet/kubelet_pods_test.go b/pkg/kubelet/kubelet_pods_test.go index 83a48fde14..413f266b84 100644 --- a/pkg/kubelet/kubelet_pods_test.go +++ b/pkg/kubelet/kubelet_pods_test.go @@ -184,11 +184,23 @@ func TestMakeMounts(t *testing.T) { func TestNodeHostsFileContent(t *testing.T) { testCases := []struct { - hostsFileName string - expectedContent string + hostsFileName string + hostAliases []v1.HostAlias + rawHostsFileContent string + expectedHostsFileContent string }{ { "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. 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback @@ -201,6 +213,16 @@ fe00::2 ip6-allrouters }, { "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. 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback @@ -209,18 +231,80 @@ fe00::0 ip6-mcastprefix fe00::1 ip6-allnodes fe00::2 ip6-allrouters 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 { - 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") 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") - assert.Equal(t, testCase.expectedContent, string(actualContent), "hosts file content not expected") + assert.Equal(t, testCase.expectedHostsFileContent, string(actualContent), "hosts file content not expected") } } From 1e7c0a4b0c15c1fd1dbdccd587da42eb587f47a9 Mon Sep 17 00:00:00 2001 From: Ricky Pai Date: Mon, 14 Aug 2017 15:39:14 -0700 Subject: [PATCH 3/3] remove validation disallowing hostAlias with hostNetwork --- pkg/api/validation/validation.go | 11 ----------- pkg/api/validation/validation_test.go | 17 ++++++++++------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index b160c0110c..7283cfca52 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -2067,16 +2067,6 @@ func validateHostNetwork(hostNetwork bool, containers []api.Container, fldPath * 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 // 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 @@ -2620,7 +2610,6 @@ func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *a if securityContext != nil { allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers, specPath.Child("containers"))...) - allErrs = append(allErrs, validateHostNetworkNoHostAliases(securityContext.HostNetwork, spec.HostAliases, specPath)...) if securityContext.FSGroup != nil { for _, msg := range validation.IsValidGroupID(*securityContext.FSGroup) { allErrs = append(allErrs, field.Invalid(fldPath.Child("fsGroup"), *(securityContext.FSGroup), msg)) diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index a849df8445..5be6f56a06 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -3844,13 +3844,22 @@ func TestValidatePodSpec(t *testing.T) { RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, - { // Populate HostAliases with `foo.bar` hostnames . + { // Populate HostAliases with `foo.bar` hostnames. HostAliases: []api.HostAlias{{IP: "12.34.56.78", Hostnames: []string{"host1.foo", "host2.bar"}}}, Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}}, Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, 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. Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}}, Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, @@ -3923,12 +3932,6 @@ func TestValidatePodSpec(t *testing.T) { RestartPolicy: api.RestartPolicyAlways, 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": { SecurityContext: &api.PodSecurityContext{ HostNetwork: false,