fix makefile

pull/10408/head
Sharif Elgamal 2021-02-12 16:15:33 -08:00
commit 38c6fc60f0
31 changed files with 359 additions and 129 deletions

View File

@ -631,14 +631,14 @@ storage-provisioner-image-%: out/storage-provisioner-%
docker build -t $(REGISTRY)/storage-provisioner-$*:$(STORAGE_PROVISIONER_TAG) -f deploy/storage-provisioner/Dockerfile --build-arg arch=$* .
X_DOCKER_BUILDER ?= minikube-builder
X_DOCKER_BUILDER ?= kicbase-builder
X_BUILD_ENV ?= DOCKER_CLI_EXPERIMENTAL=enabled
.PHONY: docker-multi-arch-builder
docker-multi-arch-builder:
env $(X_BUILD_ENV) docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
env $(X_BUILD_ENV) docker buildx rm --builder $(X_DOCKER_BUILDER) || true
env $(X_BUILD_ENV) docker buildx create --name kicbase-builder --buildkitd-flags '--debug' --use || true
env $(X_BUILD_ENV) docker buildx create --name $(X_DOCKER_BUILDER) --buildkitd-flags '--debug' --use || true
KICBASE_ARCH = linux/arm64,linux/amd64
KICBASE_IMAGE_REGISTRIES ?= $(REGISTRY)/kicbase:$(KIC_VERSION) $(REGISTRY_GH)/kicbase:$(KIC_VERSION) kicbase/stable:$(KIC_VERSION)

View File

