Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix downloading the wrong kubeadm images for k8s versions after minikube release #17373

Merged
merged 2 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 30 additions & 15 deletions pkg/minikube/bootstrapper/images/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ import (
"runtime"
"strings"

"k8s.io/klog/v2"

"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/download"

Expand Down Expand Up @@ -66,21 +64,19 @@ func componentImage(name string, v semver.Version, mirror string) string {
return fmt.Sprintf("%s:v%s", path.Join(kubernetesRepo(mirror), name), v)
}

func tagFromKubeadm(v, name, lastKnownGood string) string {
// tagFromKubeadm gets the image tag by running kubeadm image list command on the host machine (Linux only)
func tagFromKubeadm(v, name string) (string, error) {
if runtime.GOOS != "linux" {
klog.Warningf("can only get tag from kubeadm on Linux")
return lastKnownGood
return "", fmt.Errorf("can only get tag from kubeadm on Linux")
}
kubeadm, err := download.Binary("kubeadm", v, "linux", runtime.GOARCH, "")
if err != nil {
klog.Warningf("failed to download kubeadm binary: %v", err)
return lastKnownGood
return "", fmt.Errorf("failed to download kubeadm binary: %v", err)
}
// TODO: Once kubeadm graduates the "-experimental-output" flag to non-experimental should use JSON output here
b, err := exec.Command(kubeadm, "config", "images", "list").Output()
if err != nil {
klog.Warningf("failed getting kubeadm image list: %v", err)
return lastKnownGood
return "", fmt.Errorf("failed getting kubeadm image list: %v", err)
}
lines := strings.Split(string(b), "\n")
for _, line := range lines {
Expand All @@ -89,13 +85,29 @@ func tagFromKubeadm(v, name, lastKnownGood string) string {
}
parts := strings.Split(line, ":")
if len(parts) != 2 {
klog.Warningf("unexpected image format: %s", line)
return lastKnownGood
return "", fmt.Errorf("unexpected image format: %s", line)
}
return parts[1]
return parts[1], nil
}
klog.Warningf("failed to find %q image in kubeadm image list", name)
return lastKnownGood
return "", fmt.Errorf("failed to find %q image in kubeadm image list", name)
}

// tagFromLastMinor finds the last matching minor version in the kubeadm images map and uses its image version
func tagFromLastMinor(v semver.Version, name, lastKnownGood string) string {
majorMinor := fmt.Sprintf("v%d.%d", v.Major, v.Minor)
var latestMinorVer string
for _, existingVer := range constants.ValidKubernetesVersions {
if !strings.HasPrefix(existingVer, majorMinor) {
continue
}
latestMinorVer = existingVer
break
}
tag, ok := constants.KubeadmImages[latestMinorVer][name]
if !ok {
return lastKnownGood
}
return tag
}

// coreDNS returns the images used for CoreDNS
Expand Down Expand Up @@ -133,7 +145,10 @@ func imageVersion(v semver.Version, imageName, defaultVersion string) string {
if ver, ok := constants.KubeadmImages[versionString][imageName]; ok {
return ver
}
return tagFromKubeadm(versionString, imageName, defaultVersion)
if ver, err := tagFromKubeadm(versionString, imageName); err == nil {
return ver
}
return tagFromLastMinor(v, imageName, defaultVersion)
}

// auxiliary returns images that are helpful for running minikube
Expand Down
25 changes: 25 additions & 0 deletions pkg/minikube/bootstrapper/images/images_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,28 @@ func TestCNI(t *testing.T) {
})
}
}

func TestTagFromLastMinor(t *testing.T) {
tests := []struct {
verString string
imageName string
expectedTag string
}{
{"1.16.50", "coredns", "1.6.2"},
{"1.16.50", "etcd", "3.3.15-0"},
{"1.16.50", "pause", "3.1"},
{"1.16.50", "fake", "default"},
}

for _, tc := range tests {
v, err := semver.Parse(tc.verString)
if err != nil {
t.Errorf("failed to parse version to semver: %v", err)
continue
}
got := tagFromLastMinor(v, tc.imageName, "default")
if tc.expectedTag != got {
t.Errorf("tagFromLastMinor(%s, %s, default) = %s; want = %s", tc.verString, tc.imageName, got, tc.expectedTag)
}
}
}
Loading