From 7d0ccc24ecf5a9869e27b61b13a471d73384653e Mon Sep 17 00:00:00 2001 From: Steven Powell Date: Thu, 20 Jul 2023 15:49:10 -0700 Subject: [PATCH] get image version from kubeadm --- pkg/minikube/bootstrapper/images/images.go | 69 +++++++++---------- .../bootstrapper/images/images_test.go | 36 ---------- 2 files changed, 31 insertions(+), 74 deletions(-) diff --git a/pkg/minikube/bootstrapper/images/images.go b/pkg/minikube/bootstrapper/images/images.go index b093fccf99..c02cd2e24b 100644 --- a/pkg/minikube/bootstrapper/images/images.go +++ b/pkg/minikube/bootstrapper/images/images.go @@ -18,26 +18,22 @@ limitations under the License. package images import ( - "encoding/json" "fmt" - "io" - "net/http" + "os/exec" "path" + "runtime" + "strings" "k8s.io/klog/v2" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/download" "github.com/blang/semver/v4" "k8s.io/minikube/pkg/version" ) -const ( - // builds a docker v2 repository API call in the format https://registry.k8s.io/v2/coredns/coredns/tags/list - tagURLTemplate = "https://%s/v2/%s/tags/list" -) - // Pause returns the image name to pull for a given Kubernetes version func Pause(v semver.Version, mirror string) string { // Note: changing this logic requires bumping the preload version @@ -45,7 +41,7 @@ func Pause(v semver.Version, mirror string) string { // https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/constants/constants.go // https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/constants/constants_unix.go imageName := "pause" - pv := imageVersion(v, mirror, imageName, "3.6") + pv := imageVersion(v, imageName, "3.9") return fmt.Sprintf("%s:%s", path.Join(kubernetesRepo(mirror), imageName), pv) } @@ -70,38 +66,35 @@ func componentImage(name string, v semver.Version, mirror string) string { return fmt.Sprintf("%s:v%s", path.Join(kubernetesRepo(mirror), name), v) } -// fixes 13136 by getting the latest image version from the registry.k8s.io repository instead of hardcoded -func findLatestTagFromRepository(url string, lastKnownGood string) string { - client := &http.Client{} - errorMsg := fmt.Sprintf("Failed to get latest image version for %s, reverting to version %s.", url, lastKnownGood) - - resp, err := client.Get(url) - - if err != nil || resp.StatusCode != http.StatusOK { - klog.Warningf("%s Error %v", errorMsg, err) +func tagFromKubeadm(v, name, lastKnownGood string) string { + if runtime.GOOS != "linux" { + klog.Warningf("can only get tag from kubeadm on Linux") return lastKnownGood } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) + kubeadm, err := download.Binary("kubeadm", v, "linux", runtime.GOARCH, "") if err != nil { - klog.Warningf("%s Error %v", errorMsg, err) + klog.Warningf("failed to download kubeadm binary: %v", err) return lastKnownGood } - - type TagsResponse struct { - Name string `json:"name"` - Tags []string `json:"tags"` - } - - tags := TagsResponse{} - err = json.Unmarshal(body, &tags) - if err != nil || len(tags.Tags) < 1 { - klog.Warningf("%s Error %v", errorMsg, err) + b, err := exec.Command(kubeadm, "config", "images", "list").Output() + if err != nil { + klog.Warningf("failed getting kubeadm image list: %v", err) return lastKnownGood } - lastTagNum := len(tags.Tags) - 1 - return tags.Tags[lastTagNum] + lines := strings.Split(string(b), "\n") + for _, line := range lines { + if !strings.Contains(line, name) { + continue + } + parts := strings.Split(line, ":") + if len(parts) != 2 { + klog.Warningf("unexpected image format: %s", line) + return lastKnownGood + } + return parts[1] + } + klog.Warningf("failed to find %q image in kubeadm image list", name) + return lastKnownGood } // coreDNS returns the images used for CoreDNS @@ -114,7 +107,7 @@ func coreDNS(v semver.Version, mirror string) string { if semver.MustParseRange("<1.21.0-alpha.1")(v) { imageName = "coredns" } - cv := imageVersion(v, mirror, imageName, "v1.8.6") + cv := imageVersion(v, imageName, "v1.10.1") if mirror == constants.AliyunMirror { imageName = "coredns" @@ -129,17 +122,17 @@ func etcd(v semver.Version, mirror string) string { // Should match `DefaultEtcdVersion` in: // https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/constants/constants.go imageName := "etcd" - ev := imageVersion(v, mirror, imageName, "3.5.0-0") + ev := imageVersion(v, imageName, "3.5.7-0") return fmt.Sprintf("%s:%s", path.Join(kubernetesRepo(mirror), imageName), ev) } -func imageVersion(v semver.Version, mirror, imageName, defaultVersion string) string { +func imageVersion(v semver.Version, imageName, defaultVersion string) string { versionString := fmt.Sprintf("v%s", v.String()) if ver, ok := constants.KubeadmImages[versionString][imageName]; ok { return ver } - return findLatestTagFromRepository(fmt.Sprintf(tagURLTemplate, kubernetesRepo(mirror), imageName), defaultVersion) + return tagFromKubeadm(versionString, imageName, defaultVersion) } // auxiliary returns images that are helpful for running minikube diff --git a/pkg/minikube/bootstrapper/images/images_test.go b/pkg/minikube/bootstrapper/images/images_test.go index 96d97fa4d9..ba2d05e7fa 100644 --- a/pkg/minikube/bootstrapper/images/images_test.go +++ b/pkg/minikube/bootstrapper/images/images_test.go @@ -17,8 +17,6 @@ limitations under the License. package images import ( - "net/http" - "net/http/httptest" "strings" "testing" @@ -93,40 +91,6 @@ registry.k8s.io/coredns/coredns:v1.8.4 } } -func TestGetLatestTag(t *testing.T) { - serverResp := "{tags: [\"1.8.7\"]}" - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - _, err := w.Write([]byte(serverResp)) - if err != nil { - t.Errorf("failed to write https response") - } - })) - defer server.Close() - - var testCases = []struct { - name string - url string - lastKnownGood string - wsResponse string - expect string - }{ - {name: "VersionGetSuccess", url: server.URL, lastKnownGood: "v1.8.6", wsResponse: `{"name": "coredns", "tags": ["v1.8.9"]}`, expect: "v1.8.9"}, - {name: "VersionGetFail", url: server.URL, lastKnownGood: "v1.8.6", wsResponse: `{"name": "nah", "nope": ["v1.8.9"]}`, expect: "v1.8.6"}, - {name: "VersionGetFailNone", url: server.URL, lastKnownGood: "v1.8.6", wsResponse: ``, expect: "v1.8.6"}, - {name: "VersionGetSuccessMultiple", url: server.URL, lastKnownGood: "v1.8.6", wsResponse: `{"name": "coredns", "tags": ["1.8.7","v1.8.9"]}`, expect: "v1.8.9"}, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - serverResp = tc.wsResponse - resp := findLatestTagFromRepository(tc.url, tc.lastKnownGood) - if diff := cmp.Diff(tc.expect, resp); diff != "" { - t.Errorf("Incorrect response version (-want +got):\n%s", diff) - } - }) - } -} - func TestEssentialsAliyunMirror(t *testing.T) { var testCases = []struct { version string