Skip to content

Commit ef14596

Browse files
authored
Merge pull request #16925 from spowelljr/downloadKubeadm
Get image version from kubeadm
2 parents 50c6418 + 8e57ad8 commit ef14596

File tree

2 files changed

+32
-74
lines changed

2 files changed

+32
-74
lines changed

pkg/minikube/bootstrapper/images/images.go

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,30 @@ limitations under the License.
1818
package images
1919

2020
import (
21-
"encoding/json"
2221
"fmt"
23-
"io"
24-
"net/http"
22+
"os/exec"
2523
"path"
24+
"runtime"
25+
"strings"
2626

2727
"k8s.io/klog/v2"
2828

2929
"k8s.io/minikube/pkg/minikube/constants"
30+
"k8s.io/minikube/pkg/minikube/download"
3031

3132
"github.com/blang/semver/v4"
3233

3334
"k8s.io/minikube/pkg/version"
3435
)
3536

36-
const (
37-
// builds a docker v2 repository API call in the format https://registry.k8s.io/v2/coredns/coredns/tags/list
38-
tagURLTemplate = "https://%s/v2/%s/tags/list"
39-
)
40-
4137
// Pause returns the image name to pull for a given Kubernetes version
4238
func Pause(v semver.Version, mirror string) string {
4339
// Note: changing this logic requires bumping the preload version
4440
// Should match `PauseVersion` in:
4541
// https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/constants/constants.go
4642
// https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/constants/constants_unix.go
4743
imageName := "pause"
48-
pv := imageVersion(v, mirror, imageName, "3.6")
44+
pv := imageVersion(v, imageName, "3.9")
4945

5046
return fmt.Sprintf("%s:%s", path.Join(kubernetesRepo(mirror), imageName), pv)
5147
}
@@ -70,38 +66,36 @@ func componentImage(name string, v semver.Version, mirror string) string {
7066
return fmt.Sprintf("%s:v%s", path.Join(kubernetesRepo(mirror), name), v)
7167
}
7268

