From 2f98d7a3eab4016fe24e5a1d7ef4250f7540f3e7 Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Sun, 22 Apr 2018 16:55:39 -0400 Subject: [PATCH] Support nsenter in non-systemd environments 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. --- cmd/kubelet/app/server.go | 5 ++++- pkg/util/io/writer.go | 5 ++++- pkg/util/mount/nsenter_mount.go | 8 ++++++-- pkg/util/mount/nsenter_mount_unsupported.go | 4 ++-- pkg/util/nsenter/nsenter.go | 22 +++++++++++---------- pkg/util/nsenter/nsenter_unsupported.go | 4 ++-- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index ab561b719a..dc49c59d31 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -335,7 +335,10 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err var writer kubeio.Writer = &kubeio.StdWriter{} if s.Containerized { 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{} } diff --git a/pkg/util/io/writer.go b/pkg/util/io/writer.go index 8d1d9964e0..4c0c1c4b37 100644 --- a/pkg/util/io/writer.go +++ b/pkg/util/io/writer.go @@ -55,7 +55,10 @@ type NsenterWriter struct{} // WriteFile calls 'nsenter cat - > ' and 'nsenter chmod' to create a // file on the host. 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)} glog.V(5).Infof("nsenter: write data to file %s by nsenter", filename) command := ne.Exec("sh", echoArgs) diff --git a/pkg/util/mount/nsenter_mount.go b/pkg/util/mount/nsenter_mount.go index b887b1a3ef..ef9c9267d3 100644 --- a/pkg/util/mount/nsenter_mount.go +++ b/pkg/util/mount/nsenter_mount.go @@ -52,8 +52,12 @@ type NsenterMounter struct { ne *nsenter.Nsenter } -func NewNsenterMounter() *NsenterMounter { - return &NsenterMounter{ne: nsenter.NewNsenter()} +func NewNsenterMounter() (*NsenterMounter, error) { + ne, err := nsenter.NewNsenter() + if err != nil { + return nil, err + } + return &NsenterMounter{ne: ne}, nil } // NsenterMounter implements mount.Interface diff --git a/pkg/util/mount/nsenter_mount_unsupported.go b/pkg/util/mount/nsenter_mount_unsupported.go index 4b29f0ba42..6acb2d6573 100644 --- a/pkg/util/mount/nsenter_mount_unsupported.go +++ b/pkg/util/mount/nsenter_mount_unsupported.go @@ -25,8 +25,8 @@ import ( type NsenterMounter struct{} -func NewNsenterMounter() *NsenterMounter { - return &NsenterMounter{} +func NewNsenterMounter() (*NsenterMounter, error) { + return &NsenterMounter{}, nil } var _ = Interface(&NsenterMounter{}) diff --git a/pkg/util/nsenter/nsenter.go b/pkg/util/nsenter/nsenter.go index 32fbc08487..f5f7c987bd 100644 --- a/pkg/util/nsenter/nsenter.go +++ b/pkg/util/nsenter/nsenter.go @@ -57,7 +57,8 @@ const ( // contents. TODO: remove this requirement. // 6. The host image must have "mount", "findmnt", "umount", "stat", "touch", // "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: // https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt type Nsenter struct { @@ -66,7 +67,7 @@ type Nsenter struct { } // NewNsenter constructs a new instance of Nsenter -func NewNsenter() *Nsenter { +func NewNsenter() (*Nsenter, error) { ne := &Nsenter{ paths: map[string]string{ "mount": "", @@ -83,9 +84,8 @@ func NewNsenter() *Nsenter { } // search for the required commands in other locations besides /usr/bin for binary := range ne.paths { - // default to root - ne.paths[binary] = filepath.Join("/", binary) - for _, path := range []string{"/bin", "/usr/sbin", "/usr/bin"} { + // check for binary under the following directories + for _, path := range []string{"/", "/bin", "/usr/sbin", "/usr/bin"} { binPath := filepath.Join(path, binary) if _, err := os.Stat(filepath.Join(hostRootFsPath, binPath)); err != nil { continue @@ -93,10 +93,12 @@ func NewNsenter() *Nsenter { ne.paths[binary] = binPath break } - // TODO: error, so that the kubelet can stop if the paths don't exist - // (don't forget that systemd-run is optional) + // systemd-run is optional, bailout if we don't find any of the other binaries + 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 @@ -119,6 +121,6 @@ func (ne *Nsenter) AbsHostPath(command string) string { // SupportsSystemd checks whether command systemd-run exists func (ne *Nsenter) SupportsSystemd() (string, bool) { - systemdRunPath, hasSystemd := ne.paths["systemd-run"] - return systemdRunPath, hasSystemd + systemdRunPath, ok := ne.paths["systemd-run"] + return systemdRunPath, ok && systemdRunPath != "" } diff --git a/pkg/util/nsenter/nsenter_unsupported.go b/pkg/util/nsenter/nsenter_unsupported.go index 9c2130cb6f..842cf04673 100644 --- a/pkg/util/nsenter/nsenter_unsupported.go +++ b/pkg/util/nsenter/nsenter_unsupported.go @@ -30,8 +30,8 @@ type Nsenter struct { } // NewNsenter constructs a new instance of Nsenter -func NewNsenter() *Nsenter { - return &Nsenter{} +func NewNsenter() (*Nsenter, error) { + return &Nsenter{}, nil } // Exec executes nsenter commands in hostProcMountNsPath mount namespace