get image version from kubeadm

pull/16925/head
Steven Powell 2023-07-20 15:49:10 -07:00
parent 56e816767a
commit 7d0ccc24ec
2 changed files with 31 additions and 74 deletions

View File

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

View File

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