73-
// fixes 13136 by getting the latest image version from the registry.k8s.io repository instead of hardcoded
74-
func findLatestTagFromRepository(url string, lastKnownGood string) string {
75-
client := &http.Client{}
76-
errorMsg := fmt.Sprintf("Failed to get latest image version for %s, reverting to version %s.", url, lastKnownGood)
77-
78-
resp, err := client.Get(url)
79-
80-
if err != nil || resp.StatusCode != http.StatusOK {
81-
klog.Warningf("%s Error %v", errorMsg, err)
69+
func tagFromKubeadm(v, name, lastKnownGood string) string {
70+
if runtime.GOOS != "linux" {
71+
klog.Warningf("can only get tag from kubeadm on Linux")
8272
return lastKnownGood
8373
}
84-
defer resp.Body.Close()
85-
86-
body, err := io.ReadAll(resp.Body)
74+
kubeadm, err := download.Binary("kubeadm", v, "linux", runtime.GOARCH, "")
8775
if err != nil {
88-
klog.Warningf("%s Error %v", errorMsg, err)
76+
klog.Warningf("failed to download kubeadm binary: %v", err)
8977
return lastKnownGood
9078
}
91-
92-
type TagsResponse struct {
93-
Name string `json:"name"`
94-
Tags []string `json:"tags"`
95-
}
96-
97-
tags := TagsResponse{}
98-
err = json.Unmarshal(body, &tags)
99-
if err != nil || len(tags.Tags) < 1 {
100-
klog.Warningf("%s Error %v", errorMsg, err)
79+
// TODO: Once kubeadm graduates the "-experimental-output" flag to non-experimental should use JSON output here
80+
b, err := exec.Command(kubeadm, "config", "images", "list").Output()
81+
if err != nil {
82+
klog.Warningf("failed getting kubeadm image list: %v", err)
10183
return lastKnownGood
10284
}
103-
lastTagNum := len(tags.Tags) - 1
104-
return tags.Tags[lastTagNum]
85+
lines := strings.Split(string(b), "\n")
86+
for _, line := range lines {
87+
if !strings.Contains(line, name) {
88+
continue
89+
}
90+
parts := strings.Split(line, ":")
91+
if len(parts) != 2 {
92+
klog.Warningf("unexpected image format: %s", line)
93+
return lastKnownGood
94+
}
95+
return parts[1]
96+
}
97+
klog.Warningf("failed to find %q image in kubeadm image list", name)
98+
return lastKnownGood
10599
}
106100

107101
// coreDNS returns the images used for CoreDNS
@@ -114,7 +108,7 @@ func coreDNS(v semver.Version, mirror string) string {
114108
if semver.MustParseRange("<1.21.0-alpha.1")(v) {
115109
imageName = "coredns"
116110
}
117-
cv := imageVersion(v, mirror, imageName, "v1.8.6")
111+
cv := imageVersion(v, imageName, "v1.10.1")
118112

119113
if mirror == constants.AliyunMirror {
120114
imageName = "coredns"
@@ -129,17 +123,17 @@ func etcd(v semver.Version, mirror string) string {
129123
// Should match `DefaultEtcdVersion` in:
130124
// https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/constants/constants.go
131125
imageName := "etcd"
132-
ev := imageVersion(v, mirror, imageName, "3.5.0-0")
126+
ev := imageVersion(v, imageName, "3.5.7-0")
133127

134128
return fmt.Sprintf("%s:%s", path.Join(kubernetesRepo(mirror), imageName), ev)
135129
}
136130

137-
func imageVersion(v semver.Version, mirror, imageName, defaultVersion string) string {
131+
func imageVersion(v semver.Version, imageName, defaultVersion string) string {
138132
versionString := fmt.Sprintf("v%s", v.String())
139133
if ver, ok := constants.KubeadmImages[versionString][imageName]; ok {
140134
return ver
141135
}
142-
return findLatestTagFromRepository(fmt.Sprintf(tagURLTemplate, kubernetesRepo(mirror), imageName), defaultVersion)
136+
return tagFromKubeadm(versionString, imageName, defaultVersion)
143137
}
144138

145139
// auxiliary returns images that are helpful for running minikube

pkg/minikube/bootstrapper/images/images_test.go

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ limitations under the License.
1717
package images
1818

1919
import (
20-
"net/http"
21-
"net/http/httptest"
2220
"strings"
2321
"testing"
2422

@@ -93,40 +91,6 @@ registry.k8s.io/coredns/coredns:v1.8.4
9391
}
9492
}
9593

96-
func TestGetLatestTag(t *testing.T) {
97-
serverResp := "{tags: [\"1.8.7\"]}"
98-
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
99-
w.WriteHeader(http.StatusOK)
100-
_, err := w.Write([]byte(serverResp))
101-
if err != nil {
102-
t.Errorf("failed to write https response")
103-
}
104-
}))
105-
defer server.Close()
106-
107-
var testCases = []struct {
108-
name string
109-
url string
110-
lastKnownGood string
111-
wsResponse string
112-
expect string
113-
}{
114-
{name: "VersionGetSuccess", url: server.URL, lastKnownGood: "v1.8.6", wsResponse: `{"name": "coredns", "tags": ["v1.8.9"]}`, expect: "v1.8.9"},
115-
{name: "VersionGetFail", url: server.URL, lastKnownGood: "v1.8.6", wsResponse: `{"name": "nah", "nope": ["v1.8.9"]}`, expect: "v1.8.6"},
116-
{name: "VersionGetFailNone", url: server.URL, lastKnownGood: "v1.8.6", wsResponse: ``, expect: "v1.8.6"},
117-
{name: "VersionGetSuccessMultiple", url: server.URL, lastKnownGood: "v1.8.6", wsResponse: `{"name": "coredns", "tags": ["1.8.7","v1.8.9"]}`, expect: "v1.8.9"},
118-
}
119-
for _, tc := range testCases {
120-
t.Run(tc.name, func(t *testing.T) {
121-
serverResp = tc.wsResponse
122-
resp := findLatestTagFromRepository(tc.url, tc.lastKnownGood)
123-
if diff := cmp.Diff(tc.expect, resp); diff != "" {
124-
t.Errorf("Incorrect response version (-want +got):\n%s", diff)
125-
}
126-
})
127-
}
128-
}
129-
13094
func TestEssentialsAliyunMirror(t *testing.T) {
13195
var testCases = []struct {
13296
version string

0 commit comments

Comments
 (0)