Merge branch 'master' into driver-fallback

pull/7389/head
Thomas Strömberg 2020-04-09 08:24:06 -07:00 committed by GitHub
commit aee3c1d4b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 930 additions and 380 deletions

View File

@ -19,6 +19,8 @@ jobs:
run : |
make minikube-linux-amd64
make e2e-linux-amd64
make minikube-windows-amd64.exe
make e2e-windows-amd64.exe
cp -r test/integration/testdata ./out
whoami
echo github ref $GITHUB_REF
@ -117,7 +119,7 @@ jobs:
with:
name: minikube_binaries
- name: Run Integration Test
continue-on-error: true
continue-on-error: false
# bash {0} to allow test to continue to next step. in case of
shell: bash {0}
run: |
@ -251,6 +253,70 @@ jobs:
numPass=$(echo $STAT | jq '.NumberOfPass')
echo "*** $numPass Passed ***"
if [ "$numFail" -gt 0 ];then echo "*** $numFail Failed ***";exit 2;fi
docker_on_windows:
needs: [build_minikube]
env:
TIME_ELAPSED: time
JOB_NAME: "Docker_on_windows"
COMMIT_STATUS: ""
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Docker Info
shell: bash
run: |
docker info || true
docker version || true
docker ps || true
- name: Download gopogh
run: |
curl -LO https://github.com/medyagh/gopogh/releases/download/v0.1.16/gopogh.exe
shell: bash
- name: Download binaries
uses: actions/download-artifact@v1
with:
name: minikube_binaries
- name: run integration test
continue-on-error: true
run: |
set +euo pipefail
mkdir -p report
mkdir -p testhome
START_TIME=$(date -u +%s)
KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome minikube_binaries/e2e-windows-amd64.exe -minikube-start-args=--vm-driver=docker -binary=minikube_binaries/minikube-windows-amd64.exe -test.v -test.timeout=65m 2>&1 | tee ./report/testout.txt
END_TIME=$(date -u +%s)
TIME_ELAPSED=$(($END_TIME-$START_TIME))
min=$((${TIME_ELAPSED}/60))
sec=$((${TIME_ELAPSED}%60))
TIME_ELAPSED="${min} min $sec seconds"
echo ::set-env name=TIME_ELAPSED::${TIME_ELAPSED}
shell: bash
- name: Generate html report
run: |
go tool test2json -t < ./report/testout.txt > ./report/testout.json || true
STAT=$(${GITHUB_WORKSPACE}/gopogh.exe -in ./report/testout.json -out ./report/testout.html -name " $GITHUB_REF" -repo "${JOB_NAME} ${GITHUB_REF} ${GITHUB_REPOSITORY}" -details "${GITHUB_SHA}") || true
echo status: ${STAT}
FailNum=$(echo $STAT | jq '.NumberOfFail')
TestsNum=$(echo $STAT | jq '.NumberOfTests')
GOPOGH_RESULT="${JOB_NAME} : completed with ${FailNum} / ${TestsNum} failures in ${TIME_ELAPSED}"
echo ::set-env name=GOPOGH_RESULT::${GOPOGH_RESULT}
echo ::set-env name=STAT::${STAT}
shell: bash
- uses: actions/upload-artifact@v1
with:
name: docker_on_windows
path: report
- name: The End Result
run: |
echo ${GOPOGH_RESULT}
numFail=$(echo $STAT | jq '.NumberOfFail')
echo "----------------${numFail} Failures----------------------------"
echo $STAT | jq '.FailedTests' || true
echo "--------------------------------------------"
numPass=$(echo $STAT | jq '.NumberOfPass')
echo "*** $numPass Passed ***"
if [ "$numFail" -gt 0 ];then echo "*** $numFail Failed ***";exit 2;fi
shell: bash
none_ubuntu16_04:
needs: [build_minikube]
env:
@ -521,6 +587,15 @@ jobs:
run: |
mkdir -p all_reports
cp -r docker_ubuntu_18_04 ./all_reports/
- name: download results docker_on_windows
uses: actions/download-artifact@v1
with:
name: docker_on_windows
- name: cp to all_report
shell: bash
run: |
mkdir -p all_reports
cp -r docker_on_windows ./all_reports/
- name: Download Results none_ubuntu16_04
uses: actions/download-artifact@v1
with:

View File