@ -1,4 +1,4 @@
// +build darwin
// +build darwin,!arm64
/*
Copyright 2016 The Kubernetes Authors All rights reserved.

View File

@ -41,6 +41,7 @@ import (
)
var output string
var isLight bool
var profileListCmd = &cobra.Command{
Use: "list",
@ -58,8 +59,18 @@ var profileListCmd = &cobra.Command{
},
}
func listProfiles() (validProfiles, invalidProfiles []*config.Profile, err error) {
if isLight {
validProfiles, err = config.ListValidProfiles()
} else {
validProfiles, invalidProfiles, err = config.ListProfiles()
}
return validProfiles, invalidProfiles, err
}
func printProfilesTable() {
validProfiles, invalidProfiles, err := config.ListProfiles()
validProfiles, invalidProfiles, err := listProfiles()
if err != nil {
klog.Warningf("error loading profiles: %v", err)
@ -75,6 +86,13 @@ func printProfilesTable() {
}
func updateProfilesStatus(profiles []*config.Profile) {
if isLight {
for _, p := range profiles {
p.Status = "Skipped"
}
return
}
api, err := machine.NewAPIClient()
if err != nil {
klog.Errorf("failed to get machine api client %v", err)
@ -168,7 +186,7 @@ func warnInvalidProfiles(invalidProfiles []*config.Profile) {
}
func printProfilesJSON() {
validProfiles, invalidProfiles, err := config.ListProfiles()
validProfiles, invalidProfiles, err := listProfiles()
updateProfilesStatus(validProfiles)
@ -195,5 +213,6 @@ func profilesOrDefault(profiles []*config.Profile) []*config.Profile {
func init() {
profileListCmd.Flags().StringVarP(&output, "output", "o", "table", "The output format. One of 'json', 'table'")
profileListCmd.Flags().BoolVarP(&isLight, "light", "l", false, "If true, returns list of profiles faster by skipping validating the status of the cluster.")
ProfileCmd.AddCommand(profileListCmd)
}

View File

@ -17,12 +17,14 @@ limitations under the License.
package cmd
import (
"context"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"time"
"github.com/docker/machine/libmachine/mcnerror"
"github.com/mitchellh/go-ps"
@ -94,7 +96,7 @@ func init() {
}
// shotgun cleanup to delete orphaned docker container data
func deleteContainersAndVolumes(ociBin string) {
func deleteContainersAndVolumes(ctx context.Context, ociBin string) {
if _, err := exec.LookPath(ociBin); err != nil {
klog.Infof("skipping deleteContainersAndVolumes for %s: %v", ociBin, err)
return
@ -108,7 +110,7 @@ func deleteContainersAndVolumes(ociBin string) {
klog.Infof("error delete containers by label %q (might be okay): %+v", delLabel, errs)
}
errs = oci.DeleteAllVolumesByLabel(ociBin, delLabel)
errs = oci.DeleteAllVolumesByLabel(ctx, ociBin, delLabel)
if len(errs) > 0 { // it will not error if there is nothing to delete
klog.Warningf("error delete volumes by label %q (might be okay): %+v", delLabel, errs)
}
@ -118,7 +120,7 @@ func deleteContainersAndVolumes(ociBin string) {
return
}
errs = oci.PruneAllVolumesByLabel(ociBin, delLabel)
errs = oci.PruneAllVolumesByLabel(ctx, ociBin, delLabel)
if len(errs) > 0 { // it will not error if there is nothing to delete
klog.Warningf("error pruning volumes by label %q (might be okay): %+v", delLabel, errs)
}
@ -146,10 +148,12 @@ func runDelete(cmd *cobra.Command, args []string) {
}
exit.Message(reason.Usage, "Usage: minikube delete --all --purge")
}
delCtx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
if deleteAll {
deleteContainersAndVolumes(oci.Docker)
deleteContainersAndVolumes(oci.Podman)
deleteContainersAndVolumes(delCtx, oci.Docker)
deleteContainersAndVolumes(delCtx, oci.Podman)
errs := DeleteProfiles(profilesToDelete)
register.Reg.SetStep(register.Done)
@ -182,8 +186,8 @@ func runDelete(cmd *cobra.Command, args []string) {
if orphan {
// TODO: generalize for non-KIC drivers: #8040
deletePossibleKicLeftOver(cname, driver.Docker)
deletePossibleKicLeftOver(cname, driver.Podman)
deletePossibleKicLeftOver(delCtx, cname, driver.Docker)
deletePossibleKicLeftOver(delCtx, cname, driver.Podman)
}
}
@ -206,7 +210,9 @@ func DeleteProfiles(profiles []*config.Profile) []error {
klog.Infof("DeleteProfiles")
var errs []error
for _, profile := range profiles {
err := deleteProfile(profile)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
err := deleteProfile(ctx, profile)
if err != nil {
mm, loadErr := machine.LoadMachine(profile.Name)
@ -224,7 +230,7 @@ func DeleteProfiles(profiles []*config.Profile) []error {
}
// TODO: remove and/or move to delete package: #8040
func deletePossibleKicLeftOver(cname string, driverName string) {
func deletePossibleKicLeftOver(ctx context.Context, cname string, driverName string) {
bin := ""
switch driverName {
case driver.Docker:
@ -241,13 +247,12 @@ func deletePossibleKicLeftOver(cname string, driverName string) {
}
klog.Infof("deleting possible KIC leftovers for %s (driver=%s) ...", cname, driverName)
delLabel := fmt.Sprintf("%s=%s", oci.ProfileLabelKey, cname)
cs, err := oci.ListContainersByLabel(bin, delLabel)
cs, err := oci.ListContainersByLabel(ctx, bin, delLabel)
if err == nil && len(cs) > 0 {
for _, c := range cs {
out.Step(style.DeletingHost, `Deleting container "{{.name}}" ...`, out.V{"name": cname})
err := oci.DeleteContainer(bin, c)
err := oci.DeleteContainer(ctx, bin, c)
if err != nil { // it will error if there is no container to delete
klog.Errorf("error deleting container %q. You may want to delete it manually :\n%v", cname, err)
}
@ -255,11 +260,27 @@ func deletePossibleKicLeftOver(cname string, driverName string) {
}
}
errs := oci.DeleteAllVolumesByLabel(bin, delLabel)
if bin == oci.Podman {
// podman volume does not support --filter
err := oci.RemoveVolume(bin, cname)
if err != nil {
klog.Warningf("error deleting volume %s (might be okay).'\n:%v", cname, err)
}
}
errs := oci.DeleteAllVolumesByLabel(ctx, bin, delLabel)
if errs != nil { // it will not error if there is nothing to delete
klog.Warningf("error deleting volumes (might be okay).\nTo see the list of volumes run: 'docker volume ls'\n:%v", errs)
}
if bin == oci.Podman {
// podman network does not support --filter
err := oci.RemoveNetwork(bin, cname)
if err != nil {
klog.Warningf("error deleting network %s (might be okay).'\n:%v", cname, err)
}
}
errs = oci.DeleteKICNetworks(bin)
if errs != nil {
klog.Warningf("error deleting leftover networks (might be okay).\nTo see the list of networks: 'docker network ls'\n:%v", errs)
@ -270,13 +291,13 @@ func deletePossibleKicLeftOver(cname string, driverName string) {
return
}
errs = oci.PruneAllVolumesByLabel(bin, delLabel)
errs = oci.PruneAllVolumesByLabel(ctx, bin, delLabel)
if len(errs) > 0 { // it will not error if there is nothing to delete
klog.Warningf("error pruning volume (might be okay):\n%v", errs)
}
}
func deleteProfile(profile *config.Profile) error {
func deleteProfile(ctx context.Context, profile *config.Profile) error {
klog.Infof("Deleting %s", profile.Name)
register.Reg.SetStep(register.Deleting)
@ -289,7 +310,7 @@ func deleteProfile(profile *config.Profile) error {
out.Step(style.DeletingHost, `Deleting "{{.profile_name}}" in {{.driver_name}} ...`, out.V{"profile_name": profile.Name, "driver_name": profile.Config.Driver})
for _, n := range profile.Config.Nodes {
machineName := config.MachineName(*profile.Config, n)
deletePossibleKicLeftOver(machineName, profile.Config.Driver)
deletePossibleKicLeftOver(ctx, machineName, profile.Config.Driver)
}
}
} else {

View File

@ -17,6 +17,9 @@ limitations under the License.
package cmd
import (
"context"
"time"
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
@ -48,7 +51,9 @@ var nodeDeleteCmd = &cobra.Command{
if driver.IsKIC(co.Config.Driver) {
machineName := config.MachineName(*co.Config, *n)
deletePossibleKicLeftOver(machineName, co.Config.Driver)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
deletePossibleKicLeftOver(ctx, machineName, co.Config.Driver)
}
out.Step(style.Deleted, "Node {{.name}} was successfully deleted.", out.V{"name": name})

View File

@ -17,6 +17,7 @@ limitations under the License.
package cmd
import (
"context"
"encoding/json"
"fmt"
"math"
@ -130,7 +131,7 @@ func platform() string {
// runStart handles the executes the flow of "minikube start"
func runStart(cmd *cobra.Command, args []string) {
register.SetEventLogPath(localpath.EventLog(ClusterFlagValue()))
ctx := context.Background()
out.SetJSON(outputFormat == "json")
if err := pkgtrace.Initialize(viper.GetString(trace)); err != nil {
exit.Message(reason.Usage, "error initializing tracing: {{.Error}}", out.V{"Error": err.Error()})
@ -219,7 +220,7 @@ func runStart(cmd *cobra.Command, args []string) {
klog.Warningf("%s profile does not exist, trying anyways.", ClusterFlagValue())
}
err = deleteProfile(profile)
err = deleteProfile(ctx, profile)
if err != nil {
out.WarningT("Failed to delete cluster {{.name}}, proceeding with retry anyway.", out.V{"name": ClusterFlagValue()})
}
@ -252,17 +253,6 @@ func runStart(cmd *cobra.Command, args []string) {
})
}
}
if existing.KubernetesConfig.ContainerRuntime == "crio" {
// Stop and start again if it's crio because it's broken above v1.17.3
out.WarningT("Due to issues with CRI-O post v1.17.3, we need to restart your cluster.")
out.WarningT("See details at https://github.com/kubernetes/minikube/issues/8861")
stopProfile(existing.Name)
starter, err = provisionWithDriver(cmd, ds, existing)
if err != nil {
exitGuestProvision(err)
}
}
}
kubeconfig, err := startWithDriver(cmd, starter, existing)
@ -482,7 +472,7 @@ func maybeDeleteAndRetry(cmd *cobra.Command, existing config.ClusterConfig, n co
out.ErrT(style.Meh, `"{{.name}}" profile does not exist, trying anyways.`, out.V{"name": existing.Name})
}
err = deleteProfile(profile)
err = deleteProfile(context.Background(), profile)
if err != nil {
out.WarningT("Failed to delete cluster {{.name}}, proceeding with retry anyway.", out.V{"name": existing.Name})
}
@ -573,7 +563,7 @@ func selectDriver(existing *config.ClusterConfig) (registry.DriverState, []regis
}
ds := driver.Status(d)
if ds.Name == "" {
exit.Message(reason.DrvUnsupportedOS, "The driver '{{.driver}}' is not supported on {{.os}}", out.V{"driver": d, "os": runtime.GOOS})
exit.Message(reason.DrvUnsupportedOS, "The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}", out.V{"driver": d, "os": runtime.GOOS, "arch": runtime.GOARCH})
}
out.Step(style.Sparkle, `Using the {{.driver}} driver based on user configuration`, out.V{"driver": ds.String()})
return ds, nil, true
@ -583,7 +573,7 @@ func selectDriver(existing *config.ClusterConfig) (registry.DriverState, []regis
if d := viper.GetString("vm-driver"); d != "" {
ds := driver.Status(viper.GetString("vm-driver"))
if ds.Name == "" {
exit.Message(reason.DrvUnsupportedOS, "The driver '{{.driver}}' is not supported on {{.os}}", out.V{"driver": d, "os": runtime.GOOS})
exit.Message(reason.DrvUnsupportedOS, "The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}", out.V{"driver": d, "os": runtime.GOOS, "arch": runtime.GOARCH})
}
out.Step(style.Sparkle, `Using the {{.driver}} driver based on user configuration`, out.V{"driver": ds.String()})
return ds, nil, true
@ -697,7 +687,7 @@ func validateSpecifiedDriver(existing *config.ClusterConfig) {
out.ErrT(style.Meh, `"{{.name}}" profile does not exist, trying anyways.`, out.V{"name": existing.Name})
}
err = deleteProfile(profile)
err = deleteProfile(context.Background(), profile)
if err != nil {
out.WarningT("Failed to delete cluster {{.name}}.", out.V{"name": existing.Name})
}
@ -722,7 +712,7 @@ func validateDriver(ds registry.DriverState, existing *config.ClusterConfig) {
name := ds.Name
klog.Infof("validating driver %q against %+v", name, existing)
if !driver.Supported(name) {
exit.Message(reason.DrvUnsupportedOS, "The driver '{{.driver}}' is not supported on {{.os}}", out.V{"driver": name, "os": runtime.GOOS})
exit.Message(reason.DrvUnsupportedOS, "The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}", out.V{"driver": name, "os": runtime.GOOS, "arch": runtime.GOARCH})
}
// if we are only downloading artifacts for a driver, we can stop validation here
@ -995,7 +985,7 @@ func validateRequestedMemorySize(req int, drvName string) {
}
}
// validateCPUCount validates the cpu count matches the minimum recommended
// validateCPUCount validates the cpu count matches the minimum recommended & not exceeding the available cpu count
func validateCPUCount(drvName string) {
var cpuCount int
if driver.BareMetal(drvName) {
@ -1029,6 +1019,22 @@ func validateCPUCount(drvName string) {
}
if si.CPUs < cpuCount {
if driver.IsDockerDesktop(drvName) {
out.Step(style.Empty, `- Ensure your {{.driver_name}} daemon has access to enough CPU/memory resources.`, out.V{"driver_name": drvName})
if runtime.GOOS == "darwin" {
out.Step(style.Empty, `- Docs https://docs.docker.com/docker-for-mac/#resources`, out.V{"driver_name": drvName})
}
if runtime.GOOS == "windows" {
out.String("\n\t")
out.Step(style.Empty, `- Docs https://docs.docker.com/docker-for-windows/#resources`, out.V{"driver_name": drvName})
}
}
exitIfNotForced(reason.RsrcInsufficientCores, "Requested cpu count {{.requested_cpus}} is greater than the available cpus of {{.avail_cpus}}", out.V{"requested_cpus": cpuCount, "avail_cpus": si.CPUs})
}
// looks good
if si.CPUs >= 2 {
return

View File

@ -56,7 +56,7 @@ COPY entrypoint /usr/local/bin/entrypoint
RUN echo "Ensuring scripts are executable ..." \
&& chmod +x /usr/local/bin/clean-install /usr/local/bin/entrypoint \
&& echo "Installing Packages ..." \
&& DEBIAN_FRONTEND=noninteractive clean-install \
&& DEBIAN_FRONTEND=noninteractive /bin/bash clean-install \
systemd \
conntrack iptables iproute2 ethtool socat util-linux mount ebtables udev kmod \
libseccomp2 pigz \

View File

@ -55,6 +55,11 @@ env BUILD_IN_DOCKER=y \
"out/docker-machine-driver-kvm2_${DEB_VERSION}-0_amd64.deb" \
"out/docker-machine-driver-kvm2-${RPM_VERSION}-0.x86_64.rpm"
# Don't upload temporary copies, avoid unused duplicate files in the release storage
rm -f out/minikube-linux-x86_64
rm -f out/minikube-linux-aarch64
rm -f out/minikube-windows-amd64
make checksum
# unversioned names to avoid updating upstream Kubernetes documentation each release

View File

@ -72,6 +72,7 @@ func NewDriver(c Config) *Driver {
// Create a host using the driver's config
func (d *Driver) Create() error {
ctx := context.Background()
params := oci.CreateParams{
Mounts: d.NodeConfig.Mounts,
Name: d.NodeConfig.MachineName,
@ -136,7 +137,7 @@ func (d *Driver) Create() error {
// if container was created by minikube it is safe to delete and recreate it.
if oci.IsCreatedByMinikube(d.OCIBinary, params.Name) {
klog.Info("Found already existing abandoned minikube container, will try to delete.")
if err := oci.DeleteContainer(d.OCIBinary, params.Name); err != nil {
if err := oci.DeleteContainer(ctx, d.OCIBinary, params.Name); err != nil {
klog.Errorf("Failed to delete a conflicting minikube container %s. You might need to restart your %s daemon and delete it manually and try again: %v", params.Name, params.OCIBinary, err)
}
} else {
@ -338,7 +339,7 @@ func (d *Driver) Remove() error {
klog.Infof("could not find the container %s to remove it. will try anyways", d.MachineName)
}
if err := oci.DeleteContainer(d.NodeConfig.OCIBinary, d.MachineName); err != nil {
if err := oci.DeleteContainer(context.Background(), d.NodeConfig.OCIBinary, d.MachineName); err != nil {
if strings.Contains(err.Error(), "is already in progress") {
return errors.Wrap(err, "stuck delete")
}

View File

@ -54,6 +54,9 @@ var ErrDaemonInfo = errors.New("daemon info not responding")
// ErrInsufficientDockerStorage is thrown when there is not more storage for docker
var ErrInsufficientDockerStorage = &FailFastError{errors.New("insufficient docker storage, no space left on device")}
// ErrVolumeNotFound is when given volume was not found
var ErrVolumeNotFound = errors.New("kic volume not found")
// ErrNetworkSubnetTaken is thrown when a subnet is taken by another network
var ErrNetworkSubnetTaken = errors.New("subnet is taken")

View File

@ -43,8 +43,8 @@ import (
// if there no containers found with the given label, it will return nil
func DeleteContainersByLabel(ociBin string, label string) []error {
var deleteErrs []error
cs, err := ListContainersByLabel(ociBin, label)
ctx := context.Background()
cs, err := ListContainersByLabel(ctx, ociBin, label)
if err != nil {
return []error{fmt.Errorf("listing containers by label %q", label)}
}
@ -75,7 +75,7 @@ func DeleteContainersByLabel(ociBin string, label string) []error {
}
// DeleteContainer deletes a container by ID or Name
func DeleteContainer(ociBin string, name string) error {
func DeleteContainer(ctx context.Context, ociBin string, name string) error {
_, err := ContainerStatus(ociBin, name)
if err == context.DeadlineExceeded {
out.WarningT("{{.ocibin}} is taking an unsually long time to respond, consider restarting {{.ocibin}}", out.V{"ociBin": ociBin})
@ -87,7 +87,7 @@ func DeleteContainer(ociBin string, name string) error {
klog.Infof("couldn't shut down %s (might be okay): %v ", name, err)
}
if _, err := runCmd(exec.Command(ociBin, "rm", "-f", "-v", name)); err != nil {
if _, err := runCmd(exec.CommandContext(ctx, ociBin, "rm", "-f", "-v", name)); err != nil {
return errors.Wrapf(err, "delete %s", name)
}
return nil
@ -373,7 +373,7 @@ func IsCreatedByMinikube(ociBin string, nameOrID string) bool {
// ListOwnedContainers lists all the containres that kic driver created on user's machine using a label
func ListOwnedContainers(ociBin string) ([]string, error) {
return ListContainersByLabel(ociBin, ProfileLabelKey)
return ListContainersByLabel(context.Background(), ociBin, ProfileLabelKey)
}
// inspect return low-level information on containers
@ -503,8 +503,8 @@ func withPortMappings(portMappings []PortMapping) createOpt {
}
// ListContainersByLabel returns all the container names with a specified label
func ListContainersByLabel(ociBin string, label string, warnSlow ...bool) ([]string, error) {
rr, err := runCmd(exec.Command(ociBin, "ps", "-a", "--filter", fmt.Sprintf("label=%s", label), "--format", "{{.Names}}"), warnSlow...)
func ListContainersByLabel(ctx context.Context, ociBin string, label string, warnSlow ...bool) ([]string, error) {
rr, err := runCmd(exec.CommandContext(ctx, ociBin, "ps", "-a", "--filter", fmt.Sprintf("label=%s", label), "--format", "{{.Names}}"), warnSlow...)
if err != nil {
return nil, err
}

View File

@ -19,6 +19,8 @@ package oci
import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"os/exec"
"runtime"
@ -29,9 +31,50 @@ import (
"k8s.io/klog/v2"
)
// RemoveVolume removes a volume
func RemoveVolume(ociBin string, name string) error {
if !volumeExists(ociBin, name) {
return nil
}
rr, err := runCmd(exec.Command(ociBin, "volume", "rm", name))
if err != nil {
if strings.Contains(rr.Output(), "No such volume") ||
strings.Contains(rr.Output(), "no such volume") {
return ErrVolumeNotFound
}
}
return err
}
func volumeExists(ociBin string, name string) bool {
_, err := containerVolumeInspect(ociBin, name)
if err != nil && !errors.Is(err, ErrVolumeNotFound) { // log unexpected error
klog.Warningf("Error inspecting docker volume %s: %v", name, err)
}
return err == nil
}
func containerVolumeInspect(ociBin string, name string) (interface{}, error) {
var info interface{}
cmd := exec.Command(ociBin, "volume", "inspect", name)
rr, err := runCmd(cmd)
if err != nil {
if strings.Contains(rr.Output(), "No such volume") ||
strings.Contains(rr.Output(), "no such volume") {
return info, ErrVolumeNotFound
}
return info, err
}
err = json.Unmarshal(rr.Stdout.Bytes(), &info)
return info, err
}
// DeleteAllVolumesByLabel deletes all volumes that have a specific label
// if there is no volume to delete it will return nil
func DeleteAllVolumesByLabel(ociBin string, label string, warnSlow ...bool) []error {
func DeleteAllVolumesByLabel(ctx context.Context, ociBin string, label string, warnSlow ...bool) []error {
var deleteErrs []error
klog.Infof("trying to delete all %s volumes with label %s", ociBin, label)
@ -42,7 +85,7 @@ func DeleteAllVolumesByLabel(ociBin string, label string, warnSlow ...bool) []er
}
for _, v := range vs {
if _, err := runCmd(exec.Command(ociBin, "volume", "rm", "--force", v), warnSlow...); err != nil {
if _, err := runCmd(exec.CommandContext(ctx, ociBin, "volume", "rm", "--force", v), warnSlow...); err != nil {
deleteErrs = append(deleteErrs, fmt.Errorf("deleting %q", v))
}
}
@ -53,10 +96,10 @@ func DeleteAllVolumesByLabel(ociBin string, label string, warnSlow ...bool) []er
// PruneAllVolumesByLabel deletes all volumes that have a specific label
// if there is no volume to delete it will return nil
// example: docker volume prune -f --filter label=name.minikube.sigs.k8s.io=minikube
func PruneAllVolumesByLabel(ociBin string, label string, warnSlow ...bool) []error {
func PruneAllVolumesByLabel(ctx context.Context, ociBin string, label string, warnSlow ...bool) []error {
var deleteErrs []error
klog.Infof("trying to prune all %s volumes with label %s", ociBin, label)
cmd := exec.Command(ociBin, "volume", "prune", "-f", "--filter", "label="+label)
cmd := exec.CommandContext(ctx, ociBin, "volume", "prune", "-f", "--filter", "label="+label)
if _, err := runCmd(cmd, warnSlow...); err != nil {
deleteErrs = append(deleteErrs, errors.Wrapf(err, "prune volume by label %s", label))
}

View File

@ -18,6 +18,7 @@ package ssh
import (
"fmt"
"io/ioutil"
"net"
"os"
"os/exec"
@ -25,6 +26,8 @@ import (
"strconv"
"time"
"golang.org/x/crypto/ssh"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/log"
@ -106,6 +109,16 @@ func (d *Driver) PreCreateCheck() error {
if _, err := os.Stat(d.SSHKey); os.IsNotExist(err) {
return fmt.Errorf("SSH key does not exist: %q", d.SSHKey)
}
key, err := ioutil.ReadFile(d.SSHKey)
if err != nil {
return err
}
_, err = ssh.ParsePrivateKey(key)
if err != nil {
return errors.Wrapf(err, "SSH key does not parse: %q", d.SSHKey)
}
}
return nil

View File

@ -46,7 +46,7 @@ var (
// NoWaitComponents is map of componets to wait for if specified 'none' or 'false'
NoComponents = map[string]bool{APIServerWaitKey: false, SystemPodsWaitKey: false, DefaultSAWaitKey: false, AppsRunningKey: false, NodeReadyKey: false, KubeletKey: false}
// AllComponents is map for waiting for all components.
AllComponents = map[string]bool{APIServerWaitKey: true, SystemPodsWaitKey: true, DefaultSAWaitKey: true, AppsRunningKey: true, KubeletKey: true}
AllComponents = map[string]bool{APIServerWaitKey: true, SystemPodsWaitKey: true, DefaultSAWaitKey: true, AppsRunningKey: true, NodeReadyKey: true, KubeletKey: true}
// DefaultWaitList is list of all default components to wait for. only names to be used for start flags.
DefaultWaitList = []string{APIServerWaitKey, SystemPodsWaitKey}
// AllComponentsList list of all valid components keys to wait for. only names to be used used for start flags.

View File

@ -147,3 +147,19 @@ func KindNet(repo string) string {
}
return path.Join(repo, "kindnetd:0.5.4")
}
// CalicoDaemonSet returns the image used for calicoDaemonSet
func CalicoDaemonSet(repo string) string {
if repo == "" {
repo = "calico"
}
return path.Join(repo, "node:v3.14.1")
}
// CalicoDeployment returns the image used for calicoDeployment
func CalicoDeployment(repo string) string {
if repo == "" {
repo = "calico"
}
return path.Join(repo, "kube-controllers:v3.14.1")
}

View File

@ -17,11 +17,17 @@ limitations under the License.
package cni
import (
"bytes"
"text/template"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
"k8s.io/minikube/pkg/minikube/config"
)
// calicoTmpl is from https://docs.projectcalico.org/manifests/calico.yaml
var calicoTmpl = `---
var calicoTmpl = template.Must(template.New("calico").Parse(`---
# Source: calico/templates/calico-config.yaml
# This ConfigMap is used to configure a self-hosted Calico installation.
kind: ConfigMap
@ -649,7 +655,7 @@ spec:
# container programs network policy and routes on each
# host.
- name: calico-node
image: calico/node:v3.14.1
image: {{ .DaemonSetImageName }}
env:
# Use Kubernetes API as the backing datastore.
- name: DATASTORE_TYPE
@ -834,7 +840,7 @@ spec:
priorityClassName: system-cluster-critical
containers:
- name: calico-kube-controllers
image: calico/kube-controllers:v3.14.1
image: {{ .DeploymentImageName }}
env:
# Choose which controllers to run.
- name: ENABLED_CONTROLLERS
@ -864,21 +870,44 @@ metadata:
---
# Source: calico/templates/configure-canal.yaml
`
`))
// Calico is the Calico CNI manager
type Calico struct {
cc config.ClusterConfig
}
type calicoTmplStruct struct {
DeploymentImageName string
DaemonSetImageName string
}
// String returns a string representation of this CNI
func (c Calico) String() string {
return "Calico"
}
// manifest returns a Kubernetes manifest for a CNI
func (c Calico) manifest() (assets.CopyableFile, error) {
input := &calicoTmplStruct{
DeploymentImageName: images.CalicoDeployment(c.cc.KubernetesConfig.ImageRepository),
DaemonSetImageName: images.CalicoDaemonSet(c.cc.KubernetesConfig.ImageRepository),
}
b := bytes.Buffer{}
if err := calicoTmpl.Execute(&b, input); err != nil {
return nil, err
}
return manifestAsset(b.Bytes()), nil
}
// Apply enables the CNI
func (c Calico) Apply(r Runner) error {
return applyManifest(c.cc, r, manifestAsset([]byte(calicoTmpl)))
m, err := c.manifest()
if err != nil {
return errors.Wrap(err, "manifest")
}
return applyManifest(c.cc, r, m)
}
// CIDR returns the default CIDR used by this CNI

View File

@ -16,18 +16,30 @@ limitations under the License.
package driver
import "os/exec"
import (
"os/exec"
"runtime"
)
// supportedDrivers is a list of supported drivers on Darwin.
var supportedDrivers = []string{
VirtualBox,
Parallels,
VMwareFusion,
HyperKit,
VMware,
Docker,
SSH,
}
var supportedDrivers []string = func() []string {
if runtime.GOARCH == "arm64" {
// on darwin/arm64 only docker and ssh are supported yet
return []string{
Docker,
SSH,
}
}
return []string{
VirtualBox,
Parallels,
VMwareFusion,
HyperKit,
VMware,
Docker,
SSH,
}
}()
func VBoxManagePath() string {
cmd := "VBoxManage"

View File

@ -86,8 +86,10 @@ func TestCheckDockerVersion(t *testing.T) {
for _, c := range tc {
t.Run("checkDockerVersion test", func(t *testing.T) {
s := checkDockerVersion(c.version)
if c.expect != s.Reason {
t.Errorf("Error %v expected. but got %q. (version string : %s)", c.expect, s.Reason, c.version)
if s.Error != nil {
if c.expect != s.Reason {
t.Errorf("Error %v expected. but got %q. (version string : %s)", c.expect, s.Reason, c.version)
}
}
})
}

View File

@ -20,6 +20,7 @@ import (
"bufio"
"net"
"os"
"path/filepath"
"strconv"
"time"
@ -28,6 +29,7 @@ import (
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/knownhosts"
"k8s.io/client-go/util/homedir"
"k8s.io/klog/v2"
"k8s.io/minikube/pkg/util/retry"
@ -40,9 +42,12 @@ func NewSSHClient(d drivers.Driver) (*ssh.Client, error) {
return nil, errors.Wrap(err, "Error creating new ssh host from driver")
}
defaultKeyPath := filepath.Join(homedir.HomeDir(), ".ssh", "id_rsa")
auth := &machinessh.Auth{}
if h.SSHKeyPath != "" {
auth.Keys = []string{h.SSHKeyPath}
} else {
auth.Keys = []string{defaultKeyPath}
}
klog.Infof("new ssh client: %+v", h)

View File

@ -89,6 +89,7 @@ minikube profile list [flags]
### Options
```
-l, --light If true, returns list of profiles faster by skipping validating the status of the cluster.
-o, --output string The output format. One of 'json', 'table' (default "table")
```

View File

@ -25,7 +25,7 @@ All you need is Docker (or similarly compatible) container or a Virtual Machine
For Linux users, we provide 3 easy download options (for each architecture):
### x86
### amd64 / x86_64
#### Binary download
@ -49,7 +49,7 @@ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-latest
sudo rpm -ivh minikube-latest.x86_64.rpm
```
### ARM
### arm64 / aarch64
#### Binary download
@ -81,10 +81,10 @@ If the [Brew Package Manager](https://brew.sh/) installed:
brew install minikube
```
If `which minikube` fails after installation via brew, you may have to remove the minikube cask and link the binary:
If `which minikube` fails after installation via brew, you may have to remove the old minikube links and link the newly installed binary:
```shell
brew cask remove minikube
brew unlink minikube
brew link minikube
```

View File

@ -164,6 +164,9 @@ func validateLoadImage(ctx context.Context, t *testing.T, profile string) {
if NoneDriver() {
t.Skip("load image not available on none driver")
}
if GithubActionRunner() && runtime.GOOS == "darwin" {
t.Skip("skipping on github actions and darwin, as this test requires a running docker daemon")
}
defer PostMortemLogs(t, profile)
// pull busybox
busybox := "busybox:latest"
@ -811,50 +814,98 @@ func validateProfileCmd(ctx context.Context, t *testing.T, profile string) {
})
t.Run("profile_list", func(t *testing.T) {
// helper function to run command then, return target profile line from table output.
extractrofileListFunc := func(rr *RunResult) string {
listLines := strings.Split(strings.TrimSpace(rr.Stdout.String()), "\n")
for i := 3; i < (len(listLines) - 1); i++ {
profileLine := listLines[i]
if strings.Contains(profileLine, profile) {
return profileLine
}
}
return ""
}
// List profiles
start := time.Now()
rr, err := Run(t, exec.CommandContext(ctx, Target(), "profile", "list"))
elapsed := time.Since(start)
if err != nil {
t.Errorf("failed to list profiles: args %q : %v", rr.Command(), err)
}
t.Logf("Took %q to run %q", elapsed, rr.Command())
// Table output
listLines := strings.Split(strings.TrimSpace(rr.Stdout.String()), "\n")
profileExists := false
for i := 3; i < (len(listLines) - 1); i++ {
profileLine := listLines[i]
if strings.Contains(profileLine, profile) {
profileExists = true
break
}
}
if !profileExists {
profileLine := extractrofileListFunc(rr)
if profileLine == "" {
t.Errorf("expected 'profile list' output to include %q but got *%q*. args: %q", profile, rr.Stdout.String(), rr.Command())
}
// List profiles with light option.
start = time.Now()
lrr, err := Run(t, exec.CommandContext(ctx, Target(), "profile", "list", "-l"))
lightElapsed := time.Since(start)
if err != nil {
t.Errorf("failed to list profiles: args %q : %v", lrr.Command(), err)
}
t.Logf("Took %q to run %q", lightElapsed, lrr.Command())
profileLine = extractrofileListFunc(lrr)
if profileLine == "" || !strings.Contains(profileLine, "Skipped") {
t.Errorf("expected 'profile list' output to include %q with 'Skipped' status but got *%q*. args: %q", profile, rr.Stdout.String(), rr.Command())
}
if lightElapsed > 3*time.Second {
t.Errorf("expected running time of '%q' is less than 3 seconds. Took %q ", lrr.Command(), lightElapsed)
}
})
t.Run("profile_json_output", func(t *testing.T) {
// Json output
rr, err := Run(t, exec.CommandContext(ctx, Target(), "profile", "list", "--output", "json"))
// helper function to run command then, return target profile object from json output.
extractProfileObjFunc := func(rr *RunResult) *config.Profile {
var jsonObject map[string][]config.Profile
err := json.Unmarshal(rr.Stdout.Bytes(), &jsonObject)
if err != nil {
t.Errorf("failed to decode json from profile list: args %q: %v", rr.Command(), err)
return nil
}
for _, profileObject := range jsonObject["valid"] {
if profileObject.Name == profile {
return &profileObject
}
}
return nil
}
start := time.Now()
rr, err := Run(t, exec.CommandContext(ctx, Target(), "profile", "list", "-o", "json"))
elapsed := time.Since(start)
if err != nil {
t.Errorf("failed to list profiles with json format. args %q: %v", rr.Command(), err)
}
var jsonObject map[string][]map[string]interface{}
err = json.Unmarshal(rr.Stdout.Bytes(), &jsonObject)
if err != nil {
t.Errorf("failed to decode json from profile list: args %q: %v", rr.Command(), err)
}
validProfiles := jsonObject["valid"]
profileExists := false
for _, profileObject := range validProfiles {
if profileObject["Name"] == profile {
profileExists = true
break
}
}
if !profileExists {
t.Logf("Took %q to run %q", elapsed, rr.Command())
pr := extractProfileObjFunc(rr)
if pr == nil {
t.Errorf("expected the json of 'profile list' to include %q but got *%q*. args: %q", profile, rr.Stdout.String(), rr.Command())
}
start = time.Now()
lrr, err := Run(t, exec.CommandContext(ctx, Target(), "profile", "list", "-o", "json", "--light"))
lightElapsed := time.Since(start)
if err != nil {
t.Errorf("failed to list profiles with json format. args %q: %v", lrr.Command(), err)
}
t.Logf("Took %q to run %q", lightElapsed, lrr.Command())
pr = extractProfileObjFunc(lrr)
if pr == nil || pr.Status != "Skipped" {
t.Errorf("expected the json of 'profile list' to include 'Skipped' status for %q but got *%q*. args: %q", profile, lrr.Stdout.String(), lrr.Command())
}
if lightElapsed > 3*time.Second {
t.Errorf("expected running time of '%q' is less than 3 seconds. Took %q ", lrr.Command(), lightElapsed)
}
})
}

View File

@ -92,31 +92,16 @@ func TestNetworkPlugins(t *testing.T) {
}
if !t.Failed() {
t.Run("KubeletFlags", func(t *testing.T) {
var rr *RunResult
var err error
// none does not support 'minikube ssh'
rr, err := Run(t, exec.CommandContext(ctx, Target(), "ssh", "-p", profile, "pgrep -a kubelet"))
if NoneDriver() {
rr, err = Run(t, exec.CommandContext(ctx, "pgrep", "-a", "kubelet"))
} else {
rr, err = Run(t, exec.CommandContext(ctx, Target(), "ssh", "-p", profile, "pgrep -a kubelet"))
}
if err != nil {
t.Fatalf("ssh failed: %v", err)
}
out := rr.Stdout.String()
if tc.kubeletPlugin == "" {
if strings.Contains(out, "--network-plugin") {
t.Errorf("expected no network plug-in, got %s", out)
}
} else {
if !strings.Contains(out, fmt.Sprintf("--network-plugin=%s", tc.kubeletPlugin)) {
t.Errorf("expected --network-plugin=%s, got %s", tc.kubeletPlugin, out)
}
}
verifyKubeletFlagsOutput(t, tc.kubeletPlugin, out)
})
}
@ -206,3 +191,16 @@ func TestNetworkPlugins(t *testing.T) {
}
})
}
func verifyKubeletFlagsOutput(t *testing.T, kubeletPlugin, out string) {
if kubeletPlugin == "" {
if strings.Contains(out, "--network-plugin") && ContainerRuntime() == "docker" {
t.Errorf("expected no network plug-in, got %s", out)
}
if !strings.Contains(out, "--network-plugin=cni") && ContainerRuntime() != "docker" {
t.Errorf("expected cni network plugin with conatinerd/crio, got %s", out)
}
} else if !strings.Contains(out, fmt.Sprintf("--network-plugin=%s", kubeletPlugin)) {
t.Errorf("expected --network-plugin=%s, got %s", kubeletPlugin, out)
}
}

View File

@ -510,7 +510,7 @@
"The cri socket path to be used.": "",
"The docker-env command is incompatible with multi-node clusters. Use the 'registry' add-on: https://minikube.sigs.k8s.io/docs/handbook/registry/": "",
"The docker-env command is only compatible with the \"docker\" runtime, but this cluster was configured to use the \"{{.runtime}}\" runtime.": "",
"The driver '{{.driver}}' is not supported on {{.os}}": "Der Treiber '{{.driver}}' wird auf {{.os}} nicht unterstützt",
"The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}": "Der Treiber '{{.driver}}' wird auf {{.os}}/{{.arch}} nicht unterstützt",
"The existing \"{{.name}}\" cluster was created using the \"{{.old}}\" driver, which is incompatible with requested \"{{.new}}\" driver.": "",
"The existing node configuration appears to be corrupt. Run 'minikube delete'": "",
"The heapster addon is depreciated. please try to disable metrics-server instead": "",

View File

@ -511,7 +511,7 @@
"The cri socket path to be used.": "",
"The docker-env command is incompatible with multi-node clusters. Use the 'registry' add-on: https://minikube.sigs.k8s.io/docs/handbook/registry/": "",
"The docker-env command is only compatible with the \"docker\" runtime, but this cluster was configured to use the \"{{.runtime}}\" runtime.": "",
"The driver '{{.driver}}' is not supported on {{.os}}": "El controlador \"{{.driver}}\" no se puede utilizar en {{.os}}",
"The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}": "El controlador \"{{.driver}}\" no se puede utilizar en {{.os}}/{{.arch}}",
"The existing \"{{.name}}\" cluster was created using the \"{{.old}}\" driver, which is incompatible with requested \"{{.new}}\" driver.": "",
"The existing node configuration appears to be corrupt. Run 'minikube delete'": "",
"The heapster addon is depreciated. please try to disable metrics-server instead": "",

View File

@ -513,7 +513,7 @@
"The cri socket path to be used.": "",
"The docker-env command is incompatible with multi-node clusters. Use the 'registry' add-on: https://minikube.sigs.k8s.io/docs/handbook/registry/": "",
"The docker-env command is only compatible with the \"docker\" runtime, but this cluster was configured to use the \"{{.runtime}}\" runtime.": "",
"The driver '{{.driver}}' is not supported on {{.os}}": "Le pilote \"{{.driver}}\" n'est pas compatible avec {{.os}}.",
"The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}": "Le pilote \"{{.driver}}\" n'est pas compatible avec {{.os}}/{{.arch}}.",
"The existing \"{{.name}}\" cluster was created using the \"{{.old}}\" driver, which is incompatible with requested \"{{.new}}\" driver.": "",
"The existing node configuration appears to be corrupt. Run 'minikube delete'": "",
"The heapster addon is depreciated. please try to disable metrics-server instead": "",

View File

@ -507,7 +507,7 @@
"The cri socket path to be used.": "",
"The docker-env command is incompatible with multi-node clusters. Use the 'registry' add-on: https://minikube.sigs.k8s.io/docs/handbook/registry/": "",
"The docker-env command is only compatible with the \"docker\" runtime, but this cluster was configured to use the \"{{.runtime}}\" runtime.": "",
"The driver '{{.driver}}' is not supported on {{.os}}": "ドライバ「{{.driver}}」は、{{.os}} ではサポートされていません",
"The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}": "ドライバ「{{.driver}}」は、{{.os}}/{{.arch}} ではサポートされていません",
"The existing \"{{.name}}\" cluster was created using the \"{{.old}}\" driver, which is incompatible with requested \"{{.new}}\" driver.": "",
"The existing node configuration appears to be corrupt. Run 'minikube delete'": "",
"The heapster addon is depreciated. please try to disable metrics-server instead": "",

View File

@ -480,7 +480,7 @@
"The cri socket path to be used.": "",
"The docker-env command is incompatible with multi-node clusters. Use the 'registry' add-on: https://minikube.sigs.k8s.io/docs/handbook/registry/": "",
"The docker-env command is only compatible with the \"docker\" runtime, but this cluster was configured to use the \"{{.runtime}}\" runtime.": "",
"The driver '{{.driver}}' is not supported on {{.os}}": "",
"The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}": "",
"The existing \"{{.name}}\" cluster was created using the \"{{.old}}\" driver, which is incompatible with requested \"{{.new}}\" driver.": "",
"The heapster addon is depreciated. please try to disable metrics-server instead": "",
"The hyperv virtual switch name. Defaults to first found. (hyperv driver only)": "",

View File

@ -524,7 +524,7 @@
"The docker service is currently not active": "Serwis docker jest nieaktywny",
"The docker-env command is incompatible with multi-node clusters. Use the 'registry' add-on: https://minikube.sigs.k8s.io/docs/handbook/registry/": "",
"The docker-env command is only compatible with the \"docker\" runtime, but this cluster was configured to use the \"{{.runtime}}\" runtime.": "",
"The driver '{{.driver}}' is not supported on {{.os}}": "Sterownik '{{.driver}} jest niewspierany przez system {{.os}}",
"The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}": "Sterownik '{{.driver}} jest niewspierany przez system {{.os}}/{{.arch}}",
"The existing \"{{.name}}\" cluster was created using the \"{{.old}}\" driver, which is incompatible with requested \"{{.new}}\" driver.": "",
"The existing node configuration appears to be corrupt. Run 'minikube delete'": "",
"The heapster addon is depreciated. please try to disable metrics-server instead": "",

View File

@ -426,7 +426,7 @@
"The cri socket path to be used.": "",
"The docker-env command is incompatible with multi-node clusters. Use the 'registry' add-on: https://minikube.sigs.k8s.io/docs/handbook/registry/": "",
"The docker-env command is only compatible with the \"docker\" runtime, but this cluster was configured to use the \"{{.runtime}}\" runtime.": "",
"The driver '{{.driver}}' is not supported on {{.os}}": "",
"The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}": "",
"The existing \"{{.name}}\" cluster was created using the \"{{.old}}\" driver, which is incompatible with requested \"{{.new}}\" driver.": "",
"The heapster addon is depreciated. please try to disable metrics-server instead": "",
"The hyperv virtual switch name. Defaults to first found. (hyperv driver only)": "",

View File

@ -613,7 +613,7 @@
"The cri socket path to be used.": "",
"The docker-env command is incompatible with multi-node clusters. Use the 'registry' add-on: https://minikube.sigs.k8s.io/docs/handbook/registry/": "",
"The docker-env command is only compatible with the \"docker\" runtime, but this cluster was configured to use the \"{{.runtime}}\" runtime.": "",
"The driver '{{.driver}}' is not supported on {{.os}}": "{{.os}} 不支持驱动程序“{{.driver}}”",
"The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}": "{{.os}} 不支持驱动程序“{{.driver}}/{{.arch}}”",
"The existing \"{{.name}}\" cluster was created using the \"{{.old}}\" driver, which is incompatible with requested \"{{.new}}\" driver.": "",
"The existing node configuration appears to be corrupt. Run 'minikube delete'": "",
"The heapster addon is depreciated. please try to disable metrics-server instead": "",