From bba8a8bb0ff79598d6d6112659c2204421ce9958 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 18 Mar 2020 00:10:21 +0000 Subject: [PATCH 01/19] Add SysV init support --- .../bootstrapper/bsutil/ktmpl/kubelet_sysv.go | 85 +++++++++++++++++++ pkg/minikube/bootstrapper/kubeadm/kubeadm.go | 8 +- pkg/minikube/cruntime/containerd.go | 19 ++--- pkg/minikube/cruntime/crio.go | 19 ++--- pkg/minikube/cruntime/cruntime.go | 21 ++++- pkg/minikube/cruntime/docker.go | 28 +++--- pkg/minikube/registry/drvs/none/none.go | 4 +- pkg/minikube/sysinit/sysinit.go | 42 +++++++++ pkg/minikube/sysinit/systemd.go | 73 ++++++++++++++++ pkg/minikube/sysinit/sysv.go | 61 +++++++++++++ 10 files changed, 311 insertions(+), 49 deletions(-) create mode 100644 pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go create mode 100644 pkg/minikube/sysinit/sysinit.go create mode 100644 pkg/minikube/sysinit/systemd.go create mode 100644 pkg/minikube/sysinit/sysv.go diff --git a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go new file mode 100644 index 000000000000..fc04c7e9e080 --- /dev/null +++ b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go @@ -0,0 +1,85 @@ +/* +Copyright 2020 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ktmpl + +RestartWrapperTemplate = template.Must(template.New("kubeletSysVTemplate").Parse(`#!/bin/bash +# Wrapper script to emulate systemd restart on non-systemd systems +binary=$1 +unitfile=$2 +args="" + +while [[ -x "${binary}" ]]; do + if [[ -f "${unitfile}" ]]; then + args=$(egrep "^ExecStart=${binary}" "${unitfile}" | cut -d" " -f2-) + fi + ${binary} ${args} + sleep 1 +done +``` + +KubeletSysVTemplate = template.Must(template.New("kubeletSysVTemplate").Parse(`#!/bin/sh +# SysV style init script for kubelet + +readonly KUBELET={{.KubeletPath}} +readonly KUBELET_WRAPPER={{.KubeletWrapperPath}} +readonly KUBELET_PIDFILE="/var/run/kubelet.pid" +readonly KUBELET_LOGFILE=/var/run/nohup.out + +if [[ ! -x "${KUBELET}" ]]; then + echo "$KUBELET not present or not executable" + exit 1 +fi + +function start() { + cd /var/run + nohup "${KUBELET_WRAPPER}" & + echo $! > "${KUBELET_PIDFILE}" +} + +function stop() { + if [[ -f "${KUBELET_PIDFILE}" ]]; then + kill $(cat ${KUBELET_PIDFILE}) + fi + pkill "${KUBELET_WRAPPER}" + pkill kubelet +} + + +case "$1" in + start) + start + ;; + + stop) + stop + ;; + + restart) + stop + start + ;; + + status) + pgrep kubelet + ;; + + *) + echo "Usage: service kubelet {start|stop|restart|status}" + exit 1 + ;; +esac +`) \ No newline at end of file diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index 92f896e4eff4..9a6264b57379 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -426,11 +426,14 @@ func (k *Bootstrapper) UpdateCluster(cfg config.ClusterConfig) error { glog.Infof("kubelet %s config:\n%+v", kubeletCfg, cfg.KubernetesConfig) + sm := sysinit.New(k.c) + // stop kubelet to avoid "Text File Busy" error - if err := stopKubelet(k.c); err != nil { + if err := sm.Stop("kubelet"); err != nil { glog.Warningf("unable to stop kubelet: %s", err) } + if err := bsutil.TransferBinaries(cfg.KubernetesConfig, k.c); err != nil { return errors.Wrap(err, "downloading binaries") } @@ -444,9 +447,10 @@ func (k *Bootstrapper) UpdateCluster(cfg config.ClusterConfig) error { return err } - if err := startKubelet(k.c); err != nil { + if err := sm.Start("kubelet"); err != nil { return err } + return nil } diff --git a/pkg/minikube/cruntime/containerd.go b/pkg/minikube/cruntime/containerd.go index d817dd7de05b..82d5e7e3d5b9 100644 --- a/pkg/minikube/cruntime/containerd.go +++ b/pkg/minikube/cruntime/containerd.go @@ -31,6 +31,7 @@ import ( "k8s.io/minikube/pkg/minikube/bootstrapper/images" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/out" + "k8s.io/minikube/pkg/minikube/sysinit" ) const ( @@ -115,6 +116,7 @@ type Containerd struct { Runner CommandRunner ImageRepository string KubernetesVersion semver.Version + Init sysinit.Manager } // Name is a human readable name for containerd @@ -157,9 +159,7 @@ func (r *Containerd) DefaultCNI() bool { // Active returns if containerd is active on the host func (r *Containerd) Active() bool { - c := exec.Command("sudo", "systemctl", "is-active", "--quiet", "service", "containerd") - _, err := r.Runner.RunCmd(c) - return err == nil + return r.Init.Active("containerd") } // Available returns an error if it is not possible to use this runtime on a host @@ -207,21 +207,14 @@ func (r *Containerd) Enable(disOthers bool) error { if err := enableIPForwarding(r.Runner); err != nil { return err } + // Otherwise, containerd will fail API requests with 'Unimplemented' - c := exec.Command("sudo", "systemctl", "restart", "containerd") - if _, err := r.Runner.RunCmd(c); err != nil { - return errors.Wrap(err, "restart containerd") - } - return nil + return r.Init.Restart("containerd") } // Disable idempotently disables containerd on a host func (r *Containerd) Disable() error { - c := exec.Command("sudo", "systemctl", "stop", "containerd") - if _, err := r.Runner.RunCmd(c); err != nil { - return errors.Wrapf(err, "stop containerd") - } - return nil + return r.Init.Stop("containerd") } // ImageExists checks if an image exists, expected input format diff --git a/pkg/minikube/cruntime/crio.go b/pkg/minikube/cruntime/crio.go index 804e4989bafc..2e057dddf708 100644 --- a/pkg/minikube/cruntime/crio.go +++ b/pkg/minikube/cruntime/crio.go @@ -27,6 +27,8 @@ import ( "k8s.io/minikube/pkg/minikube/bootstrapper/images" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/out" + "k8s.io/minikube/pkg/minikube/sysinit" + ) const ( @@ -40,6 +42,8 @@ type CRIO struct { Runner CommandRunner ImageRepository string KubernetesVersion semver.Version + Init sysinit.Manager + } // generateCRIOConfig sets up /etc/crio/crio.conf @@ -103,9 +107,7 @@ func (r *CRIO) Available() error { // Active returns if CRIO is active on the host func (r *CRIO) Active() bool { - c := exec.Command("sudo", "systemctl", "is-active", "--quiet", "service", "crio") - _, err := r.Runner.RunCmd(c) - return err == nil + return r.Init.Active("crio") } // Enable idempotently enables CRIO on a host @@ -124,19 +126,12 @@ func (r *CRIO) Enable(disOthers bool) error { if err := enableIPForwarding(r.Runner); err != nil { return err } - - if _, err := r.Runner.RunCmd(exec.Command("sudo", "systemctl", "restart", "crio")); err != nil { - return errors.Wrapf(err, "enable crio.") - } - return nil + return r.Init.Start("crio") } // Disable idempotently disables CRIO on a host func (r *CRIO) Disable() error { - if _, err := r.Runner.RunCmd(exec.Command("sudo", "systemctl", "stop", "crio")); err != nil { - return errors.Wrapf(err, "disable crio.") - } - return nil + return r.Init.Stop("crio") } // ImageExists checks if an image exists diff --git a/pkg/minikube/cruntime/cruntime.go b/pkg/minikube/cruntime/cruntime.go index d7153d083094..4c696efd1927 100644 --- a/pkg/minikube/cruntime/cruntime.go +++ b/pkg/minikube/cruntime/cruntime.go @@ -28,6 +28,7 @@ import ( "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/out" + "k8s.io/minikube/pkg/minikube/sysinit" ) // ContainerState is the run state of a container @@ -131,13 +132,27 @@ type ListOptions struct { // New returns an appropriately configured runtime func New(c Config) (Manager, error) { + sm := sysinit.New(c.Runner) + switch c.Type { case "", "docker": - return &Docker{Socket: c.Socket, Runner: c.Runner}, nil + return &Docker{Socket: c.Socket, Runner: c.Runner, Init: sm}, nil case "crio", "cri-o": - return &CRIO{Socket: c.Socket, Runner: c.Runner, ImageRepository: c.ImageRepository, KubernetesVersion: c.KubernetesVersion}, nil + return &CRIO{ + Socket: c.Socket, + Runner: c.Runner, + ImageRepository: c.ImageRepository, + KubernetesVersion: c.KubernetesVersion, + Init: sm, + }, nil case "containerd": - return &Containerd{Socket: c.Socket, Runner: c.Runner, ImageRepository: c.ImageRepository, KubernetesVersion: c.KubernetesVersion}, nil + return &Containerd{ + Socket: c.Socket, + Runner: c.Runner, + ImageRepository: c.ImageRepository, + KubernetesVersion: c.KubernetesVersion, + Init: sm, + }, nil default: return nil, fmt.Errorf("unknown runtime type: %q", c.Type) } diff --git a/pkg/minikube/cruntime/docker.go b/pkg/minikube/cruntime/docker.go index 8b203badec75..14bfc3aee05e 100644 --- a/pkg/minikube/cruntime/docker.go +++ b/pkg/minikube/cruntime/docker.go @@ -32,6 +32,7 @@ import ( "k8s.io/minikube/pkg/minikube/docker" "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/out" + "k8s.io/minikube/pkg/minikube/sysinit" ) // KubernetesContainerPrefix is the prefix of each kubernetes container @@ -56,6 +57,8 @@ func (e *ErrISOFeature) Error() string { type Docker struct { Socket string Runner CommandRunner + Init sysinit.Manager + } // Name is a human readable name for Docker @@ -95,11 +98,10 @@ func (r *Docker) Available() error { return err } + // Active returns if docker is active on the host func (r *Docker) Active() bool { - c := exec.Command("sudo", "systemctl", "is-active", "--quiet", "service", "docker") - _, err := r.Runner.RunCmd(c) - return err == nil + return r.Init.Active("docker") } // Enable idempotently enables Docker on a host @@ -109,29 +111,21 @@ func (r *Docker) Enable(disOthers bool) error { glog.Warningf("disableOthers: %v", err) } } - c := exec.Command("sudo", "systemctl", "start", "docker") - if _, err := r.Runner.RunCmd(c); err != nil { - return errors.Wrap(err, "enable docker.") - } - return nil + + return r.Init.Start("docker") } // Restart restarts Docker on a host func (r *Docker) Restart() error { - c := exec.Command("sudo", "systemctl", "restart", "docker") - if _, err := r.Runner.RunCmd(c); err != nil { - return errors.Wrap(err, "restarting docker.") - } - return nil + return r.Init.Restart("docker") } // Disable idempotently disables Docker on a host func (r *Docker) Disable() error { - c := exec.Command("sudo", "systemctl", "stop", "docker", "docker.socket") - if _, err := r.Runner.RunCmd(c); err != nil { - return errors.Wrap(err, "disable docker") + if err := r.Init.Stop("docker"); err != nil { + return err } - return nil + return r.Init.Stop("docker.socket") } // ImageExists checks if an image exists diff --git a/pkg/minikube/registry/drvs/none/none.go b/pkg/minikube/registry/drvs/none/none.go index 26542d4d2831..e7317c206bfb 100644 --- a/pkg/minikube/registry/drvs/none/none.go +++ b/pkg/minikube/registry/drvs/none/none.go @@ -51,9 +51,9 @@ func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { } func status() registry.State { - _, err := exec.LookPath("systemctl") + _, err := exec.LookPath("iptables") if err != nil { - return registry.State{Error: err, Fix: "Use a systemd based Linux distribution", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"} + return registry.State{Error: err, Fix: "iptables must be installed", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"} } return registry.State{Installed: true, Healthy: true} } diff --git a/pkg/minikube/sysinit/sysinit.go b/pkg/minikube/sysinit/sysinit.go new file mode 100644 index 000000000000..efbcc74f66d0 --- /dev/null +++ b/pkg/minikube/sysinit/sysinit.go @@ -0,0 +1,42 @@ +package sysinit + +import ( + "os/exec" + + "k8s.io/minikube/pkg/minikube/command" +) + +// Runner is the subset of command.Runner this package consumes +type Runner interface { + RunCmd(cmd *exec.Cmd) (*command.RunResult, error) +} + +// Manager is a common interface for init systems +type Manager interface { + // Name returns the name of the init manager + Name() string + + // Active returns if a service is active + Active(string) bool + + // Start starts a service idempotently + Start(string) error + + // Restart restarts a service + Restart(string) error + + // Stop stops a service + Stop(string) error +} + +// New returns an appropriately configured service manager +func New(r Runner) Manager { + // If we aren't passed a runner, pretend we are systemd as always + if r == nil { + return &Systemd{r: r} + } + if usesSystemd(r) { + return &Systemd{r: r} + } + return &SysV{r: r} +} diff --git a/pkg/minikube/sysinit/systemd.go b/pkg/minikube/sysinit/systemd.go new file mode 100644 index 000000000000..741bdd512c29 --- /dev/null +++ b/pkg/minikube/sysinit/systemd.go @@ -0,0 +1,73 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// sysinit provides an abstraction over init systems like systemctl +package sysinit + +import ( + "os/exec" +) + +// Systemd is a service manager for systemd distributions +type Systemd struct { + r Runner +} + +// Name returns the name of the init system +func (s *Systemd) Name() string { + return "systemd" +} + +// reload reloads systemd configuration +func (s *Systemd) reload() error { + _, err := s.r.RunCmd(exec.Command("sudo", "systemctl", "daemon-reload")) + return err == nil +} + +// Active checks if a service is running +func (s *Systemd) Active(svc string) bool { + _, err := s.r.RunCmd(exec.Command("sudo", "systemctl", "is-active", "--quiet", "service", svc)) + return err == nil +} + +// Start starts a service +func (s *Systemd) Start(svc string) error { + if err := s.reload() { + return err + } + _, err := s.r.RunCmd(exec.Command("sudo", "systemctl", "start", svc)) + return err +} + +// Restart restarts a service +func (s *Systemd) Restart(svc string) error { + if err := s.reload() { + return err + } + _, err := s.r.RunCmd(exec.Command("sudo", "systemctl", "restart", svc)) + return err +} + +// Stop stops a service +func (s *Systemd) Stop(svc string) error { + _, err := s.r.RunCmd(exec.Command("sudo", "systemctl", "restart", svc)) + return err +} + +func usesSystemd(r Runner) bool { + _, err := r.RunCmd(exec.Command("systemctl", "--version")) + return err == nil +} diff --git a/pkg/minikube/sysinit/sysv.go b/pkg/minikube/sysinit/sysv.go new file mode 100644 index 000000000000..d89309c0e441 --- /dev/null +++ b/pkg/minikube/sysinit/sysv.go @@ -0,0 +1,61 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// sysinit provides an abstraction over init systems like systemctl +package sysinit + +import ( + "os/exec" + "path" +) + +// SysV is a service manager for SysV-based init systems +type SysV struct { + r Runner +} + +// Name returns the name of the init system +func (s *Systemd) Name() string { + return "sysv" +} + + +// Active checks if a service is running +func (s *SysV) Active(svc string) bool { + _, err := s.r.RunCmd(exec.Command("sudo", path.Join("/etc/init.d", svc), "status")) + return err == nil +} + +// Start starts a service idempotently +func (s *SysV) Start(svc string) error { + if s.Active(svc) { + return nil + } + _, err := s.r.RunCmd(exec.Command("sudo", path.Join("/etc/init.d", svc), "start")) + return err +} + +// Restart restarts a service +func (s *SysV) Restart(svc string) error { + _, err := s.r.RunCmd(exec.Command("sudo", path.Join("/etc/init.d", svc), "restart")) + return err +} + +// Stop stops a service +func (s *SysV) Stop(svc string) error { + _, err := s.r.RunCmd(exec.Command("sudo", path.Join("/etc/init.d", svc), "stop")) + return err +} From 2ea6cd3a02fcef3b6c54d55ff1d1a0e7b685d5b8 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 3 Apr 2020 16:16:08 -0700 Subject: [PATCH 02/19] First semi-working version --- pkg/minikube/bootstrapper/bsutil/files.go | 22 +++----------- .../bootstrapper/bsutil/ktmpl/kubelet_sysv.go | 17 ++++++----- pkg/minikube/bootstrapper/bsutil/kubelet.go | 29 +++++++------------ pkg/minikube/bootstrapper/kubeadm/kubeadm.go | 28 +++++++++++++----- pkg/minikube/cruntime/cruntime.go | 18 ++++++------ pkg/minikube/node/start.go | 4 ++- pkg/minikube/sysinit/sysinit.go | 22 ++++++++++++-- pkg/minikube/sysinit/systemd.go | 2 +- pkg/minikube/sysinit/sysv.go | 4 ++- 9 files changed, 78 insertions(+), 68 deletions(-) diff --git a/pkg/minikube/bootstrapper/bsutil/files.go b/pkg/minikube/bootstrapper/bsutil/files.go index cec6d690856d..127f64b4e5ba 100644 --- a/pkg/minikube/bootstrapper/bsutil/files.go +++ b/pkg/minikube/bootstrapper/bsutil/files.go @@ -20,8 +20,6 @@ package bsutil import ( "path" - "k8s.io/minikube/pkg/minikube/assets" - "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/vmpath" ) @@ -35,20 +33,8 @@ const ( KubeletServiceFile = "/lib/systemd/system/kubelet.service" // KubeletSystemdConfFile is config for the systemd kubelet.service KubeletSystemdConfFile = "/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + // InitRestartWrapper is ... + InitRestartWrapper = "/etc/init.d/.restart_wrapper.sh" + // KubeletInitPath is where Sys-V style init script is installed + KubeletInitPath = "/etc/init.d/kubelet_sysv" ) - -// ConfigFileAssets returns configuration file assets -func ConfigFileAssets(cfg config.KubernetesConfig, kubeadm []byte, kubelet []byte, kubeletSvc []byte, defaultCNIConfig []byte) []assets.CopyableFile { - fs := []assets.CopyableFile{ - assets.NewMemoryAssetTarget(kubeadm, KubeadmYamlPath+".new", "0640"), - assets.NewMemoryAssetTarget(kubelet, KubeletSystemdConfFile+".new", "0644"), - assets.NewMemoryAssetTarget(kubeletSvc, KubeletServiceFile+".new", "0644"), - } - // Copy the default CNI config (k8s.conf), so that kubelet can successfully - // start a Pod in the case a user hasn't manually installed any CNI plugin - // and minikube was started with "--extra-config=kubelet.network-plugin=cni". - if defaultCNIConfig != nil { - fs = append(fs, assets.NewMemoryAssetTarget(defaultCNIConfig, DefaultCNIConfigPath, "0644")) - } - return fs -} diff --git a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go index 373a55025e75..fae7e04ac150 100644 --- a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go +++ b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go @@ -21,25 +21,26 @@ import "text/template" var RestartWrapper = `#!/bin/bash # Wrapper script to emulate systemd restart on non-systemd systems binary=$1 -unitfile=$2 +conf=$2 args="" while [[ -x "${binary}" ]]; do - if [[ -f "${unitfile}" ]]; then - args=$(egrep "^ExecStart=${binary}" "${unitfile}" | cut -d" " -f2-) + if [[ -f "${conf}" ]]; then + args=$(egrep "^ExecStart=${binary}" "${conf}" | cut -d" " -f2-) fi ${binary} ${args} sleep 1 done ` -var KubeletSysVTemplate = template.Must(template.New("kubeletSysVTemplate").Parse(`#!/bin/sh +var KubeletInitTemplate = template.Must(template.New("kubeletSysVTemplate").Parse(`#!/bin/bash # SysV style init script for kubelet -readonly KUBELET={{.KubeletPath}} -readonly KUBELET_WRAPPER={{.KubeletWrapperPath}} +readonly KUBELET="{{.KubeletPath}}" +readonly KUBELET_WRAPPER="{{.WrapperPath}}" +readonly KUBELET_CONF="{{.ConfPath}}" readonly KUBELET_PIDFILE="/var/run/kubelet.pid" -readonly KUBELET_LOGFILE=/var/run/nohup.out +readonly KUBELET_LOGFILE="/var/run/nohup.out" if [[ ! -x "${KUBELET}" ]]; then echo "$KUBELET not present or not executable" @@ -48,7 +49,7 @@ fi function start() { cd /var/run - nohup "${KUBELET_WRAPPER}" & + nohup "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" & echo $! > "${KUBELET_PIDFILE}" } diff --git a/pkg/minikube/bootstrapper/bsutil/kubelet.go b/pkg/minikube/bootstrapper/bsutil/kubelet.go index 3902c60a569e..a25cc074c3a2 100644 --- a/pkg/minikube/bootstrapper/bsutil/kubelet.go +++ b/pkg/minikube/bootstrapper/bsutil/kubelet.go @@ -119,33 +119,24 @@ func NewKubeletService(cfg config.KubernetesConfig) ([]byte, error) { return b.Bytes(), nil } -func NewSysVTemplate(k8s config.KubernetesConfig ([]byte, error) { +// NewInitScript returns a generated systemd unit file for the kubelet +func NewInitScript(v string, wrapperPath string) ([]byte, error) { + var b bytes.Buffer opts := struct { - - KubeletPath string + KubeletPath string + WrapperPath string + ConfPath string }{ - ExtraOptions: convertToFlags(extraOpts), - ContainerRuntime: k8s.ContainerRuntime, - KubeletPath: path.Join(binRoot(k8s.KubernetesVersion), "kubelet"), + KubeletPath: path.Join(binRoot(v), "kubelet"), + WrapperPath: wrapperPath, + ConfPath: KubeletSystemdConfFile, } - if err := ktmpl.KubeletSystemdTemplate.Execute(&b, opts); err != nil { - return nil, err - } - - return b.Bytes(), nil -} - -// NewKubeletService returns a generated systemd unit file for the kubelet -func NewKubeletService(cfg config.KubernetesConfig) ([]byte, error) { - var b bytes.Buffer - opts := struct{ KubeletPath string }{KubeletPath: path.Join(binRoot(cfg.KubernetesVersion), "kubelet")} - if err := ktmpl.KubeletServiceTemplate.Execute(&b, opts); err != nil { + if err := ktmpl.KubeletInitTemplate.Execute(&b, opts); err != nil { return nil, errors.Wrap(err, "template execute") } return b.Bytes(), nil } - // KubeNodeName returns the node name registered in Kubernetes func KubeNodeName(cc config.ClusterConfig, n config.Node) string { if cc.Driver == driver.None { diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index adf5e4674ae6..a7d8b2f64540 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -43,6 +43,7 @@ import ( "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/bootstrapper/bsutil" + "k8s.io/minikube/pkg/minikube/bootstrapper/bsutil/ktmpl" "k8s.io/minikube/pkg/minikube/bootstrapper/bsutil/kverify" "k8s.io/minikube/pkg/minikube/bootstrapper/images" "k8s.io/minikube/pkg/minikube/command" @@ -190,7 +191,7 @@ func (k *Bootstrapper) init(cfg config.ClusterConfig) error { } extraFlags := bsutil.CreateFlagsFromExtraArgs(cfg.KubernetesConfig.ExtraOptions) - r, err := cruntime.New(cruntime.Config{Type: cfg.KubernetesConfig.ContainerRuntime}) + r, err := cruntime.New(cruntime.Config{Type: cfg.KubernetesConfig.ContainerRuntime, Runner: k.c}) if err != nil { return err } @@ -655,17 +656,28 @@ func (k *Bootstrapper) UpdateNode(cfg config.ClusterConfig, n config.Node, r cru return errors.Wrap(err, "downloading binaries") } - var cniFile []byte + files := []assets.CopyableFile{ + assets.NewMemoryAssetTarget(kubeadmCfg, bsutil.KubeadmYamlPath+".new", "0640"), + assets.NewMemoryAssetTarget(kubeletCfg, bsutil.KubeletSystemdConfFile+".new", "0644"), + assets.NewMemoryAssetTarget(kubeletService, bsutil.KubeletServiceFile+".new", "0644"), + } + // Copy the default CNI config (k8s.conf), so that kubelet can successfully + // start a Pod in the case a user hasn't manually installed any CNI plugin + // and minikube was started with "--extra-config=kubelet.network-plugin=cni". if cfg.KubernetesConfig.EnableDefaultCNI { - cniFile = []byte(defaultCNIConfig) + files = append(files, assets.NewMemoryAssetTarget([]byte(defaultCNIConfig), bsutil.DefaultCNIConfigPath, "0644")) } - // Install assets into temporary files - files := bsutil.ConfigFileAssets(cfg.KubernetesConfig, kubeadmCfg, kubeletCfg, kubeletService, cniFile) - + glog.Infof("sysinit says: %v", sm.Name()) // Install SysV-like init scripts if necessary - if sm.Name() == "sysv" { - files = append(files) + if sm.Name() == sysinit.SysVName { + initScript, err := bsutil.NewInitScript(cfg.KubernetesConfig.KubernetesVersion, bsutil.InitRestartWrapper) + if err != nil { + return errors.Wrap(err, "init script") + } + + files = append(files, assets.NewMemoryAssetTarget([]byte(ktmpl.RestartWrapper), bsutil.InitRestartWrapper, "0755")) + files = append(files, assets.NewMemoryAssetTarget(initScript, bsutil.KubeletInitPath, "0755")) } if err := copyFiles(k.c, files); err != nil { diff --git a/pkg/minikube/cruntime/cruntime.go b/pkg/minikube/cruntime/cruntime.go index 4c696efd1927..9bde921993e1 100644 --- a/pkg/minikube/cruntime/cruntime.go +++ b/pkg/minikube/cruntime/cruntime.go @@ -133,25 +133,25 @@ type ListOptions struct { // New returns an appropriately configured runtime func New(c Config) (Manager, error) { sm := sysinit.New(c.Runner) - + switch c.Type { case "", "docker": return &Docker{Socket: c.Socket, Runner: c.Runner, Init: sm}, nil case "crio", "cri-o": return &CRIO{ - Socket: c.Socket, - Runner: c.Runner, - ImageRepository: c.ImageRepository, + Socket: c.Socket, + Runner: c.Runner, + ImageRepository: c.ImageRepository, KubernetesVersion: c.KubernetesVersion, - Init: sm, + Init: sm, }, nil case "containerd": return &Containerd{ - Socket: c.Socket, - Runner: c.Runner, - ImageRepository: c.ImageRepository, + Socket: c.Socket, + Runner: c.Runner, + ImageRepository: c.ImageRepository, KubernetesVersion: c.KubernetesVersion, - Init: sm, + Init: sm, }, nil default: return nil, fmt.Errorf("unknown runtime type: %q", c.Type) diff --git a/pkg/minikube/node/start.go b/pkg/minikube/node/start.go index 11695485d00e..eda61ab59262 100644 --- a/pkg/minikube/node/start.go +++ b/pkg/minikube/node/start.go @@ -117,6 +117,7 @@ func Start(cc config.ClusterConfig, n config.Node, existingAddons map[string]boo // setup kubeadm (must come after setupKubeconfig) bs = setupKubeAdm(machineAPI, cc, n) + err = bs.StartCluster(cc) if err != nil { exit.WithLogEntries("Error starting cluster", err, logs.FindProblems(cr, bs, cc, mRunner)) @@ -192,7 +193,8 @@ func Start(cc config.ClusterConfig, n config.Node, existingAddons map[string]boo func configureRuntimes(runner cruntime.CommandRunner, drvName string, k8s config.KubernetesConfig, kv semver.Version) cruntime.Manager { co := cruntime.Config{ Type: viper.GetString(containerRuntime), - Runner: runner, ImageRepository: k8s.ImageRepository, + Runner: runner, + ImageRepository: k8s.ImageRepository, KubernetesVersion: kv, } cr, err := cruntime.New(co) diff --git a/pkg/minikube/sysinit/sysinit.go b/pkg/minikube/sysinit/sysinit.go index 7d158a754bfa..f39347d51719 100644 --- a/pkg/minikube/sysinit/sysinit.go +++ b/pkg/minikube/sysinit/sysinit.go @@ -2,10 +2,14 @@ package sysinit import ( "os/exec" + "runtime" + "github.com/golang/glog" "k8s.io/minikube/pkg/minikube/command" ) +var cachedSystemdCheck *bool + // Runner is the subset of command.Runner this package consumes type Runner interface { RunCmd(cmd *exec.Cmd) (*command.RunResult, error) @@ -34,11 +38,23 @@ type Manager interface { // New returns an appropriately configured service manager func New(r Runner) Manager { - // If we aren't passed a runner, pretend we are systemd as always + _, file, no, _ := runtime.Caller(1) + if r == nil { - return &Systemd{r: r} + glog.Warningf("manager from %s:%d: nil runner! (systemd)", file, no) + return nil } - if usesSystemd(r) { + + var systemd bool + if cachedSystemdCheck != nil { + systemd = *cachedSystemdCheck + } else { + glog.Errorf("uncached systemd check from %s:%d", file, no) + systemd = usesSystemd(r) + cachedSystemdCheck = &systemd + } + + if systemd { return &Systemd{r: r} } return &SysV{r: r} diff --git a/pkg/minikube/sysinit/systemd.go b/pkg/minikube/sysinit/systemd.go index 7f9143ebd421..be840c3e09ce 100644 --- a/pkg/minikube/sysinit/systemd.go +++ b/pkg/minikube/sysinit/systemd.go @@ -74,6 +74,6 @@ func (s *Systemd) ForceStop(svc string) error { } func usesSystemd(r Runner) bool { - _, err := r.RunCmd(exec.Command("systemctl", "--version")) + _, err := r.RunCmd(exec.Command("xsystemctl", "--version")) return err == nil } diff --git a/pkg/minikube/sysinit/sysv.go b/pkg/minikube/sysinit/sysv.go index 99e9af7f7564..4c0db2cdbc20 100644 --- a/pkg/minikube/sysinit/sysv.go +++ b/pkg/minikube/sysinit/sysv.go @@ -21,6 +21,8 @@ import ( "os/exec" ) +const SysVName = "Sys-V" + // SysV is a service manager for SysV-like init systems type SysV struct { r Runner @@ -28,7 +30,7 @@ type SysV struct { // Name returns the name of the init system func (s *SysV) Name() string { - return "SysV" + return SysVName } // Active checks if a service is running From 455cdfffab28351ff7d0965b69ea83b73d1334c4 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 3 Apr 2020 18:33:54 -0700 Subject: [PATCH 03/19] Remove temp name --- pkg/minikube/bootstrapper/bsutil/files.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/minikube/bootstrapper/bsutil/files.go b/pkg/minikube/bootstrapper/bsutil/files.go index 127f64b4e5ba..8d6bc05bc36d 100644 --- a/pkg/minikube/bootstrapper/bsutil/files.go +++ b/pkg/minikube/bootstrapper/bsutil/files.go @@ -36,5 +36,5 @@ const ( // InitRestartWrapper is ... InitRestartWrapper = "/etc/init.d/.restart_wrapper.sh" // KubeletInitPath is where Sys-V style init script is installed - KubeletInitPath = "/etc/init.d/kubelet_sysv" + KubeletInitPath = "/etc/init.d/kubelet" ) From de366d7c4391316766bae38507b5859139b580fc Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 3 Apr 2020 18:59:52 -0700 Subject: [PATCH 04/19] More development on sysv support --- cmd/minikube/cmd/docker-env.go | 6 ++---- .../bootstrapper/bsutil/ktmpl/kubelet_sysv.go | 16 ++++++++++++++-- .../bootstrapper/bsutil/kverify/kverify.go | 19 +++++-------------- pkg/minikube/bootstrapper/kubeadm/kubeadm.go | 18 ++---------------- pkg/minikube/kubelet/kubelet.go | 7 ++++--- pkg/minikube/sysinit/systemd.go | 2 +- 6 files changed, 28 insertions(+), 40 deletions(-) diff --git a/cmd/minikube/cmd/docker-env.go b/cmd/minikube/cmd/docker-env.go index 76ae9d4f5ad0..c4432c6b5825 100644 --- a/cmd/minikube/cmd/docker-env.go +++ b/cmd/minikube/cmd/docker-env.go @@ -24,7 +24,6 @@ import ( "io" "net" "os" - "os/exec" "strconv" "strings" @@ -38,6 +37,7 @@ import ( "k8s.io/minikube/pkg/minikube/mustload" "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/shell" + "k8s.io/minikube/pkg/minikube/sysinit" ) var dockerEnvTmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubeDockerdProfile }}{{ .Suffix }}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}", constants.DockerTLSVerifyEnv, constants.DockerHostEnv, constants.DockerCertPathEnv, constants.MinikubeActiveDockerdEnv) @@ -116,9 +116,7 @@ func (EnvNoProxyGetter) GetNoProxyVar() (string, string) { // isDockerActive checks if Docker is active func isDockerActive(r command.Runner) bool { - c := exec.Command("sudo", "systemctl", "is-active", "--quiet", "service", "docker") - _, err := r.RunCmd(c) - return err == nil + return sysinit.New(r).Active("docker") } // dockerEnvCmd represents the docker-env command diff --git a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go index fae7e04ac150..4ee81697d8bb 100644 --- a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go +++ b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go @@ -77,9 +77,21 @@ case "$1" in ;; status) - pgrep kubelet + if [[ -f "${KUBELET_PIDFILE}" ]]; then + kill -0 $(cat ${KUBELET_PIDFILE}) + if [[ "$?" != 0 ]]; then + echo "${KUBELET_PIDFILE} is stale" + exit 1 + fi + else + echo "${KUBELET_PIDFILE} is missing" + exit 2 + fi + + echo "matching processes:" + pgrep -f kubelet + exit 0 ;; - *) echo "Usage: service kubelet {start|stop|restart|status}" exit 1 diff --git a/pkg/minikube/bootstrapper/bsutil/kverify/kverify.go b/pkg/minikube/bootstrapper/bsutil/kverify/kverify.go index b7bf7fd5c5a1..dcf30b386a78 100644 --- a/pkg/minikube/bootstrapper/bsutil/kverify/kverify.go +++ b/pkg/minikube/bootstrapper/bsutil/kverify/kverify.go @@ -42,6 +42,7 @@ import ( "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/logs" + "k8s.io/minikube/pkg/minikube/sysinit" ) // minLogCheckTime how long to wait before spamming error logs to console @@ -322,20 +323,10 @@ func apiServerHealthz(hostname string, port int) (state.State, error) { // KubeletStatus checks the kubelet status func KubeletStatus(cr command.Runner) (state.State, error) { glog.Infof("Checking kubelet status ...") - rr, err := cr.RunCmd(exec.Command("sudo", "systemctl", "is-active", "kubelet")) - if err != nil { - // Do not return now, as we still have parsing to do! - glog.Warningf("%s returned error: %v", rr.Command(), err) - } - s := strings.TrimSpace(rr.Stdout.String()) - glog.Infof("kubelet is-active: %s", s) - switch s { - case "active": + + active := sysinit.New(cr).Active("kubelet") + if active { return state.Running, nil - case "inactive": - return state.Stopped, nil - case "activating": - return state.Starting, nil } - return state.Error, nil + return state.Stopped, nil } diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index a7d8b2f64540..7a7a111fd012 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -85,22 +85,8 @@ func NewBootstrapper(api libmachine.API, cc config.ClusterConfig, n config.Node) // GetKubeletStatus returns the kubelet status func (k *Bootstrapper) GetKubeletStatus() (string, error) { - rr, err := k.c.RunCmd(exec.Command("sudo", "systemctl", "is-active", "kubelet")) - if err != nil { - // Do not return now, as we still have parsing to do! - glog.Warningf("%s returned error: %v", rr.Command(), err) - } - s := strings.TrimSpace(rr.Stdout.String()) - glog.Infof("kubelet is-active: %s", s) - switch s { - case "active": - return state.Running.String(), nil - case "inactive": - return state.Stopped.String(), nil - case "activating": - return state.Starting.String(), nil - } - return state.Error.String(), nil + st, err := kverify.KubeletStatus(k.c) + return st.String(), err } // GetAPIServerStatus returns the api-server status diff --git a/pkg/minikube/kubelet/kubelet.go b/pkg/minikube/kubelet/kubelet.go index 8f15e6aca02a..90b9391e86f3 100644 --- a/pkg/minikube/kubelet/kubelet.go +++ b/pkg/minikube/kubelet/kubelet.go @@ -25,6 +25,7 @@ import ( "github.com/golang/glog" "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/command" + "k8s.io/minikube/pkg/minikube/sysinit" "k8s.io/minikube/pkg/util/retry" ) @@ -89,9 +90,9 @@ func Restart(cr command.Runner) error { // Check checks on the status of the kubelet func Check(cr command.Runner) error { glog.Infof("checking for running kubelet ...") - c := exec.Command("sudo", "systemctl", "is-active", "--quiet", "service", "kubelet") - if _, err := cr.RunCmd(c); err != nil { - return errors.Wrap(err, "check kubelet") + active := sysinit.New(cr).Active("kubelet") + if !active { + return fmt.Errorf("inactive") } return nil } diff --git a/pkg/minikube/sysinit/systemd.go b/pkg/minikube/sysinit/systemd.go index be840c3e09ce..7f9143ebd421 100644 --- a/pkg/minikube/sysinit/systemd.go +++ b/pkg/minikube/sysinit/systemd.go @@ -74,6 +74,6 @@ func (s *Systemd) ForceStop(svc string) error { } func usesSystemd(r Runner) bool { - _, err := r.RunCmd(exec.Command("xsystemctl", "--version")) + _, err := r.RunCmd(exec.Command("systemctl", "--version")) return err == nil } From da725107a919045eb301a64bc7af011dfe5d080d Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 3 Apr 2020 19:43:18 -0700 Subject: [PATCH 05/19] Add date logging --- pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go index 4ee81697d8bb..998d8c9ba824 100644 --- a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go +++ b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go @@ -28,7 +28,9 @@ while [[ -x "${binary}" ]]; do if [[ -f "${conf}" ]]; then args=$(egrep "^ExecStart=${binary}" "${conf}" | cut -d" " -f2-) fi + echo "$(date) binary=${binary} args=${args}" ${binary} ${args} + echo "" sleep 1 done ` From 5cd7230d63a523da5270ec605be7e179b4cd63f3 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 3 Apr 2020 19:55:31 -0700 Subject: [PATCH 06/19] More diagnostics --- go.mod | 1 + pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go | 4 ++++ pkg/minikube/bootstrapper/kubeadm/kubeadm.go | 10 ++++++++++ pkg/minikube/sysinit/sysv.go | 10 +++++++++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2a00c7499246..977070770742 100644 --- a/go.mod +++ b/go.mod @@ -79,6 +79,7 @@ require ( golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 golang.org/x/text v0.3.2 google.golang.org/api v0.9.0 + google.golang.org/appengine v1.6.1 google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24 // indirect google.golang.org/grpc v1.26.0 // indirect gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect diff --git a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go index 998d8c9ba824..4aea5b7a06b5 100644 --- a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go +++ b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go @@ -52,6 +52,7 @@ fi function start() { cd /var/run nohup "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" & + disown echo $! > "${KUBELET_PIDFILE}" } @@ -67,15 +68,18 @@ function stop() { case "$1" in start) start + exit 0 ;; stop) stop + exit 0 ;; restart) stop start + exit 0 ;; status) diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index 7a7a111fd012..4535b3e5d6fe 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -619,6 +619,11 @@ func (k *Bootstrapper) UpdateCluster(cfg config.ClusterConfig) error { // UpdateNode updates a node. func (k *Bootstrapper) UpdateNode(cfg config.ClusterConfig, n config.Node, r cruntime.Manager) error { + now := time.Now() + defer func() { + glog.Infof("reloadKubelet took %s", time.Since(now)) + }() + kubeadmCfg, err := bsutil.GenerateKubeadmYAML(cfg, n, r) if err != nil { return errors.Wrap(err, "generating kubeadm cfg") @@ -697,6 +702,11 @@ func copyFiles(runner command.Runner, files []assets.CopyableFile) error { } func reloadKubelet(runner command.Runner, sm sysinit.Manager) error { + now := time.Now() + defer func() { + glog.Infof("reloadKubelet took %s", time.Since(now)) + }() + svc := bsutil.KubeletServiceFile conf := bsutil.KubeletSystemdConfFile diff --git a/pkg/minikube/sysinit/sysv.go b/pkg/minikube/sysinit/sysv.go index 4c0db2cdbc20..325c7daab8e1 100644 --- a/pkg/minikube/sysinit/sysv.go +++ b/pkg/minikube/sysinit/sysv.go @@ -18,7 +18,11 @@ limitations under the License. package sysinit import ( + "context" "os/exec" + "time" + + "github.com/golang/glog" ) const SysVName = "Sys-V" @@ -44,7 +48,11 @@ func (s *SysV) Start(svc string) error { if s.Active(svc) { return nil } - _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "start")) + ctx, cb := context.WithTimeout(context.Background(), 5*time.Second) + defer cb() + + rr, err := s.r.RunCmd(exec.CommandContext(ctx, "sudo", "service", svc, "start")) + glog.Infof("rr: %v", rr.Output()) return err } From 470a3e6aab02990d6255b8747300f81dfd328c6b Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 3 Apr 2020 20:02:36 -0700 Subject: [PATCH 07/19] Try setsid --- pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go index 4aea5b7a06b5..377c8f6dc128 100644 --- a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go +++ b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go @@ -51,9 +51,11 @@ fi function start() { cd /var/run - nohup "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" & - disown - echo $! > "${KUBELET_PIDFILE}" + pid=$(bash -c 'cd /; setsid nohup "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" /dev/null & jobs -p %1') + # nohup "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" & + # disown + echo "wrapper started at ${pid}" + echo $pid > "${KUBELET_PIDFILE}" } function stop() { From c082170b6770f4a544fe07fd74473c027e6656a3 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 3 Apr 2020 20:12:06 -0700 Subject: [PATCH 08/19] Use start-stop-daemon --- .../bootstrapper/bsutil/ktmpl/kubelet_sysv.go | 34 ++----------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go index 377c8f6dc128..b7739d9a9691 100644 --- a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go +++ b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go @@ -50,55 +50,27 @@ if [[ ! -x "${KUBELET}" ]]; then fi function start() { - cd /var/run - pid=$(bash -c 'cd /; setsid nohup "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" /dev/null & jobs -p %1') - # nohup "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" & - # disown - echo "wrapper started at ${pid}" - echo $pid > "${KUBELET_PIDFILE}" + start-stop-daemon --pid "${KUBELET_PIDFILE}" --background --start --make-pidfile --exec "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" } function stop() { - if [[ -f "${KUBELET_PIDFILE}" ]]; then - kill $(cat ${KUBELET_PIDFILE}) - fi - pkill "${KUBELET_WRAPPER}" - pkill kubelet + start-stop-daemon --pid "${KUBELET_PIDFILE}" --stop } case "$1" in start) start - exit 0 ;; - stop) stop - exit 0 ;; - restart) stop start - exit 0 ;; - status) - if [[ -f "${KUBELET_PIDFILE}" ]]; then - kill -0 $(cat ${KUBELET_PIDFILE}) - if [[ "$?" != 0 ]]; then - echo "${KUBELET_PIDFILE} is stale" - exit 1 - fi - else - echo "${KUBELET_PIDFILE} is missing" - exit 2 - fi - - echo "matching processes:" - pgrep -f kubelet - exit 0 + start-stop-daemon --pid "${KUBELET_PIDFILE}" --status ;; *) echo "Usage: service kubelet {start|stop|restart|status}" From 3d87a2da886f5304234c852110416fcc94b5c7a6 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 3 Apr 2020 20:15:23 -0700 Subject: [PATCH 09/19] oknodo --pidfile --- pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go index b7739d9a9691..fc55abeed009 100644 --- a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go +++ b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go @@ -50,11 +50,11 @@ if [[ ! -x "${KUBELET}" ]]; then fi function start() { - start-stop-daemon --pid "${KUBELET_PIDFILE}" --background --start --make-pidfile --exec "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" + start-stop-daemon --oknodo --pidfile "${KUBELET_PIDFILE}" --background --start --make-pidfile --exec "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" } function stop() { - start-stop-daemon --pid "${KUBELET_PIDFILE}" --stop + start-stop-daemon --oknodo --pidfile "${KUBELET_PIDFILE}" --stop } @@ -73,7 +73,7 @@ case "$1" in start-stop-daemon --pid "${KUBELET_PIDFILE}" --status ;; *) - echo "Usage: service kubelet {start|stop|restart|status}" + echo "Usage: service kubelet {start|stop|restart|status}" exit 1 ;; esac From 3f8d479577a56543020c861ab7e09b65f3032b84 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Tue, 7 Apr 2020 10:44:36 -0700 Subject: [PATCH 10/19] moment --- cmd/minikube/cmd/status.go | 12 +- pkg/minikube/bootstrapper/bootstrapper.go | 1 - .../bootstrapper/bsutil/kverify/kverify.go | 124 ------------------ .../bsutil/kverify/system_pods.go | 23 +--- pkg/minikube/bootstrapper/kubeadm/kubeadm.go | 5 - 5 files changed, 9 insertions(+), 156 deletions(-) diff --git a/cmd/minikube/cmd/status.go b/cmd/minikube/cmd/status.go index bd1a72524c59..2256b031a3c2 100644 --- a/cmd/minikube/cmd/status.go +++ b/cmd/minikube/cmd/status.go @@ -208,15 +208,9 @@ func status(api libmachine.API, cc config.ClusterConfig, n config.Node) (*Status return st, err } - stk, err := kverify.KubeletStatus(cr) - glog.Infof("%s kubelet status = %s (err=%v)", name, stk, err) - - if err != nil { - glog.Warningf("kubelet err: %v", err) - st.Kubelet = state.Error.String() - } else { - st.Kubelet = stk.String() - } + stk := kverify.KubeletStatus(cr) + glog.Infof("%s kubelet status = %s (err=%v)", name, stk) + st.Kubelet = stk.String() // Early exit for regular nodes if !controlPlane { diff --git a/pkg/minikube/bootstrapper/bootstrapper.go b/pkg/minikube/bootstrapper/bootstrapper.go index c724b2607fa3..0019b1750d5a 100644 --- a/pkg/minikube/bootstrapper/bootstrapper.go +++ b/pkg/minikube/bootstrapper/bootstrapper.go @@ -45,7 +45,6 @@ type Bootstrapper interface { // LogCommands returns a map of log type to a command which will display that log. LogCommands(config.ClusterConfig, LogOptions) map[string]string SetupCerts(config.KubernetesConfig, config.Node) error - GetKubeletStatus() (string, error) GetAPIServerStatus(string, int) (string, error) } diff --git a/pkg/minikube/bootstrapper/bsutil/kverify/kverify.go b/pkg/minikube/bootstrapper/bsutil/kverify/kverify.go index e128874ba42a..f4486196c349 100644 --- a/pkg/minikube/bootstrapper/bsutil/kverify/kverify.go +++ b/pkg/minikube/bootstrapper/bsutil/kverify/kverify.go @@ -19,22 +19,6 @@ package kverify import ( "time" - - "github.com/docker/machine/libmachine/state" - "github.com/golang/glog" - "github.com/pkg/errors" - core "k8s.io/api/core/v1" - meta "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/apimachinery/pkg/version" - "k8s.io/client-go/kubernetes" - kconst "k8s.io/kubernetes/cmd/kubeadm/app/constants" - "k8s.io/minikube/pkg/minikube/bootstrapper" - "k8s.io/minikube/pkg/minikube/command" - "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/cruntime" - "k8s.io/minikube/pkg/minikube/logs" - "k8s.io/minikube/pkg/minikube/sysinit" ) // minLogCheckTime how long to wait before spamming error logs to console @@ -80,114 +64,6 @@ func ShouldWait(wcs map[string]bool) bool { if wcs[c] { return true } - return true, nil - } - - if err := wait.PollImmediate(kconst.APICallRetryInterval, kconst.DefaultControlPlaneTimeout, vcheck); err != nil { - return fmt.Errorf("controlPlane never updated to %s", cfg.KubernetesConfig.KubernetesVersion) - } - - glog.Infof("duration metric: took %s to wait for apiserver health ...", time.Since(hStart)) - return nil -} - -// APIServerVersionMatch checks if the server version matches the expected -func APIServerVersionMatch(client *kubernetes.Clientset, expected string) error { - vi, err := client.ServerVersion() - if err != nil { - return errors.Wrap(err, "server version") - } - glog.Infof("control plane version: %s", vi) - if version.CompareKubeAwareVersionStrings(vi.String(), expected) != 0 { - return fmt.Errorf("controlPane = %q, expected: %q", vi.String(), expected) - } - return nil -} - -// announceProblems checks for problems, and slows polling down if any are found -func announceProblems(r cruntime.Manager, bs bootstrapper.Bootstrapper, cfg config.ClusterConfig, cr command.Runner) { - problems := logs.FindProblems(r, bs, cfg, cr) - if len(problems) > 0 { - logs.OutputProblems(problems, 5) - time.Sleep(kconst.APICallRetryInterval * 15) - } -} - -// APIServerStatus returns apiserver status in libmachine style state.State -func APIServerStatus(cr command.Runner, hostname string, port int) (state.State, error) { - glog.Infof("Checking apiserver status ...") - - pid, err := apiServerPID(cr) - if err != nil { - glog.Warningf("stopped: unable to get apiserver pid: %v", err) - return state.Stopped, nil - } - - // Get the freezer cgroup entry for this pid - rr, err := cr.RunCmd(exec.Command("sudo", "egrep", "^[0-9]+:freezer:", fmt.Sprintf("/proc/%d/cgroup", pid))) - if err != nil { - glog.Warningf("unable to find freezer cgroup: %v", err) - return apiServerHealthz(hostname, port) - - } - freezer := strings.TrimSpace(rr.Stdout.String()) - glog.Infof("apiserver freezer: %q", freezer) - fparts := strings.Split(freezer, ":") - if len(fparts) != 3 { - glog.Warningf("unable to parse freezer - found %d parts: %s", len(fparts), freezer) - return apiServerHealthz(hostname, port) - } - - rr, err = cr.RunCmd(exec.Command("sudo", "cat", path.Join("/sys/fs/cgroup/freezer", fparts[2], "freezer.state"))) - if err != nil { - glog.Errorf("unable to get freezer state: %s", rr.Stderr.String()) - return apiServerHealthz(hostname, port) - } - - fs := strings.TrimSpace(rr.Stdout.String()) - glog.Infof("freezer state: %q", fs) - if fs == "FREEZING" || fs == "FROZEN" { - return state.Paused, nil - } - return apiServerHealthz(hostname, port) -} - -// apiServerHealthz hits the /healthz endpoint and returns libmachine style state.State -func apiServerHealthz(hostname string, port int) (state.State, error) { - url := fmt.Sprintf("https://%s/healthz", net.JoinHostPort(hostname, fmt.Sprint(port))) - glog.Infof("Checking apiserver healthz at %s ...", url) - // To avoid: x509: certificate signed by unknown authority - tr := &http.Transport{ - Proxy: nil, // To avoid connectiv issue if http(s)_proxy is set. - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client := &http.Client{Transport: tr} - resp, err := client.Get(url) - // Connection refused, usually. - if err != nil { - glog.Infof("stopped: %s: %v", url, err) - return state.Stopped, nil - } - if resp.StatusCode == http.StatusUnauthorized { - glog.Errorf("%s returned code %d (unauthorized). Please ensure that your apiserver authorization settings make sense!", url, resp.StatusCode) - return state.Error, nil - } - if resp.StatusCode != http.StatusOK { - glog.Warningf("%s response: %v %+v", url, err, resp) - return state.Error, nil - } - return state.Running, nil -} - -// KubeletStatus checks the kubelet status -func KubeletStatus(cr command.Runner) (state.State, error) { - glog.Infof("Checking kubelet status ...") - - active := sysinit.New(cr).Active("kubelet") - if active { - return state.Running, nil - } - return state.Stopped, nil } return false } diff --git a/pkg/minikube/bootstrapper/bsutil/kverify/system_pods.go b/pkg/minikube/bootstrapper/bsutil/kverify/system_pods.go index f6e9a5f98f7a..ba436e1a2ff6 100644 --- a/pkg/minikube/bootstrapper/bsutil/kverify/system_pods.go +++ b/pkg/minikube/bootstrapper/bsutil/kverify/system_pods.go @@ -19,7 +19,6 @@ package kverify import ( "fmt" - "os/exec" "strings" "time" @@ -36,6 +35,7 @@ import ( "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/logs" + "k8s.io/minikube/pkg/minikube/sysinit" "k8s.io/minikube/pkg/util/retry" ) @@ -151,22 +151,11 @@ func announceProblems(r cruntime.Manager, bs bootstrapper.Bootstrapper, cfg conf } // KubeletStatus checks the kubelet status -func KubeletStatus(cr command.Runner) (state.State, error) { +func KubeletStatus(cr command.Runner) state.State { glog.Infof("Checking kubelet status ...") - rr, err := cr.RunCmd(exec.Command("sudo", "systemctl", "is-active", "kubelet")) - if err != nil { - // Do not return now, as we still have parsing to do! - glog.Warningf("%s returned error: %v", rr.Command(), err) - } - s := strings.TrimSpace(rr.Stdout.String()) - glog.Infof("kubelet is-active: %s", s) - switch s { - case "active": - return state.Running, nil - case "inactive": - return state.Stopped, nil - case "activating": - return state.Starting, nil + active := sysinit.New(cr).Active("kubelet") + if active { + return state.Running } - return state.Error, nil + return state.Stopped } diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index 48a378f59bdf..6d1b7ff8c507 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -83,11 +83,6 @@ func NewBootstrapper(api libmachine.API, cc config.ClusterConfig, n config.Node) return &Bootstrapper{c: runner, contextName: cc.Name, k8sClient: nil}, nil } -// GetKubeletStatus returns the kubelet status -func (k *Bootstrapper) GetKubeletStatus() (string, error) { - st, err := kverify.KubeletStatus(k.c) - return st.String(), err -} // GetAPIServerStatus returns the api-server status func (k *Bootstrapper) GetAPIServerStatus(hostname string, port int) (string, error) { From 043b6107c01b258dc275a16b34725a2df961706a Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 8 Apr 2020 11:34:58 -0700 Subject: [PATCH 11/19] Changes --- .../bootstrapper/bsutil/ktmpl/kubelet_sysv.go | 80 ------------------- pkg/minikube/bootstrapper/kubeadm/kubeadm.go | 3 +- pkg/minikube/sysinit/sysinit.go | 12 ++- pkg/minikube/sysinit/sysv.go | 75 ----------------- 4 files changed, 6 insertions(+), 164 deletions(-) delete mode 100644 pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go delete mode 100644 pkg/minikube/sysinit/sysv.go diff --git a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go b/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go deleted file mode 100644 index fc55abeed009..000000000000 --- a/pkg/minikube/bootstrapper/bsutil/ktmpl/kubelet_sysv.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ktmpl - -import "text/template" - -var RestartWrapper = `#!/bin/bash -# Wrapper script to emulate systemd restart on non-systemd systems -binary=$1 -conf=$2 -args="" - -while [[ -x "${binary}" ]]; do - if [[ -f "${conf}" ]]; then - args=$(egrep "^ExecStart=${binary}" "${conf}" | cut -d" " -f2-) - fi - echo "$(date) binary=${binary} args=${args}" - ${binary} ${args} - echo "" - sleep 1 -done -` - -var KubeletInitTemplate = template.Must(template.New("kubeletSysVTemplate").Parse(`#!/bin/bash -# SysV style init script for kubelet - -readonly KUBELET="{{.KubeletPath}}" -readonly KUBELET_WRAPPER="{{.WrapperPath}}" -readonly KUBELET_CONF="{{.ConfPath}}" -readonly KUBELET_PIDFILE="/var/run/kubelet.pid" -readonly KUBELET_LOGFILE="/var/run/nohup.out" - -if [[ ! -x "${KUBELET}" ]]; then - echo "$KUBELET not present or not executable" - exit 1 -fi - -function start() { - start-stop-daemon --oknodo --pidfile "${KUBELET_PIDFILE}" --background --start --make-pidfile --exec "${KUBELET_WRAPPER}" "${KUBELET}" "${KUBELET_CONF}" -} - -function stop() { - start-stop-daemon --oknodo --pidfile "${KUBELET_PIDFILE}" --stop -} - - -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart) - stop - start - ;; - status) - start-stop-daemon --pid "${KUBELET_PIDFILE}" --status - ;; - *) - echo "Usage: service kubelet {start|stop|restart|status}" - exit 1 - ;; -esac -`)) diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index 6d1b7ff8c507..7f5cb9d3b5cb 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -83,7 +83,6 @@ func NewBootstrapper(api libmachine.API, cc config.ClusterConfig, n config.Node) return &Bootstrapper{c: runner, contextName: cc.Name, k8sClient: nil}, nil } - // GetAPIServerStatus returns the api-server status func (k *Bootstrapper) GetAPIServerStatus(hostname string, port int) (string, error) { s, err := kverify.APIServerStatus(k.c, hostname, port) @@ -688,7 +687,7 @@ func (k *Bootstrapper) UpdateNode(cfg config.ClusterConfig, n config.Node, r cru } glog.Infof("sysinit says: %v", sm.Name()) - // Install SysV-like init scripts if necessary + // Install OpenRC-like init scripts if necessary if sm.Name() == sysinit.SysVName { initScript, err := bsutil.NewInitScript(cfg.KubernetesConfig.KubernetesVersion, bsutil.InitRestartWrapper) if err != nil { diff --git a/pkg/minikube/sysinit/sysinit.go b/pkg/minikube/sysinit/sysinit.go index f39347d51719..9a4d3fb515c3 100644 --- a/pkg/minikube/sysinit/sysinit.go +++ b/pkg/minikube/sysinit/sysinit.go @@ -2,9 +2,7 @@ package sysinit import ( "os/exec" - "runtime" - "github.com/golang/glog" "k8s.io/minikube/pkg/minikube/command" ) @@ -38,18 +36,18 @@ type Manager interface { // New returns an appropriately configured service manager func New(r Runner) Manager { - _, file, no, _ := runtime.Caller(1) - + // If we are not provided a runner, we can't do anything anyways if r == nil { - glog.Warningf("manager from %s:%d: nil runner! (systemd)", file, no) return nil } var systemd bool + + // Caching the result is important, as this manager may be created in many places, + // and ssh calls are expensive on some drivers, such as Docker. if cachedSystemdCheck != nil { systemd = *cachedSystemdCheck } else { - glog.Errorf("uncached systemd check from %s:%d", file, no) systemd = usesSystemd(r) cachedSystemdCheck = &systemd } @@ -57,5 +55,5 @@ func New(r Runner) Manager { if systemd { return &Systemd{r: r} } - return &SysV{r: r} + return &OpenRC{r: r} } diff --git a/pkg/minikube/sysinit/sysv.go b/pkg/minikube/sysinit/sysv.go deleted file mode 100644 index 325c7daab8e1..000000000000 --- a/pkg/minikube/sysinit/sysv.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// sysinit provides an abstraction over init systems like systemctl -package sysinit - -import ( - "context" - "os/exec" - "time" - - "github.com/golang/glog" -) - -const SysVName = "Sys-V" - -// SysV is a service manager for SysV-like init systems -type SysV struct { - r Runner -} - -// Name returns the name of the init system -func (s *SysV) Name() string { - return SysVName -} - -// Active checks if a service is running -func (s *SysV) Active(svc string) bool { - _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "status")) - return err == nil -} - -// Start starts a service idempotently -func (s *SysV) Start(svc string) error { - if s.Active(svc) { - return nil - } - ctx, cb := context.WithTimeout(context.Background(), 5*time.Second) - defer cb() - - rr, err := s.r.RunCmd(exec.CommandContext(ctx, "sudo", "service", svc, "start")) - glog.Infof("rr: %v", rr.Output()) - return err -} - -// Restart restarts a service -func (s *SysV) Restart(svc string) error { - _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "restart")) - return err -} - -// Stop stops a service -func (s *SysV) Stop(svc string) error { - _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "stop")) - return err -} - -// ForceStop stops a service with prejuidice -func (s *SysV) ForceStop(svc string) error { - _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "stop", "-f")) - return err -} From e4aa29ed8289e6e882345c7b1ccb163ff6d30397 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 8 Apr 2020 11:36:56 -0700 Subject: [PATCH 12/19] Rename --- pkg/minikube/sysinit/openrc.go | 158 +++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 pkg/minikube/sysinit/openrc.go diff --git a/pkg/minikube/sysinit/openrc.go b/pkg/minikube/sysinit/openrc.go new file mode 100644 index 000000000000..080ef522b7b4 --- /dev/null +++ b/pkg/minikube/sysinit/openrc.go @@ -0,0 +1,158 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// sysinit provides an abstraction over init systems like systemctl +package sysinit + +import ( + "context" + "os/exec" + "time" + + "github.com/golang/glog" +) + +const SysVName = "OpenRC" + + +/* +Copyright 2020 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ktmpl + +import "text/template" + +var RestartWrapper = `#!/bin/bash +# Wrapper script to emulate systemd restart on non-systemd systems +binary=$1 +conf=$2 +args="" + +while [[ -x "${binary}" ]]; do + if [[ -f "${conf}" ]]; then + args=$(egrep "^ExecStart=${binary}" "${conf}" | cut -d" " -f2-) + fi + echo "$(date) binary=${binary} args=${args}" + ${binary} ${args} + echo "" + sleep 1 +done +` + +var InitScript = template.Must(template.New("initScript").Parse(`#!/bin/bash +# OpenRC init script for systemd units + +readonly BINARY="{{.BinaryPath}}" +readonly NAME="$(basename ${BINARY})" + +readonly RESTART_WRAPPER="{{.WrapperPath}}" +readonly UNIT_PATH="{{.UnitPath}}" +readonly PID_PATH="/var/run/${NAME}.pid" + +if [[ ! -x "${BINARY}" ]]; then + echo "$BINARY not present or not executable" + exit 1 +fi + +function start() { + start-stop-daemon --oknodo --PID_PATH "${PID_PATH}" --background --start --make-PID_PATH --exec "${WRAPPER}" "${BINARY}" "${UNIT_PATH}" +} + +function stop() { + start-stop-daemon --oknodo --PID_PATH "${PID_PATH}" --stop +} + + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + status) + start-stop-daemon --pid "${PID_PATH}" --status + ;; + *) + echo "Usage: service BINARY {start|stop|restart|status}" + exit 1 + ;; +esac +`)) + +// OpenRC is a service manager for OpenRC-like init systems +type OpenRC struct { + r Runner +} + +// Name returns the name of the init system +func (s *OpenRC) Name() string { + return SysVName +} + +// Active checks if a service is running +func (s *OpenRC) Active(svc string) bool { + _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "status")) + return err == nil +} + +// Start starts a service idempotently +func (s *OpenRC) Start(svc string) error { + if s.Active(svc) { + return nil + } + ctx, cb := context.WithTimeout(context.Background(), 5*time.Second) + defer cb() + + rr, err := s.r.RunCmd(exec.CommandContext(ctx, "sudo", "service", svc, "start")) + glog.Infof("rr: %v", rr.Output()) + return err +} + +// Restart restarts a service +func (s *OpenRC) Restart(svc string) error { + _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "restart")) + return err +} + +// Stop stops a service +func (s *OpenRC) Stop(svc string) error { + _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "stop")) + return err +} + +// ForceStop stops a service with prejuidice +func (s *OpenRC) ForceStop(svc string) error { + _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "stop", "-f")) + return err +} From 734d5c835536ac65e996894088587e674aa12a2e Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 8 Apr 2020 14:01:08 -0700 Subject: [PATCH 13/19] sysv->openrc --- pkg/minikube/bootstrapper/bsutil/kubelet.go | 18 ---- pkg/minikube/bootstrapper/kubeadm/kubeadm.go | 25 +++--- pkg/minikube/sysinit/openrc.go | 87 ++++++++++---------- pkg/minikube/sysinit/sysinit.go | 4 + pkg/minikube/sysinit/systemd.go | 7 ++ 5 files changed, 65 insertions(+), 76 deletions(-) diff --git a/pkg/minikube/bootstrapper/bsutil/kubelet.go b/pkg/minikube/bootstrapper/bsutil/kubelet.go index a25cc074c3a2..1ed22d17c6b9 100644 --- a/pkg/minikube/bootstrapper/bsutil/kubelet.go +++ b/pkg/minikube/bootstrapper/bsutil/kubelet.go @@ -119,24 +119,6 @@ func NewKubeletService(cfg config.KubernetesConfig) ([]byte, error) { return b.Bytes(), nil } -// NewInitScript returns a generated systemd unit file for the kubelet -func NewInitScript(v string, wrapperPath string) ([]byte, error) { - var b bytes.Buffer - opts := struct { - KubeletPath string - WrapperPath string - ConfPath string - }{ - KubeletPath: path.Join(binRoot(v), "kubelet"), - WrapperPath: wrapperPath, - ConfPath: KubeletSystemdConfFile, - } - if err := ktmpl.KubeletInitTemplate.Execute(&b, opts); err != nil { - return nil, errors.Wrap(err, "template execute") - } - return b.Bytes(), nil -} - // KubeNodeName returns the node name registered in Kubernetes func KubeNodeName(cc config.ClusterConfig, n config.Node) string { if cc.Driver == driver.None { diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index 7f5cb9d3b5cb..af60f138e768 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -43,7 +43,6 @@ import ( "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/bootstrapper/bsutil" - "k8s.io/minikube/pkg/minikube/bootstrapper/bsutil/ktmpl" "k8s.io/minikube/pkg/minikube/bootstrapper/bsutil/kverify" "k8s.io/minikube/pkg/minikube/bootstrapper/images" "k8s.io/minikube/pkg/minikube/command" @@ -686,24 +685,20 @@ func (k *Bootstrapper) UpdateNode(cfg config.ClusterConfig, n config.Node, r cru files = append(files, assets.NewMemoryAssetTarget([]byte(defaultCNIConfig), bsutil.DefaultCNIConfigPath, "0644")) } - glog.Infof("sysinit says: %v", sm.Name()) - // Install OpenRC-like init scripts if necessary - if sm.Name() == sysinit.SysVName { - initScript, err := bsutil.NewInitScript(cfg.KubernetesConfig.KubernetesVersion, bsutil.InitRestartWrapper) - if err != nil { - return errors.Wrap(err, "init script") - } - - files = append(files, assets.NewMemoryAssetTarget([]byte(ktmpl.RestartWrapper), bsutil.InitRestartWrapper, "0755")) - files = append(files, assets.NewMemoryAssetTarget(initScript, bsutil.KubeletInitPath, "0755")) + // Installs compatibility shims for non-systemd environments + kubeletPath := path.Join(vmpath.GuestPersistentDir, "binaries", cfg.KubernetesConfig.KubernetesVersion, "kubectl") + shims, err := sm.GenerateInitShim("kubelet", kubeletPath, bsutil.KubeletSystemdConfFile) + if err != nil { + return errors.Wrap(err, "shim") } + files = append(files, shims...) if err := copyFiles(k.c, files); err != nil { - return err + return errors.Wrap(err, "copy") } - if err := reloadKubelet(k.c, sm); err != nil { - return err + if err := startKubeletIfRequired(k.c, sm); err != nil { + return errors.Wrap(err, "reload") } return nil @@ -728,7 +723,7 @@ func copyFiles(runner command.Runner, files []assets.CopyableFile) error { return nil } -func reloadKubelet(runner command.Runner, sm sysinit.Manager) error { +func startKubeletIfRequired(runner command.Runner, sm sysinit.Manager) error { now := time.Now() defer func() { glog.Infof("reloadKubelet took %s", time.Since(now)) diff --git a/pkg/minikube/sysinit/openrc.go b/pkg/minikube/sysinit/openrc.go index 080ef522b7b4..39e084dfd1ba 100644 --- a/pkg/minikube/sysinit/openrc.go +++ b/pkg/minikube/sysinit/openrc.go @@ -18,68 +18,41 @@ limitations under the License. package sysinit import ( + "bytes" "context" + "html/template" "os/exec" + "path" "time" "github.com/golang/glog" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/assets" + "k8s.io/minikube/pkg/minikube/vmpath" ) const SysVName = "OpenRC" - -/* -Copyright 2020 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ktmpl - -import "text/template" - -var RestartWrapper = `#!/bin/bash +var restartWrapper = `#!/bin/bash # Wrapper script to emulate systemd restart on non-systemd systems -binary=$1 -conf=$2 +unit=$1 args="" -while [[ -x "${binary}" ]]; do +while true; do if [[ -f "${conf}" ]]; then - args=$(egrep "^ExecStart=${binary}" "${conf}" | cut -d" " -f2-) + eval $(egrep "^ExecStart=" "${conf}" | cut -d"=" -f2-) fi - echo "$(date) binary=${binary} args=${args}" - ${binary} ${args} - echo "" sleep 1 done ` -var InitScript = template.Must(template.New("initScript").Parse(`#!/bin/bash -# OpenRC init script for systemd units - -readonly BINARY="{{.BinaryPath}}" -readonly NAME="$(basename ${BINARY})" - -readonly RESTART_WRAPPER="{{.WrapperPath}}" -readonly UNIT_PATH="{{.UnitPath}}" +var initScriptTmpl = template.Must(template.New("initScript").Parse(`#!/bin/bash +# OpenRC init script shim for systemd units +readonly NAME="{{.Name}}" +readonly RESTART_WRAPPER="{{.Wrapper}}" +readonly UNIT_PATH="{{.Unit}}" readonly PID_PATH="/var/run/${NAME}.pid" -if [[ ! -x "${BINARY}" ]]; then - echo "$BINARY not present or not executable" - exit 1 -fi - function start() { start-stop-daemon --oknodo --PID_PATH "${PID_PATH}" --background --start --make-PID_PATH --exec "${WRAPPER}" "${BINARY}" "${UNIT_PATH}" } @@ -88,7 +61,6 @@ function stop() { start-stop-daemon --oknodo --PID_PATH "${PID_PATH}" --stop } - case "$1" in start) start @@ -156,3 +128,32 @@ func (s *OpenRC) ForceStop(svc string) error { _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "stop", "-f")) return err } + +// GenerateInitShim generates any additional init files required for this service +func (s *OpenRC) GenerateInitShim(svc string, binary string, unit string) ([]assets.CopyableFile, error) { + restartWrapperPath := path.Join(vmpath.GuestPersistentDir, "openrc-restart-wrapper.sh") + + opts := struct { + Binary string + Wrapper string + Name string + Unit string + }{ + Name: svc, + Binary: binary, + Wrapper: restartWrapperPath, + Unit: unit, + } + + var b bytes.Buffer + if err := initScriptTmpl.Execute(&b, opts); err != nil { + return nil, errors.Wrap(err, "template execute") + } + + files := []assets.CopyableFile{ + assets.NewMemoryAssetTarget([]byte(restartWrapper), restartWrapperPath, "0755"), + assets.NewMemoryAssetTarget(b.Bytes(), path.Join("/etc/init.d/", svc), "0755"), + } + + return files, nil +} diff --git a/pkg/minikube/sysinit/sysinit.go b/pkg/minikube/sysinit/sysinit.go index 9a4d3fb515c3..7bb19f656d47 100644 --- a/pkg/minikube/sysinit/sysinit.go +++ b/pkg/minikube/sysinit/sysinit.go @@ -3,6 +3,7 @@ package sysinit import ( "os/exec" + "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/command" ) @@ -32,6 +33,9 @@ type Manager interface { // ForceStop stops a service with prejudice ForceStop(string) error + + // GenerateInitShim generates any additional init files required for this service + GenerateInitShim(svc string, binary string, unit string) ([]assets.CopyableFile, error) } // New returns an appropriately configured service manager diff --git a/pkg/minikube/sysinit/systemd.go b/pkg/minikube/sysinit/systemd.go index 7f9143ebd421..71065b9b09c3 100644 --- a/pkg/minikube/sysinit/systemd.go +++ b/pkg/minikube/sysinit/systemd.go @@ -19,6 +19,8 @@ package sysinit import ( "os/exec" + + "k8s.io/minikube/pkg/minikube/assets" ) // Systemd is a service manager for systemd distributions @@ -73,6 +75,11 @@ func (s *Systemd) ForceStop(svc string) error { return err } +// GenerateInitShim does nothing for systemd +func (s *Systemd) GenerateInitShim(svc string, binary string, unit string) ([]assets.CopyableFile, error) { + return nil, nil +} + func usesSystemd(r Runner) bool { _, err := r.RunCmd(exec.Command("systemctl", "--version")) return err == nil From 8ab5cb3e0b4dd209ad2afa944a3a32c3f4c63f50 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 8 Apr 2020 15:36:37 -0700 Subject: [PATCH 14/19] No error from kubelet status --- pkg/drivers/none/none.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/drivers/none/none.go b/pkg/drivers/none/none.go index 91ab30546463..e877b15220e1 100644 --- a/pkg/drivers/none/none.go +++ b/pkg/drivers/none/none.go @@ -142,7 +142,7 @@ func (d *Driver) GetState() (state.State, error) { return state.Running, nil } - return kverify.KubeletStatus(d.exec) + return kverify.KubeletStatus(d.exec), nil } // Kill stops a host forcefully, including any containers that we are managing. From ae59f00b1819dd8ac091abce6223c4d1cf4b0de2 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 8 Apr 2020 16:37:03 -0700 Subject: [PATCH 15/19] Init script fixes --- pkg/minikube/sysinit/openrc.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pkg/minikube/sysinit/openrc.go b/pkg/minikube/sysinit/openrc.go index 39e084dfd1ba..a9e38160e1ad 100644 --- a/pkg/minikube/sysinit/openrc.go +++ b/pkg/minikube/sysinit/openrc.go @@ -35,12 +35,11 @@ const SysVName = "OpenRC" var restartWrapper = `#!/bin/bash # Wrapper script to emulate systemd restart on non-systemd systems -unit=$1 -args="" +readonly UNIT_PATH=$1 while true; do - if [[ -f "${conf}" ]]; then - eval $(egrep "^ExecStart=" "${conf}" | cut -d"=" -f2-) + if [[ -f "${UNIT_PATH}" ]]; then + eval $(egrep "^ExecStart=" "${UNIT_PATH}" | cut -d"=" -f2-) fi sleep 1 done @@ -54,11 +53,11 @@ readonly UNIT_PATH="{{.Unit}}" readonly PID_PATH="/var/run/${NAME}.pid" function start() { - start-stop-daemon --oknodo --PID_PATH "${PID_PATH}" --background --start --make-PID_PATH --exec "${WRAPPER}" "${BINARY}" "${UNIT_PATH}" + start-stop-daemon --oknodo --pidfile "${PID_PATH}" --background --start --make-pid --exec "${RESTART_WRAPPER}" "${UNIT_PATH}" } function stop() { - start-stop-daemon --oknodo --PID_PATH "${PID_PATH}" --stop + start-stop-daemon --oknodo --pidfile "${PID_PATH}" --stop } case "$1" in @@ -73,10 +72,10 @@ case "$1" in start ;; status) - start-stop-daemon --pid "${PID_PATH}" --status + start-stop-daemon --pidfile "${PID_PATH}" --status ;; *) - echo "Usage: service BINARY {start|stop|restart|status}" + echo "Usage: {{.Name}} {start|stop|restart|status}" exit 1 ;; esac From a8802292274f594623c47ebf6258f41b9889f2d8 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 8 Apr 2020 17:46:10 -0700 Subject: [PATCH 16/19] Implement Disable/Enable, replace kubelet pkg --- cmd/minikube/cmd/status.go | 2 +- go.mod | 1 - pkg/drivers/kic/kic.go | 8 +- pkg/drivers/none/none.go | 8 +- pkg/minikube/bootstrapper/kubeadm/kubeadm.go | 3 +- pkg/minikube/cluster/pause.go | 19 ++- pkg/minikube/cruntime/cruntime_test.go | 26 ++-- pkg/minikube/cruntime/docker.go | 2 +- pkg/minikube/kubelet/kubelet.go | 118 ------------------- pkg/minikube/node/start.go | 6 +- pkg/minikube/sysinit/openrc.go | 10 ++ pkg/minikube/sysinit/sysinit.go | 22 ++++ pkg/minikube/sysinit/systemd.go | 12 ++ 13 files changed, 91 insertions(+), 146 deletions(-) delete mode 100644 pkg/minikube/kubelet/kubelet.go diff --git a/cmd/minikube/cmd/status.go b/cmd/minikube/cmd/status.go index 2256b031a3c2..e5b8d7cdba88 100644 --- a/cmd/minikube/cmd/status.go +++ b/cmd/minikube/cmd/status.go @@ -209,7 +209,7 @@ func status(api libmachine.API, cc config.ClusterConfig, n config.Node) (*Status } stk := kverify.KubeletStatus(cr) - glog.Infof("%s kubelet status = %s (err=%v)", name, stk) + glog.Infof("%s kubelet status = %s", name, stk) st.Kubelet = stk.String() // Early exit for regular nodes diff --git a/go.mod b/go.mod index 977070770742..2a00c7499246 100644 --- a/go.mod +++ b/go.mod @@ -79,7 +79,6 @@ require ( golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 golang.org/x/text v0.3.2 google.golang.org/api v0.9.0 - google.golang.org/appengine v1.6.1 google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24 // indirect google.golang.org/grpc v1.26.0 // indirect gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect diff --git a/pkg/drivers/kic/kic.go b/pkg/drivers/kic/kic.go index 692bcdf485c0..7a342afcbc92 100644 --- a/pkg/drivers/kic/kic.go +++ b/pkg/drivers/kic/kic.go @@ -37,7 +37,7 @@ import ( "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/download" - "k8s.io/minikube/pkg/minikube/kubelet" + "k8s.io/minikube/pkg/minikube/sysinit" ) // Driver represents a kic driver https://minikube.sigs.k8s.io/docs/reference/drivers/docker @@ -245,7 +245,7 @@ func (d *Driver) GetState() (state.State, error) { func (d *Driver) Kill() error { // on init this doesn't get filled when called from cmd d.exec = command.NewKICRunner(d.MachineName, d.OCIBinary) - if err := kubelet.ForceStop(d.exec); err != nil { + if err := sysinit.New(d.exec).ForceStop("kubelet"); err != nil { glog.Warningf("couldn't force stop kubelet. will continue with kill anyways: %v", err) } cmd := exec.Command(d.NodeConfig.OCIBinary, "kill", d.MachineName) @@ -318,9 +318,9 @@ func (d *Driver) Stop() error { d.exec = command.NewKICRunner(d.MachineName, d.OCIBinary) // docker does not send right SIG for systemd to know to stop the systemd. // to avoid bind address be taken on an upgrade. more info https://github.com/kubernetes/minikube/issues/7171 - if err := kubelet.Stop(d.exec); err != nil { + if err := sysinit.New(d.exec).Stop("kubelet"); err != nil { glog.Warningf("couldn't stop kubelet. will continue with stop anyways: %v", err) - if err := kubelet.ForceStop(d.exec); err != nil { + if err := sysinit.New(d.exec).ForceStop("kubelet"); err != nil { glog.Warningf("couldn't force stop kubelet. will continue with stop anyways: %v", err) } } diff --git a/pkg/drivers/none/none.go b/pkg/drivers/none/none.go index e877b15220e1..1049f713fe38 100644 --- a/pkg/drivers/none/none.go +++ b/pkg/drivers/none/none.go @@ -31,7 +31,7 @@ import ( "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/kubeconfig" - "k8s.io/minikube/pkg/minikube/kubelet" + "k8s.io/minikube/pkg/minikube/sysinit" "k8s.io/minikube/pkg/minikube/vmpath" ) @@ -147,7 +147,7 @@ func (d *Driver) GetState() (state.State, error) { // Kill stops a host forcefully, including any containers that we are managing. func (d *Driver) Kill() error { - if err := kubelet.ForceStop(d.exec); err != nil { + if err := sysinit.New(d.exec).ForceStop("kubelet"); err != nil { glog.Warningf("couldn't force stop kubelet. will continue with kill anyways: %v", err) } @@ -211,9 +211,9 @@ func (d *Driver) Start() error { // Stop a host gracefully, including any containers that we are managing. func (d *Driver) Stop() error { - if err := kubelet.Stop(d.exec); err != nil { + if err := sysinit.New(d.exec).Stop("kubelet"); err != nil { glog.Warningf("couldn't stop kubelet. will continue with stop anyways: %v", err) - if err := kubelet.ForceStop(d.exec); err != nil { + if err := sysinit.New(d.exec).ForceStop("kubelet"); err != nil { glog.Warningf("couldn't force stop kubelet. will continue with stop anyways: %v", err) } } diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index af60f138e768..448e12e38151 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -50,7 +50,6 @@ import ( "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/driver" - "k8s.io/minikube/pkg/minikube/kubelet" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/sysinit" @@ -581,7 +580,7 @@ func (k *Bootstrapper) DeleteCluster(k8s config.KubernetesConfig) error { glog.Warningf("%s: %v", rr.Command(), err) } - if err := kubelet.ForceStop(k.c); err != nil { + if err := sysinit.New(k.c).ForceStop("kubelet"); err != nil { glog.Warningf("stop kubelet: %v", err) } diff --git a/pkg/minikube/cluster/pause.go b/pkg/minikube/cluster/pause.go index d7661f1274c3..09b1a10c2449 100644 --- a/pkg/minikube/cluster/pause.go +++ b/pkg/minikube/cluster/pause.go @@ -21,27 +21,33 @@ import ( "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/cruntime" - "k8s.io/minikube/pkg/minikube/kubelet" + "k8s.io/minikube/pkg/minikube/sysinit" ) // Pause pauses a Kubernetes cluster func Pause(cr cruntime.Manager, r command.Runner, namespaces []string) ([]string, error) { ids := []string{} + // Disable the kubelet so it does not attempt to restart paused pods - if err := kubelet.Disable(r); err != nil { + sm := sysinit.New(r) + if err := sm.Disable("kubelet"); err != nil { return ids, errors.Wrap(err, "kubelet disable") } - if err := kubelet.Stop(r); err != nil { + + if err := sm.Stop("kubelet"); err != nil { return ids, errors.Wrap(err, "kubelet stop") } + ids, err := cr.ListContainers(cruntime.ListOptions{State: cruntime.Running, Namespaces: namespaces}) if err != nil { return ids, errors.Wrap(err, "list running") } + if len(ids) == 0 { glog.Warningf("no running containers to pause") return ids, nil } + return ids, cr.PauseContainers(ids) } @@ -59,11 +65,14 @@ func Unpause(cr cruntime.Manager, r command.Runner, namespaces []string) ([]stri return ids, errors.Wrap(err, "unpause") } - if err := kubelet.Enable(r); err != nil { + sm := sysinit.New(r) + if err := sm.Enable("kubelet"); err != nil { return ids, errors.Wrap(err, "kubelet enable") } - if err := kubelet.Start(r); err != nil { + + if err := sm.Start("kubelet"); err != nil { return ids, errors.Wrap(err, "kubelet start") } + return ids, nil } diff --git a/pkg/minikube/cruntime/cruntime_test.go b/pkg/minikube/cruntime/cruntime_test.go index 9523f1126a14..aef420cf8496 100644 --- a/pkg/minikube/cruntime/cruntime_test.go +++ b/pkg/minikube/cruntime/cruntime_test.go @@ -23,6 +23,7 @@ import ( "strings" "testing" + "github.com/golang/glog" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/pkg/errors" @@ -406,12 +407,27 @@ func (f *FakeRunner) crictl(args []string, _ bool) (string, error) { // systemctl is a fake implementation of systemctl func (f *FakeRunner) systemctl(args []string, root bool) (string, error) { // nolint result 0 (string) is always "" + glog.Infof("fake systemctl: %v", args) action := args[0] - svcs := args[1:] + + if action == "--version" { + return "systemd 123 (321.2-1)", nil + } + + if action == "daemon-reload" { + return "ok", nil + } + + var svcs []string + if len(args) > 0 { + svcs = args[1:] + } + // force if svcs[0] == "-f" { svcs = svcs[1:] } + out := "" for i, arg := range args { @@ -496,7 +512,6 @@ func TestVersion(t *testing.T) { // defaultServices reflects the default boot state for the minikube VM var defaultServices = map[string]serviceState{ "docker": SvcRunning, - "docker.socket": SvcRunning, "crio": SvcExited, "crio-shutdown": SvcExited, "containerd": SvcExited, @@ -507,7 +522,7 @@ func TestDisable(t *testing.T) { runtime string want []string }{ - {"docker", []string{"sudo", "systemctl", "stop", "-f", "docker", "docker.socket"}}, + {"docker", []string{"sudo", "systemctl", "stop", "-f", "docker"}}, {"crio", []string{"sudo", "systemctl", "stop", "-f", "crio"}}, {"containerd", []string{"sudo", "systemctl", "stop", "-f", "containerd"}}, } @@ -539,23 +554,20 @@ func TestEnable(t *testing.T) { }{ {"docker", map[string]serviceState{ "docker": SvcRunning, - "docker.socket": SvcRunning, "containerd": SvcExited, "crio": SvcExited, "crio-shutdown": SvcExited, }}, {"containerd", map[string]serviceState{ "docker": SvcExited, - "docker.socket": SvcExited, "containerd": SvcRestarted, "crio": SvcExited, "crio-shutdown": SvcExited, }}, {"crio", map[string]serviceState{ "docker": SvcExited, - "docker.socket": SvcExited, "containerd": SvcExited, - "crio": SvcRestarted, + "crio": SvcRunning, "crio-shutdown": SvcExited, }}, } diff --git a/pkg/minikube/cruntime/docker.go b/pkg/minikube/cruntime/docker.go index 71c77dd3ffb0..236ae3510ac9 100644 --- a/pkg/minikube/cruntime/docker.go +++ b/pkg/minikube/cruntime/docker.go @@ -120,7 +120,7 @@ func (r *Docker) Restart() error { // Disable idempotently disables Docker on a host func (r *Docker) Disable() error { - return r.Init.ForceStop("docker.socket") + return r.Init.ForceStop("docker") } // ImageExists checks if an image exists diff --git a/pkg/minikube/kubelet/kubelet.go b/pkg/minikube/kubelet/kubelet.go deleted file mode 100644 index 90b9391e86f3..000000000000 --- a/pkg/minikube/kubelet/kubelet.go +++ /dev/null @@ -1,118 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package kubelet - -import ( - "fmt" - "os/exec" - "strings" - "time" - - "github.com/golang/glog" - "github.com/pkg/errors" - "k8s.io/minikube/pkg/minikube/command" - "k8s.io/minikube/pkg/minikube/sysinit" - "k8s.io/minikube/pkg/util/retry" -) - -// Stop idempotently stops the kubelet -func Stop(cr command.Runner) error { - return stop(cr, false) -} - -// ForceStop idempotently force stops the kubelet -func ForceStop(cr command.Runner) error { - return stop(cr, true) -} - -// stop dempotently stops the kubelet -func stop(cr command.Runner, force bool) error { - glog.Infof("stopping kubelet ...") - stp := func() error { - cmd := exec.Command("sudo", "systemctl", "stop", "kubelet.service") - if force { - cmd = exec.Command("sudo", "systemctl", "stop", "-f", "kubelet.service") - } - if rr, err := cr.RunCmd(cmd); err != nil { - return fmt.Errorf("temporary error for %q : %v", rr.Command(), err) - } - cmd = exec.Command("sudo", "systemctl", "show", "-p", "SubState", "kubelet") - rr, err := cr.RunCmd(cmd) - if err != nil { - return fmt.Errorf("temporary error: for %q : %v", rr.Command(), err) - } - if !strings.Contains(rr.Stdout.String(), "dead") && !strings.Contains(rr.Stdout.String(), "failed") { - return fmt.Errorf("unexpected kubelet state: %q", rr.Stdout.String()) - } - return nil - } - - if err := retry.Expo(stp, 1*time.Second, time.Minute, 2); err != nil { - return errors.Wrapf(err, "error stopping kubelet") - } - return nil -} - -// Start starts the kubelet -func Start(cr command.Runner) error { - glog.Infof("restarting kubelet.service ...") - c := exec.Command("sudo", "systemctl", "start", "kubelet") - if _, err := cr.RunCmd(c); err != nil { - return err - } - return nil -} - -// Restart restarts the kubelet -func Restart(cr command.Runner) error { - glog.Infof("restarting kubelet.service ...") - c := exec.Command("sudo", "systemctl", "restart", "kubelet.service") - if _, err := cr.RunCmd(c); err != nil { - return err - } - return nil -} - -// Check checks on the status of the kubelet -func Check(cr command.Runner) error { - glog.Infof("checking for running kubelet ...") - active := sysinit.New(cr).Active("kubelet") - if !active { - return fmt.Errorf("inactive") - } - return nil -} - -// Disable disables the Kubelet -func Disable(cr command.Runner) error { - glog.Infof("disabling kubelet ...") - c := exec.Command("sudo", "systemctl", "disable", "kubelet") - if _, err := cr.RunCmd(c); err != nil { - return errors.Wrap(err, "disable") - } - return nil -} - -// Enable enables the Kubelet -func Enable(cr command.Runner) error { - glog.Infof("enabling kubelet ...") - c := exec.Command("sudo", "systemctl", "enable", "kubelet") - if _, err := cr.RunCmd(c); err != nil { - return errors.Wrap(err, "enable") - } - return nil -} diff --git a/pkg/minikube/node/start.go b/pkg/minikube/node/start.go index 6527e6bbadcb..30cb1e9f1665 100644 --- a/pkg/minikube/node/start.go +++ b/pkg/minikube/node/start.go @@ -192,9 +192,9 @@ func Start(cc config.ClusterConfig, n config.Node, existingAddons map[string]boo // ConfigureRuntimes does what needs to happen to get a runtime going. func configureRuntimes(runner cruntime.CommandRunner, drvName string, k8s config.KubernetesConfig, kv semver.Version) cruntime.Manager { co := cruntime.Config{ - Type: viper.GetString(containerRuntime), - Runner: runner, - ImageRepository: k8s.ImageRepository, + Type: viper.GetString(containerRuntime), + Runner: runner, + ImageRepository: k8s.ImageRepository, KubernetesVersion: kv, } cr, err := cruntime.New(co) diff --git a/pkg/minikube/sysinit/openrc.go b/pkg/minikube/sysinit/openrc.go index 39e084dfd1ba..aa9be5c1bad3 100644 --- a/pkg/minikube/sysinit/openrc.go +++ b/pkg/minikube/sysinit/openrc.go @@ -111,6 +111,16 @@ func (s *OpenRC) Start(svc string) error { return err } +// Disable does nothing +func (s *OpenRC) Disable(svc string) error { + return nil +} + +// Enable does nothing +func (s *OpenRC) Enable(svc string) error { + return nil +} + // Restart restarts a service func (s *OpenRC) Restart(svc string) error { _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "restart")) diff --git a/pkg/minikube/sysinit/sysinit.go b/pkg/minikube/sysinit/sysinit.go index 7bb19f656d47..fc20479ded5e 100644 --- a/pkg/minikube/sysinit/sysinit.go +++ b/pkg/minikube/sysinit/sysinit.go @@ -1,3 +1,19 @@ +/* +Copyright 2020 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package sysinit import ( @@ -22,6 +38,12 @@ type Manager interface { // Active returns if a service is active Active(string) bool + // Disable disables a service + Disable(string) error + + // Enable enables a service + Enable(string) error + // Start starts a service idempotently Start(string) error diff --git a/pkg/minikube/sysinit/systemd.go b/pkg/minikube/sysinit/systemd.go index 71065b9b09c3..1d0506132092 100644 --- a/pkg/minikube/sysinit/systemd.go +++ b/pkg/minikube/sysinit/systemd.go @@ -45,6 +45,18 @@ func (s *Systemd) Active(svc string) bool { return err == nil } +// Disable disables a service +func (s *Systemd) Disable(svc string) error { + _, err := s.r.RunCmd(exec.Command("sudo", "systemctl", "disable", svc)) + return err +} + +// Enable enables a service +func (s *Systemd) Enable(svc string) error { + _, err := s.r.RunCmd(exec.Command("sudo", "systemctl", "enable", svc)) + return err +} + // Start starts a service func (s *Systemd) Start(svc string) error { if err := s.reload(); err != nil { From ae6fd4c660db73a69ad7ed57d976543bc720b7e6 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 8 Apr 2020 17:54:29 -0700 Subject: [PATCH 17/19] Lint --- pkg/minikube/sysinit/openrc.go | 9 +++------ pkg/minikube/sysinit/systemd.go | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/pkg/minikube/sysinit/openrc.go b/pkg/minikube/sysinit/openrc.go index f23ddb05298f..b64539c70eda 100644 --- a/pkg/minikube/sysinit/openrc.go +++ b/pkg/minikube/sysinit/openrc.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// sysinit provides an abstraction over init systems like systemctl +// Package sysinit provides an abstraction over init systems like systemctl package sysinit import ( @@ -31,8 +31,6 @@ import ( "k8s.io/minikube/pkg/minikube/vmpath" ) -const SysVName = "OpenRC" - var restartWrapper = `#!/bin/bash # Wrapper script to emulate systemd restart on non-systemd systems readonly UNIT_PATH=$1 @@ -88,7 +86,7 @@ type OpenRC struct { // Name returns the name of the init system func (s *OpenRC) Name() string { - return SysVName + return "OpenRC" } // Active checks if a service is running @@ -134,8 +132,7 @@ func (s *OpenRC) Stop(svc string) error { // ForceStop stops a service with prejuidice func (s *OpenRC) ForceStop(svc string) error { - _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "stop", "-f")) - return err + return s.Stop(svc) } // GenerateInitShim generates any additional init files required for this service diff --git a/pkg/minikube/sysinit/systemd.go b/pkg/minikube/sysinit/systemd.go index 1d0506132092..4bb53a186b09 100644 --- a/pkg/minikube/sysinit/systemd.go +++ b/pkg/minikube/sysinit/systemd.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// sysinit provides an abstraction over init systems like systemctl +// Package sysinit provides an abstraction over init systems like systemctl package sysinit import ( @@ -81,7 +81,7 @@ func (s *Systemd) Stop(svc string) error { return err } -// Stop stops a service +// ForceStop terminates a service with prejudice func (s *Systemd) ForceStop(svc string) error { _, err := s.r.RunCmd(exec.Command("sudo", "systemctl", "stop", "-f", svc)) return err From c368cd12d63878729c8ca6b2f02b39d8153f95f2 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 8 Apr 2020 18:05:04 -0700 Subject: [PATCH 18/19] use exec --- pkg/minikube/sysinit/openrc.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/minikube/sysinit/openrc.go b/pkg/minikube/sysinit/openrc.go index b64539c70eda..26d68cd1bb45 100644 --- a/pkg/minikube/sysinit/openrc.go +++ b/pkg/minikube/sysinit/openrc.go @@ -37,7 +37,9 @@ readonly UNIT_PATH=$1 while true; do if [[ -f "${UNIT_PATH}" ]]; then - eval $(egrep "^ExecStart=" "${UNIT_PATH}" | cut -d"=" -f2-) + args=$(egrep "^ExecStart=" "${UNIT_PATH}" | cut -d"=" -f2-) + echo $args + exec $args fi sleep 1 done @@ -104,7 +106,7 @@ func (s *OpenRC) Start(svc string) error { defer cb() rr, err := s.r.RunCmd(exec.CommandContext(ctx, "sudo", "service", svc, "start")) - glog.Infof("rr: %v", rr.Output()) + glog.Infof("start output: %s", rr.Output()) return err } @@ -120,13 +122,15 @@ func (s *OpenRC) Enable(svc string) error { // Restart restarts a service func (s *OpenRC) Restart(svc string) error { - _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "restart")) + rr, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "restart")) + glog.Infof("restart output: %s", rr.Output()) return err } // Stop stops a service func (s *OpenRC) Stop(svc string) error { - _, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "stop")) + rr, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "stop")) + glog.Infof("stop output: %s", rr.Output()) return err } From ece6b4729c443c75ce0a3a91200a6b3862f6adfd Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 8 Apr 2020 18:15:42 -0700 Subject: [PATCH 19/19] kill children --- pkg/minikube/sysinit/openrc.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/minikube/sysinit/openrc.go b/pkg/minikube/sysinit/openrc.go index 26d68cd1bb45..822c4157d083 100644 --- a/pkg/minikube/sysinit/openrc.go +++ b/pkg/minikube/sysinit/openrc.go @@ -37,9 +37,7 @@ readonly UNIT_PATH=$1 while true; do if [[ -f "${UNIT_PATH}" ]]; then - args=$(egrep "^ExecStart=" "${UNIT_PATH}" | cut -d"=" -f2-) - echo $args - exec $args + eval $(egrep "^ExecStart=" "${UNIT_PATH}" | cut -d"=" -f2-) fi sleep 1 done @@ -57,7 +55,10 @@ function start() { } function stop() { - start-stop-daemon --oknodo --pidfile "${PID_PATH}" --stop + if [[ -f "${PID_PATH}" ]]; then + pkill -P "$(cat ${PID_PATH})" + fi + start-stop-daemon --oknodo --pidfile "${PID_PATH}" --stop } case "$1" in