@ -62,6 +62,6 @@ minikube is a Kubernetes [#sig-cluster-lifecycle](https://github.com/kubernetes/
* [minikube-dev mailing list](https://groups.google.com/forum/#!forum/minikube-dev)
* [Bi-weekly office hours, Mondays @ 11am PST](https://tinyurl.com/minikube-oh)
* [Contributing](https://minikube.sigs.k8s.io/docs/contributing/)
* [Development Roadmap](https://minikube.sigs.k8s.io/docs/contributing/roadmap/)
* [Contributing](https://minikube.sigs.k8s.io/docs/contrib/)
* [Development Roadmap](https://minikube.sigs.k8s.io/docs/contrib/roadmap/)

View File

@ -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

View File

@ -668,7 +668,7 @@ func validateUser(drvName string) {
useForce := viper.GetBool(force)
if driver.NeedsRoot(drvName) && u.Uid != "0" && !useForce {
exit.WithCodeT(exit.Permissions, `The "{{.driver_name}}" driver requires root privileges. Please run minikube using 'sudo minikube --driver={{.driver_name}}'.`, out.V{"driver_name": drvName})
exit.WithCodeT(exit.Permissions, `The "{{.driver_name}}" driver requires root privileges. Please run minikube using 'sudo minikube start --driver={{.driver_name}}'.`, out.V{"driver_name": drvName})
}
if driver.NeedsRoot(drvName) || u.Uid != "0" {

View File

@ -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", name, stk)
st.Kubelet = stk.String()
// Early exit for regular nodes
if !controlPlane {

View File

@ -31,6 +31,7 @@ import (
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/sysinit"
)
func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string) error {
@ -86,7 +87,9 @@ func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string
KubernetesVersion: kubernetesVersion,
}
runner := command.NewKICRunner(profile, driver.OCIBinary)
if err := bsutil.TransferBinaries(kcfg, runner); err != nil {
sm := sysinit.New(runner)
if err := bsutil.TransferBinaries(kcfg, runner, sm); err != nil {
return errors.Wrap(err, "transferring k8s binaries")
}
// Create image tarball

View File

@ -0,0 +1,91 @@
/*
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 hyperkit
import (
"io/ioutil"
"os"
"testing"
)
func TestExtractFile(t *testing.T) {
testDir, err := ioutil.TempDir(os.TempDir(), "")
if nil != err {
return
}
defer os.Remove(testDir)
tests := []struct {
name string
isoPath string
srcPath string
destPath string
expectedError bool
}{
{
name: "all is right",
isoPath: "iso_test.iso",
srcPath: "/test1.txt",
destPath: testDir + "/test1.txt",
expectedError: false,
},
{
name: "isoPath is error",
isoPath: "tests.iso",
srcPath: "/test1.txt",
destPath: testDir + "/test1.txt",
expectedError: true,
},
{
name: "srcPath is empty",
isoPath: "iso_tests.iso",
srcPath: "",
destPath: testDir + "/test1.txt",
expectedError: true,
},
{
name: "srcPath is error",
isoPath: "iso_tests.iso",
srcPath: "/t1.txt",
destPath: testDir + "/test1.txt",
expectedError: true,
},
{
name: "destPath is empty",
isoPath: "iso_test.iso",
srcPath: "/test1.txt",
destPath: "",
expectedError: true,
},
{
name: "find files in a folder",
isoPath: "./iso_test.iso",
srcPath: "/test2/test2.txt",
destPath: testDir + "/test2.txt",
expectedError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ExtractFile(tt.isoPath, tt.srcPath, tt.destPath)
if (nil != err) != tt.expectedError {
t.Errorf("expectedError = %v, get = %v", tt.expectedError, err)
return
}
})
}
}

Binary file not shown.

View File

@ -22,6 +22,7 @@ import (
"os/exec"
"strconv"
"strings"
"sync"
"time"
"github.com/docker/machine/libmachine/drivers"
@ -37,7 +38,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
@ -112,6 +113,28 @@ func (d *Driver) Create() error {
}
}
if err := oci.PrepareContainerNode(params); err != nil {
return errors.Wrap(err, "setting up container node")
}
var waitForPreload sync.WaitGroup
waitForPreload.Add(1)
go func() {
defer waitForPreload.Done()
// If preload doesn't exist, don't bother extracting tarball to volume
if !download.PreloadExists(d.NodeConfig.KubernetesVersion, d.NodeConfig.ContainerRuntime) {
return
}
t := time.Now()
glog.Infof("Starting extracting preloaded images to volume")
// Extract preloaded images to container
if err := oci.ExtractTarballToVolume(download.TarballPath(d.NodeConfig.KubernetesVersion, d.NodeConfig.ContainerRuntime), params.Name, BaseImage); err != nil {
glog.Infof("Unable to extract preloaded tarball to volume: %v", err)
} else {
glog.Infof("duration metric: took %f seconds to extract preloaded images to volume", time.Since(t).Seconds())
}
}()
if err := oci.CreateContainerNode(params); err != nil {
return errors.Wrap(err, "create kic node")
}
@ -120,19 +143,7 @@ func (d *Driver) Create() error {
return errors.Wrap(err, "prepare kic ssh")
}
// If preload doesn't exist, don't bother extracting tarball to volume
if !download.PreloadExists(d.NodeConfig.KubernetesVersion, d.NodeConfig.ContainerRuntime) {
return nil
}
t := time.Now()
glog.Infof("Starting extracting preloaded images to volume")
// Extract preloaded images to container
if err := oci.ExtractTarballToVolume(download.TarballPath(d.NodeConfig.KubernetesVersion, d.NodeConfig.ContainerRuntime), params.Name, BaseImage); err != nil {
glog.Infof("Unable to extract preloaded tarball to volume: %v", err)
} else {
glog.Infof("Took %f seconds to extract preloaded images to volume", time.Since(t).Seconds())
}
waitForPreload.Wait()
return nil
}
@ -245,7 +256,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 +329,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)
}
}

View File

@ -84,6 +84,19 @@ func DeleteContainer(ociBin string, name string) error {
return nil
}
// PrepareContainerNode sets up the container node befpre CreateContainerNode is caleld
// for the docker runtime, it creates a docker volume which will be mounted into kic
func PrepareContainerNode(p CreateParams) error {
if p.OCIBinary != Docker {
return nil
}
if err := createDockerVolume(p.Name, p.Name); err != nil {
return errors.Wrapf(err, "creating volume for %s container", p.Name)
}
glog.Infof("Successfully created a docker volume %s", p.Name)
return nil
}
// CreateContainerNode creates a new container node
func CreateContainerNode(p CreateParams) error {
runArgs := []string{
@ -122,10 +135,6 @@ func CreateContainerNode(p CreateParams) error {
runArgs = append(runArgs, "--volume", fmt.Sprintf("%s:/var:exec", hostVarVolPath))
}
if p.OCIBinary == Docker {
if err := createDockerVolume(p.Name, p.Name); err != nil {
return errors.Wrapf(err, "creating volume for %s container", p.Name)
}
glog.Infof("Successfully created a docker volume %s", p.Name)
runArgs = append(runArgs, "--volume", fmt.Sprintf("%s:/var", p.Name))
// setting resource limit in privileged mode is only supported by docker
// podman error: "Error: invalid configuration, cannot set resources with rootless containers not using cgroups v2 unified mode"

View File

@ -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"
)
@ -142,12 +142,12 @@ 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.
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)
}
}

View File

@ -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)
}

View File

@ -32,11 +32,12 @@ import (
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/download"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/sysinit"
"k8s.io/minikube/pkg/minikube/vmpath"
)
// TransferBinaries transfers all required Kubernetes binaries
func TransferBinaries(cfg config.KubernetesConfig, c command.Runner) error {
func TransferBinaries(cfg config.KubernetesConfig, c command.Runner, sm sysinit.Manager) error {
ok, err := binariesExist(cfg, c)
if err == nil && ok {
glog.Info("Found k8s binaries, skipping transfer")
@ -50,11 +51,6 @@ func TransferBinaries(cfg config.KubernetesConfig, c command.Runner) error {
return err
}
// stop kubelet to avoid "Text File Busy" error
if _, err := c.RunCmd(exec.Command("/bin/bash", "-c", "pgrep kubelet && sudo systemctl stop kubelet")); err != nil {
glog.Warningf("unable to stop kubelet: %s", err)
}
var g errgroup.Group
for _, name := range constants.KubernetesReleaseBinaries {
name := name
@ -64,6 +60,12 @@ func TransferBinaries(cfg config.KubernetesConfig, c command.Runner) error {
return errors.Wrapf(err, "downloading %s", name)
}
if name == "kubelet" {
if err := sm.ForceStop("kubelet"); err != nil {
glog.Errorf("unable to stop kubelet: %v", err)
}
}
dst := path.Join(dir, name)
if err := machine.CopyBinary(c, src, dst); err != nil {
return errors.Wrapf(err, "copybinary %s -> %s", src, dst)

View File

@ -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"
)
// 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
}

View File

@ -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"
)
// WaitForSystemPods verifies essential pods for running kurnetes is running
@ -156,22 +156,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)
active := sysinit.New(cr).Active("kubelet")
if active {
return state.Running
}
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
}
return state.Error, nil
return state.Stopped
}

View File

@ -323,20 +323,33 @@ func collectCACerts() (map[string]string, error) {
if err != nil {
return err
}
if info == nil {
return nil
}
if info.IsDir() {
return nil
}
if info != nil && !info.IsDir() {
ext := strings.ToLower(filepath.Ext(hostpath))
if ext == ".crt" || ext == ".pem" {
glog.Infof("found cert: %s (%d bytes)", info.Name(), info.Size())
validPem, err := isValidPEMCertificate(hostpath)
if err != nil {
return err
}
if validPem {
filename := filepath.Base(hostpath)
dst := fmt.Sprintf("%s.%s", strings.TrimSuffix(filename, ext), "pem")
certFiles[hostpath] = path.Join(vmpath.GuestCertAuthDir, dst)
}
fullPath := filepath.Join(certsDir, hostpath)
ext := strings.ToLower(filepath.Ext(hostpath))
if ext == ".crt" || ext == ".pem" {
if info.Size() < 32 {
glog.Warningf("ignoring %s, impossibly tiny %d bytes", fullPath, info.Size())
return nil
}
glog.Infof("found cert: %s (%d bytes)", fullPath, info.Size())
validPem, err := isValidPEMCertificate(hostpath)
if err != nil {
return err
}
if validPem {
filename := filepath.Base(hostpath)
dst := fmt.Sprintf("%s.%s", strings.TrimSuffix(filename, ext), "pem")
certFiles[hostpath] = path.Join(vmpath.GuestCertAuthDir, dst)
}
}
return nil
@ -394,23 +407,26 @@ func installCertSymlinks(cr command.Runner, caCerts map[string]string) error {
for _, caCertFile := range caCerts {
dstFilename := path.Base(caCertFile)
certStorePath := path.Join(vmpath.GuestCertStoreDir, dstFilename)
// If the cert really exists, add a named symlink
cmd := fmt.Sprintf("test -f %s && ln -fs %s %s", caCertFile, caCertFile, certStorePath)
cmd := fmt.Sprintf("test -s %s && ln -fs %s %s", caCertFile, caCertFile, certStorePath)
if _, err := cr.RunCmd(exec.Command("sudo", "/bin/bash", "-c", cmd)); err != nil {
return errors.Wrapf(err, "create symlink for %s", caCertFile)
}
if hasSSLBinary {
subjectHash, err := getSubjectHash(cr, caCertFile)
if err != nil {
return errors.Wrapf(err, "calculate hash for cacert %s", caCertFile)
}
subjectHashLink := path.Join(vmpath.GuestCertStoreDir, fmt.Sprintf("%s.0", subjectHash))
// NOTE: This symlink may exist, but point to a missing file
cmd := fmt.Sprintf("test -L %s || ln -fs %s %s", subjectHashLink, certStorePath, subjectHashLink)
if _, err := cr.RunCmd(exec.Command("sudo", "/bin/bash", "-c", cmd)); err != nil {
return errors.Wrapf(err, "create symlink for %s", caCertFile)
}
if !hasSSLBinary {
continue
}
subjectHash, err := getSubjectHash(cr, caCertFile)
if err != nil {
return errors.Wrapf(err, "calculate hash for cacert %s", caCertFile)
}
subjectHashLink := path.Join(vmpath.GuestCertStoreDir, fmt.Sprintf("%s.0", subjectHash))
// NOTE: This symlink may exist, but point to a missing file
cmd = fmt.Sprintf("test -L %s || ln -fs %s %s", subjectHashLink, certStorePath, subjectHashLink)
if _, err := cr.RunCmd(exec.Command("sudo", "/bin/bash", "-c", cmd)); err != nil {
return errors.Wrapf(err, "create symlink for %s", caCertFile)
}
}
return nil

View File

@ -51,8 +51,8 @@ func TestSetupCerts(t *testing.T) {
}
expected := map[string]string{
`sudo /bin/bash -c "test -f /usr/share/ca-certificates/mycert.pem && ln -fs /usr/share/ca-certificates/mycert.pem /etc/ssl/certs/mycert.pem"`: "-",
`sudo /bin/bash -c "test -f /usr/share/ca-certificates/minikubeCA.pem && ln -fs /usr/share/ca-certificates/minikubeCA.pem /etc/ssl/certs/minikubeCA.pem"`: "-",
`sudo /bin/bash -c "test -s /usr/share/ca-certificates/mycert.pem && ln -fs /usr/share/ca-certificates/mycert.pem /etc/ssl/certs/mycert.pem"`: "-",
`sudo /bin/bash -c "test -s /usr/share/ca-certificates/minikubeCA.pem && ln -fs /usr/share/ca-certificates/minikubeCA.pem /etc/ssl/certs/minikubeCA.pem"`: "-",
}
f := command.NewFakeCommandRunner()
f.SetCommandToOutput(expected)

View File

@ -51,9 +51,9 @@ 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"
"k8s.io/minikube/pkg/minikube/vmpath"
"k8s.io/minikube/pkg/util"
"k8s.io/minikube/pkg/util/retry"
@ -82,26 +82,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) {
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
}
// GetAPIServerStatus returns the api-server status
func (k *Bootstrapper) GetAPIServerStatus(hostname string, port int) (string, error) {
s, err := kverify.APIServerStatus(k.c, hostname, port)
@ -190,7 +170,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
}
@ -615,7 +595,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)
}
@ -679,6 +659,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")
@ -696,24 +681,40 @@ func (k *Bootstrapper) UpdateNode(cfg config.ClusterConfig, n config.Node, r cru
glog.Infof("kubelet %s config:\n%+v", kubeletCfg, cfg.KubernetesConfig)
if err := bsutil.TransferBinaries(cfg.KubernetesConfig, k.c); err != nil {
sm := sysinit.New(k.c)
if err := bsutil.TransferBinaries(cfg.KubernetesConfig, k.c, sm); err != nil {
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)
// 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); err != nil {
return err
if err := startKubeletIfRequired(k.c, sm); err != nil {
return errors.Wrap(err, "reload")
}
return nil
}
@ -736,7 +737,12 @@ func copyFiles(runner command.Runner, files []assets.CopyableFile) error {
return nil
}
func reloadKubelet(runner command.Runner) error {
func startKubeletIfRequired(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
@ -746,11 +752,12 @@ func reloadKubelet(runner command.Runner) error {
return nil
}
startCmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("sudo cp %s.new %s && sudo cp %s.new %s && sudo systemctl daemon-reload && sudo systemctl restart kubelet", svc, svc, conf, conf))
startCmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("sudo cp %s.new %s && sudo cp %s.new %s", svc, svc, conf, conf))
if _, err := runner.RunCmd(startCmd); err != nil {
return errors.Wrap(err, "starting kubelet")
}
return nil
return sm.Start("kubelet")
}
// applyKicOverlay applies the CNI plugin needed to make kic work

View File

@ -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
}

View File

@ -32,6 +32,7 @@ import (
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/download"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/sysinit"
)
const (
@ -116,6 +117,7 @@ type Containerd struct {
Runner CommandRunner
ImageRepository string
KubernetesVersion semver.Version
Init sysinit.Manager
}
// Name is a human readable name for containerd
@ -158,9 +160,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
@ -208,21 +208,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", "-f", "containerd")
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrapf(err, "stop containerd")
}
return nil
return r.Init.ForceStop("containerd")
}
// ImageExists checks if an image exists, expected input format

View File

@ -28,6 +28,7 @@ import (
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/download"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/sysinit"
)
const (
@ -41,6 +42,7 @@ type CRIO struct {
Runner CommandRunner
ImageRepository string
KubernetesVersion semver.Version
Init sysinit.Manager
}
// generateCRIOConfig sets up /etc/crio/crio.conf
@ -104,9 +106,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
@ -125,19 +125,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", "-f", "crio")); err != nil {
return errors.Wrapf(err, "disable crio.")
}
return nil
return r.Init.ForceStop("crio")
}
// ImageExists checks if an image exists

View File

@ -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)
}

View File

@ -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,
}},
}

View File

@ -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,7 @@ func (e *ErrISOFeature) Error() string {
type Docker struct {
Socket string
Runner CommandRunner
Init sysinit.Manager
}
// Name is a human readable name for Docker
@ -97,9 +99,7 @@ func (r *Docker) Available() error {
// 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 +109,18 @@ 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", "-f", "docker", "docker.socket")
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrap(err, "disable docker")
}
return nil
return r.Init.ForceStop("docker")
}
// ImageExists checks if an image exists

View File

@ -1,117 +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/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 ...")
c := exec.Command("sudo", "systemctl", "is-active", "--quiet", "service", "kubelet")
if _, err := cr.RunCmd(c); err != nil {
return errors.Wrap(err, "check kubelet")
}
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
}

View File

@ -113,7 +113,8 @@ func Start(starter Starter, apiServer bool) (*kubeconfig.Settings, error) {
// setup kubeadm (must come after setupKubeconfig)
bs = setupKubeAdm(starter.MachineAPI, *starter.Cfg, *starter.Node)
err = bs.StartCluster(*starter.Cfg)
if err != nil {
if err != nil {
out.LogEntries("Error starting cluster", err, logs.FindProblems(cr, bs, *starter.Cfg, starter.Runner))
return nil, err
}

View File

@ -21,9 +21,11 @@ import (
"fmt"
"os/exec"
"runtime"
"strings"
"time"
"github.com/docker/machine/libmachine/drivers"
"github.com/golang/glog"
"k8s.io/minikube/pkg/drivers/kic"
"k8s.io/minikube/pkg/drivers/kic/oci"
"k8s.io/minikube/pkg/minikube/config"
@ -70,7 +72,7 @@ func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) {
func status() registry.State {
_, err := exec.LookPath(oci.Docker)
if err != nil {
return registry.State{Error: err, Installed: false, Healthy: false, Fix: "Docker is required.", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/docker/"}
return registry.State{Error: err, Installed: false, Healthy: false, Fix: "Install Docker.", Doc: "https://minikube.sigs.k8s.io/docs/drivers/docker/#install-docker"}
}
// Allow no more than 3 seconds for docker info
@ -78,8 +80,19 @@ func status() registry.State {
defer cancel()
err = exec.CommandContext(ctx, oci.Docker, "info").Run()
if ctx.Err() == context.DeadlineExceeded {
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Docker responds too slow. Restart the Docker Service.", Doc: "https://minikube.sigs.k8s.io/docs/drivers/docker"}
}
if err != nil {
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Docker is not running or is responding too slow. Try: restarting docker desktop."}
glog.Infof("docker info returned error: %v", err)
if strings.Contains(err.Error(), "Cannot connect to the Docker daemon") {
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Start the Docker Service.", Doc: "https://minikube.sigs.k8s.io/docs/drivers/docker"}
}
// if we get here, something is really wrong on their docker.
// our best suggestion would be re-install latest docker.
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Re-install the latest version of Docker.", Doc: "https://minikube.sigs.k8s.io/docs/drivers/docker"}
}
return registry.State{Installed: true, Healthy: true}

View File

@ -52,8 +52,9 @@ func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) {
}
func status() registry.State {
if _, err := exec.LookPath("systemctl"); err != nil {
return registry.State{Error: err, Fix: "Use a systemd based Linux distribution", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"}
_, err := exec.LookPath("iptables")
if err != nil {
return registry.State{Error: err, Fix: "iptables must be installed", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"}
}
if _, err := exec.LookPath("docker"); err != nil {

View File

@ -0,0 +1,170 @@
/*
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 sysinit provides an abstraction over init systems like systemctl
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"
)
var restartWrapper = `#!/bin/bash
# Wrapper script to emulate systemd restart on non-systemd systems
readonly UNIT_PATH=$1
while true; do
if [[ -f "${UNIT_PATH}" ]]; then
eval $(egrep "^ExecStart=" "${UNIT_PATH}" | cut -d"=" -f2-)
fi
sleep 1
done
`
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"
function start() {
start-stop-daemon --oknodo --pidfile "${PID_PATH}" --background --start --make-pid --exec "${RESTART_WRAPPER}" "${UNIT_PATH}"
}
function stop() {
if [[ -f "${PID_PATH}" ]]; then
pkill -P "$(cat ${PID_PATH})"
fi
start-stop-daemon --oknodo --pidfile "${PID_PATH}" --stop
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
start-stop-daemon --pidfile "${PID_PATH}" --status
;;
*)
echo "Usage: {{.Name}} {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 "OpenRC"
}
// 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("start output: %s", rr.Output())
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 {
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 {
rr, err := s.r.RunCmd(exec.Command("sudo", "service", svc, "stop"))
glog.Infof("stop output: %s", rr.Output())
return err
}
// ForceStop stops a service with prejuidice
func (s *OpenRC) ForceStop(svc string) error {
return s.Stop(svc)
}
// 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
}

View File

@ -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 sysinit
import (
"os/exec"
"k8s.io/minikube/pkg/minikube/assets"
"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)
}
// 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
// Disable disables a service
Disable(string) error
// Enable enables a service
Enable(string) error
// Start starts a service idempotently
Start(string) error
// Restart restarts a service
Restart(string) error
// Stop stops a service
Stop(string) error
// 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
func New(r Runner) Manager {
// If we are not provided a runner, we can't do anything anyways
if r == nil {
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 {
systemd = usesSystemd(r)
cachedSystemdCheck = &systemd
}
if systemd {
return &Systemd{r: r}
}
return &OpenRC{r: r}
}

View File

@ -0,0 +1,98 @@
/*
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 sysinit provides an abstraction over init systems like systemctl
package sysinit
import (
"os/exec"
"k8s.io/minikube/pkg/minikube/assets"
)
// 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
}
// 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
}
// 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 {
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(); err != nil {
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", "stop", svc))
return err
}
// 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
}
// 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
}

View File

@ -163,3 +163,9 @@ div.td-content {
font-size: 1.3rem !important;
}
}
// make search bar wider https://www.docsy.dev/docs/adding-content/navigation/#configure-local-search-with-lunr
.popover.offline-search-result {
background-color: $gray-200 !important;
max-width: 460px;
}

View File

@ -79,11 +79,12 @@ All translations are stored in the top-level `translations` directory.
* You now have a fresh minikube binary in the `out` directory. If your system locale is that of the language you added translations for, a simple `out/minikube start` will work as a test, assuming you translated phrases from `minikube start`. You can use whatever command you'd like in that way.
* If you have a different system locale, you can override the printed language using the LANG environment variable:
* If you have a different system locale, you can override the printed language using the LC_ALL environment variable:
```
~/minikube$ LANG=fr out/minikube start
😄 minikube v1.9.0-beta.2 sur Darwin 10.14.6
✨ Choix automatique du driver hyperkit
~/minikube$ LC_ALL=fr out/minikube start
😄 minikube v1.9.2 sur Darwin 10.14.5
✨ Choix automatique du driver hyperkit. Autres choix: <no value>
👍 Starting control plane node minikube in cluster minikube
🔥 Création de VM hyperkit (CPUs=2, Mémoire=4000MB, Disque=20000MB)...
🐳 Préparation de Kubernetes v1.18.0 sur Docker 19.03.8...
🌟 Installation des addons: default-storageclass, storage-provisioner

View File

@ -21,12 +21,16 @@ The Docker driver allows you to install Kubernetes into an existing Docker insta
- On macOS, containers might get hung and require a restart of Docker for Desktop. See [docker/for-mac#1835](https://github.com/docker/for-mac/issues/1835)
- The `ingress` and `ingress-dns` addons are currently only supported on Linux. See [#7332](https://github.com/kubernetes/minikube/issues/7332)
- The `ingress`, `ingress-dns` and `registry` addons are currently only supported on Linux. See [#7332](https://github.com/kubernetes/minikube/issues/7332) and [#7535](https://github.com/kubernetes/minikube/issues/7535)
- On WSL2 (experimental - see [#5392](https://github.com/kubernetes/minikube/issues/5392)), you may need to run:
`sudo mkdir /sys/fs/cgroup/systemd && sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd`.
- Addon 'registry' for mac and windows is not supported yet and it is [a work in progress](https://github.com/kubernetes/minikube/issues/7535).
## Troubleshooting
- On macOS or Windows, you may need to restart Docker for Desktop if a command gets hung

View File

@ -2,7 +2,7 @@
title: "Pushing images"
weight: 5
description: >
There are many ways to push images into minikube.
comparing 5 ways to push your image into a minikiube cluster.
aliases:
- /docs/tasks/building
- /docs/tasks/caching
@ -10,15 +10,81 @@ aliases:
- /docs/tasks/docker_daemon
---
# Cached Images
## Comparison table for different methods
The best method to push your image to minikube depends on the container-runtime you built your cluster with (default docker).
Here is a comparison table to help you choose:
From the host, you can push a Docker image directly to minikube. It will also be cached for future cluster starts.
| Method | Supported Runtimes | Issues | Performance |
|--- |--- |--- |--- |--- |
| [docker-env command](/docs/handbook/pushing/#1pushing-directly-to-the-in-cluster-docker-daemon-docker-env) | only docker | | good |
| [podman-env command](/docs/handbook/pushing/#3-pushing-directly-to-in-cluster-crio-podman-env) | only cri-o | | good |
| [cache add command](/pushing/#push-images-using-cache-command) | all | | ok |
| [registry addon](/docs/handbook/pushing/#4-pushing-to-an-in-cluster-using-registry-addon) | all | work in progress for [docker on mac](https://github.com/kubernetes/minikube/issues/7535) | ok |
| [minikube ssh](/docs/handbook/pushing/#5-building-images-inside-of-minikube-using-ssh) | all | | best |
* note1 : the default container-runtime on minikube is 'docker'.
* note2 : 'none' driver (bare metal) does not need pushing image to the cluster, as any image on your system is already available to the kuberentes.
---
## 1.Pushing directly to the in-cluster Docker daemon (docker-env)
When using a container or VM driver (all drivers except none), you can reuse the Docker daemon inside minikube cluster.
this means you don't have to build on your host machine and push the image into a docker registry. You can just build inside the same docker daemon as minikube which speeds up local experiments.
To point your terminal to use the docker daemon inside minikube run this:
```shell
minikube cache add ubuntu:16.04
eval $(minikube docker-env)
```
The add command will store the requested image to `$MINIKUBE_HOME/cache/images`, and load it into the VM's container runtime environment next time `minikube start` is called.
now any 'docker' command you run in this current terminal will run against the docker inside minikube VM or Container.
Try it:
```shell
docker ps
```
now you 'build' against the docker inside minikube. which is instantly accessible to kubernetes cluster.
'''
docker build -t myimage .
'''
Remember to turn off the `imagePullPolicy:Always` (use `imagePullPolicy:IfNotPresent` or `imagePullPolicy:Never`), as otherwise Kubernetes won't use images you built locally.
{{% pageinfo %}}
Evaluating the docker-env is only valid for the current terminal.
and by closing the terminal, you will go back to using your own system's docker daemon.
in some drivers such as Docker or Podman, you will need to re-do docker-env each time you restart your minikube.
{{% /pageinfo %}}
To verify your terminal is using minikuber's docker-env you can check the value of the environment variable MINIKUBE_ACTIVE_DOCKERD to reflect the profile name.
more information on [docker-env](https://minikube.sigs.k8s.io/docs/commands/docker-env/)
---
## 2.Push images using 'cache' command.
From your host, you can push a Docker image directly to minikube. This image will be cached and automatically pulled into all future minikube clusters created on the machine
```shell
minikube cache add alpine:latest
```
The add command will store the requested image to `$MINIKUBE_HOME/cache/images`, and load it into the minikube cluster's container runtime environment automatically.
{{% pageinfo %}}
if your image changes after your cached it, you could do `cache reload` to ensure minikube gets the last updates.
```
shell
minikube cache reload
```
{{% /pageinfo %}}
To display images you have added to the cache:
@ -26,7 +92,8 @@ To display images you have added to the cache:
minikube cache list
```
This listing will not include the images which are built-in to minikube.
This listing will not include the images minikube's built-in system images.
```shell
@ -37,36 +104,9 @@ For more information, see:
* [Reference: cache command]({{< ref "/docs/commands/cache.md" >}})
You must be using minikube with the container runtime set to Docker. This is the default setting.
---
# Pushing directly to the in-cluster Docker daemon
When user a container or VM driver, it's really handy to reuse the Docker daemon inside minikube; as this means you don't have to build on your host machine and push the image into a docker registry - you can just build inside the same docker daemon as minikube which speeds up local experiments.
To point your terminal to use the docker daemon inside minikube run this:
```shell
eval $(minikube docker-env)
```
now any command you run in this current terminal will run against the docker inside minikube VM or Container.
Try it:
```shell
docker ps
```
now you can use same docker build command against the docker inside minikube. which is instantly accessible to kubernetes cluster.
'''
docker build -t myimage .
'''
Remember to turn off the `imagePullPolicy:Always` (use `imagePullPolicy:IfNotPresent` or `imagePullPolicy:Never`), as otherwise Kubernetes won't use images you built locally.
more information on [docker-env](https://minikube.sigs.k8s.io/docs/commands/docker-env/)
# Pushing directly to in-cluster CRIO
## 3. Pushing directly to in-cluster CRIO. (podman-env)
To push directly to CRIO, configure podman client on your mac/linux host using the podman-env command in your shell:
@ -82,7 +122,9 @@ podman-remote help
Remember to turn off the `imagePullPolicy:Always` (use `imagePullPolicy:IfNotPresent` or `imagePullPolicy:Never`), as otherwise Kubernetes won't use images you built locally.
# Pushing to an in-cluster Registry
---
## 4. Pushing to an in-cluster using Registry addon
For illustration purpose, we will assume that minikube VM has one of the ip from `192.168.39.0/24` subnet. If you have not overridden these subnets as per [networking guide](https://minikube.sigs.k8s.io/reference/networking/), you can find out default subnet being used by minikube for a specific OS and driver combination [here](https://github.com/kubernetes/minikube/blob/dfd9b6b83d0ca2eeab55588a16032688bc26c348/pkg/minikube/cluster/cluster.go#L408) which is subject to change. Replace `192.168.39.0/24` with appropriate values for your environment wherever applicable.
@ -108,9 +150,12 @@ Push docker image to minikube registry:
docker push $(minikube ip):5000/test-img
```
# Building images inside of minikube
---
Use `minikube ssh` to connect to the virtual machine, and run the `docker build` there:
## 5. Building images inside of minikube using SSH
Use `minikube ssh` to run commands inside the minikube node, and run the `docker build` directly there.
Any command you run there will run against the same daemon that kubernetes cluster is using.
```shell
docker build
@ -126,3 +171,7 @@ sudo -E podman build
For more information on the `podman build` command, read the [Podman documentation](https://github.com/containers/libpod/blob/master/docs/source/markdown/podman-build.1.md) (podman.io).
to exit minikube ssh and come back to your terminal type:
```shell
exit
```

@ -1 +1 @@
Subproject commit e13afeb5c0ffa5a2dff237fffa77bea80319f578
Subproject commit dd303fd19cc13ffc01bcbe86ff54f21e423d04de

View File

@ -73,6 +73,11 @@ func TestFunctional(t *testing.T) {
if err := os.Remove(p); err != nil {
t.Logf("unable to remove %q: %v", p, err)
}
p = localEmptyCertPath()
if err := os.Remove(p); err != nil {
t.Logf("unable to remove %q: %v", p, err)
}
CleanupWithLogs(t, profile, cancel)
}()
@ -793,18 +798,44 @@ func localTestCertPath() string {
return filepath.Join(localpath.MiniPath(), "/certs", testCert())
}
// localEmptyCertPath is where the test file will be synced into the VM
func localEmptyCertPath() string {
return filepath.Join(localpath.MiniPath(), "/certs", fmt.Sprintf("%d_empty.pem", os.Getpid()))
}
// Copy extra file into minikube home folder for file sync test
func setupFileSync(ctx context.Context, t *testing.T, profile string) {
p := localSyncTestPath()
t.Logf("local sync path: %s", p)
err := copy.Copy("./testdata/sync.test", p)
if err != nil {
t.Fatalf("failed to copy ./testdata/sync.test : %v", err)
t.Fatalf("failed to copy ./testdata/sync.test: %v", err)
}
err = copy.Copy("./testdata/minikube_test.pem", localTestCertPath())
testPem := "./testdata/minikube_test.pem"
err = copy.Copy(testPem, localTestCertPath())
if err != nil {
t.Fatalf("failed to copy ./testdata/minikube_test.pem : %v", err)
t.Fatalf("failed to copy %s: %v", testPem, err)
}
want, err := os.Stat(testPem)
if err != nil {
t.Fatalf("stat failed: %v", err)
}
got, err := os.Stat(localTestCertPath())
if err != nil {
t.Fatalf("stat failed: %v", err)
}
if want.Size() != got.Size() {
t.Errorf("%s size=%d, want %d", localTestCertPath(), got.Size(), want.Size())
}
// Create an empty file just to mess with people
if _, err := os.Create(localEmptyCertPath()); err != nil {
t.Fatalf("create failed: %v", err)
}
}

View File

@ -203,7 +203,8 @@ func clusterLogs(t *testing.T, profile string) {
t.Logf("-----------------------post-mortem--------------------------------")
t.Logf("<<< %s FAILED: start of post-mortem logs <<<", t.Name())
t.Logf("-------------------post-mortem minikube logs----------------------")
t.Logf("======> post-mortem[%s]: minikube logs <======", t.Name())
rr, err := Run(t, exec.Command(Target(), "-p", profile, "logs", "--problems"))
if err != nil {
t.Logf("failed logs error: %v", err)
@ -211,27 +212,43 @@ func clusterLogs(t *testing.T, profile string) {
}
t.Logf("%s logs: %s", t.Name(), rr.Output())
t.Logf("------------------post-mortem api server status-------------------")
t.Logf("======> post-mortem[%s]: disk usage <======", t.Name())
rr, err = Run(t, exec.Command(Target(), "-p", profile, "ssh", "df -h /var/lib/docker/overlay2 /var /; du -hs /var/lib/docker/overlay2"))
if err != nil {
t.Logf("failed df error: %v", err)
}
t.Logf("%s df: %s", t.Name(), rr.Stdout)
st = Status(context.Background(), t, Target(), profile, "APIServer")
if st != state.Running.String() {
t.Logf("%q apiserver is not running, skipping kubectl commands (state=%q)", profile, st)
return
}
t.Logf("--------------------post-mortem get pods--------------------------")
t.Logf("======> post-mortem[%s]: get pods <======", t.Name())
rr, rerr := Run(t, exec.Command("kubectl", "--context", profile, "get", "po", "-A", "--show-labels"))
if rerr != nil {
t.Logf("%s: %v", rr.Command(), rerr)
return
}
t.Logf("(dbg) %s:\n%s", rr.Command(), rr.Output())
t.Logf("-------------------post-mortem describe node----------------------")
t.Logf("======> post-mortem[%s]: describe node <======", t.Name())
rr, err = Run(t, exec.Command("kubectl", "--context", profile, "describe", "node"))
if err != nil {
t.Logf("%s: %v", rr.Command(), err)
} else {
t.Logf("(dbg) %s:\n%s", rr.Command(), rr.Output())
}
t.Logf("------------------------------------------------------------------")
t.Logf("======> post-mortem[%s]: describe pods <======", t.Name())
rr, err = Run(t, exec.Command("kubectl", "--context", profile, "describe", "po", "-A"))
if err != nil {
t.Logf("%s: %v", rr.Command(), err)
} else {
t.Logf("(dbg) %s:\n%s", rr.Command(), rr.Stdout)
}
t.Logf("<<< %s FAILED: end of post-mortem logs <<<", t.Name())
t.Logf("---------------------/post-mortem---------------------------------")
}