Merge pull request #62951 from dims/support-nsenter-better-in-non-systemd-envs

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Support nsenter in non-systemd environments

**What this PR does / why we need it**:

In our CI, we run kubekins image for most of the jobs. This is a
debian image with upstart and does not enable systemd. So we should

* Bailout if any binary is missing other than systemd-run.
* SupportsSystemd should check the binary path to correctly
  identify if the systemd-run is present or not
* Pass the errors back to the callers so kubelet is forced to
  fail early when there is a problem. We currently assume
  that all binaries are in the root directory by default which
  is wrong.


**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #

**Special notes for your reviewer**:

**Release note**:

```release-note
NONE
```
pull/8/head
Kubernetes Submit Queue 2018-04-25 01:08:10 -07:00 committed by GitHub
commit aa1ec693c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 30 additions and 18 deletions

View File

@ -335,7 +335,10 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err
var writer kubeio.Writer = &kubeio.StdWriter{} var writer kubeio.Writer = &kubeio.StdWriter{}
if s.Containerized { if s.Containerized {
glog.V(2).Info("Running kubelet in containerized mode") glog.V(2).Info("Running kubelet in containerized mode")
mounter = mount.NewNsenterMounter() mounter, err = mount.NewNsenterMounter()
if err != nil {
return nil, err
}
writer = &kubeio.NsenterWriter{} writer = &kubeio.NsenterWriter{}
} }

View File

@ -55,7 +55,10 @@ type NsenterWriter struct{}
// WriteFile calls 'nsenter cat - > <the file>' and 'nsenter chmod' to create a // WriteFile calls 'nsenter cat - > <the file>' and 'nsenter chmod' to create a
// file on the host. // file on the host.
func (writer *NsenterWriter) WriteFile(filename string, data []byte, perm os.FileMode) error { func (writer *NsenterWriter) WriteFile(filename string, data []byte, perm os.FileMode) error {
ne := nsenter.NewNsenter() ne, err := nsenter.NewNsenter()
if err != nil {
return err
}
echoArgs := []string{"-c", fmt.Sprintf("cat > %s", filename)} echoArgs := []string{"-c", fmt.Sprintf("cat > %s", filename)}
glog.V(5).Infof("nsenter: write data to file %s by nsenter", filename) glog.V(5).Infof("nsenter: write data to file %s by nsenter", filename)
command := ne.Exec("sh", echoArgs) command := ne.Exec("sh", echoArgs)

View File

@ -52,8 +52,12 @@ type NsenterMounter struct {
ne *nsenter.Nsenter ne *nsenter.Nsenter
} }
func NewNsenterMounter() *NsenterMounter { func NewNsenterMounter() (*NsenterMounter, error) {
return &NsenterMounter{ne: nsenter.NewNsenter()} ne, err := nsenter.NewNsenter()
if err != nil {
return nil, err
}
return &NsenterMounter{ne: ne}, nil
} }
// NsenterMounter implements mount.Interface // NsenterMounter implements mount.Interface

View File

@ -25,8 +25,8 @@ import (
type NsenterMounter struct{} type NsenterMounter struct{}
func NewNsenterMounter() *NsenterMounter { func NewNsenterMounter() (*NsenterMounter, error) {
return &NsenterMounter{} return &NsenterMounter{}, nil
} }
var _ = Interface(&NsenterMounter{}) var _ = Interface(&NsenterMounter{})

View File

@ -57,7 +57,8 @@ const (
// contents. TODO: remove this requirement. // contents. TODO: remove this requirement.
// 6. The host image must have "mount", "findmnt", "umount", "stat", "touch", // 6. The host image must have "mount", "findmnt", "umount", "stat", "touch",
// "mkdir", "ls", "sh" and "chmod" binaries in /bin, /usr/sbin, or /usr/bin // "mkdir", "ls", "sh" and "chmod" binaries in /bin, /usr/sbin, or /usr/bin
// 7. The host image should have systemd-run in /bin, /usr/sbin, or /usr/bin // 7. The host image should have systemd-run in /bin, /usr/sbin, or /usr/bin if
// systemd is installed/enabled in the operating system.
// For more information about mount propagation modes, see: // For more information about mount propagation modes, see:
// https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt // https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt
type Nsenter struct { type Nsenter struct {
@ -66,7 +67,7 @@ type Nsenter struct {
} }
// NewNsenter constructs a new instance of Nsenter // NewNsenter constructs a new instance of Nsenter
func NewNsenter() *Nsenter { func NewNsenter() (*Nsenter, error) {
ne := &Nsenter{ ne := &Nsenter{
paths: map[string]string{ paths: map[string]string{
"mount": "", "mount": "",
@ -83,9 +84,8 @@ func NewNsenter() *Nsenter {
} }
// search for the required commands in other locations besides /usr/bin // search for the required commands in other locations besides /usr/bin
for binary := range ne.paths { for binary := range ne.paths {
// default to root // check for binary under the following directories
ne.paths[binary] = filepath.Join("/", binary) for _, path := range []string{"/", "/bin", "/usr/sbin", "/usr/bin"} {
for _, path := range []string{"/bin", "/usr/sbin", "/usr/bin"} {
binPath := filepath.Join(path, binary) binPath := filepath.Join(path, binary)
if _, err := os.Stat(filepath.Join(hostRootFsPath, binPath)); err != nil { if _, err := os.Stat(filepath.Join(hostRootFsPath, binPath)); err != nil {
continue continue
@ -93,10 +93,12 @@ func NewNsenter() *Nsenter {
ne.paths[binary] = binPath ne.paths[binary] = binPath
break break
} }
// TODO: error, so that the kubelet can stop if the paths don't exist // systemd-run is optional, bailout if we don't find any of the other binaries
// (don't forget that systemd-run is optional) if ne.paths[binary] == "" && binary != "systemd-run" {
return nil, fmt.Errorf("unable to find %v", binary)
}
} }
return ne return ne, nil
} }
// Exec executes nsenter commands in hostProcMountNsPath mount namespace // Exec executes nsenter commands in hostProcMountNsPath mount namespace
@ -119,6 +121,6 @@ func (ne *Nsenter) AbsHostPath(command string) string {
// SupportsSystemd checks whether command systemd-run exists // SupportsSystemd checks whether command systemd-run exists
func (ne *Nsenter) SupportsSystemd() (string, bool) { func (ne *Nsenter) SupportsSystemd() (string, bool) {
systemdRunPath, hasSystemd := ne.paths["systemd-run"] systemdRunPath, ok := ne.paths["systemd-run"]
return systemdRunPath, hasSystemd return systemdRunPath, ok && systemdRunPath != ""
} }

View File

@ -30,8 +30,8 @@ type Nsenter struct {
} }
// NewNsenter constructs a new instance of Nsenter // NewNsenter constructs a new instance of Nsenter
func NewNsenter() *Nsenter { func NewNsenter() (*Nsenter, error) {
return &Nsenter{} return &Nsenter{}, nil
} }
// Exec executes nsenter commands in hostProcMountNsPath mount namespace // Exec executes nsenter commands in hostProcMountNsPath mount namespace