Merge branch 'kubernetes:master' into Hyperkit-StaticWarning
commit
6d7f04ebfd
|
|
@ -13,7 +13,7 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||||
- name: Install bom
|
- name: Install bom
|
||||||
uses: kubernetes-sigs/release-actions/setup-bom@a30d93cf2aa029e1e4c8a6c79f766aebf429fddb # main
|
uses: kubernetes-sigs/release-actions/setup-bom@8af7b2a5596dff526de9db59b2c4b8457e9f52a1 # main
|
||||||
- name: Generage SBOM
|
- name: Generage SBOM
|
||||||
run: |
|
run: |
|
||||||
bom generate -o minikube_${{github.ref_name}}_sbom.spdx \
|
bom generate -o minikube_${{github.ref_name}}_sbom.spdx \
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -70,7 +70,7 @@ gsutil.cmd -m cp -r gs://minikube-builds/$env:MINIKUBE_LOCATION/installers/check
|
||||||
|
|
||||||
# Download gopogh and gotestsum
|
# Download gopogh and gotestsum
|
||||||
go install github.com/medyagh/gopogh/cmd/gopogh@v0.29.0
|
go install github.com/medyagh/gopogh/cmd/gopogh@v0.29.0
|
||||||
go install gotest.tools/gotestsum@v1.12.3
|
go install gotest.tools/gotestsum@v1.13.0
|
||||||
# temporary: remove the old install of gopogh & gotestsum as it's taking priority over our current install, preventing updating
|
# temporary: remove the old install of gopogh & gotestsum as it's taking priority over our current install, preventing updating
|
||||||
if (Test-Path "C:\Go") {
|
if (Test-Path "C:\Go") {
|
||||||
Remove-Item "C:\Go" -Recurse -Force
|
Remove-Item "C:\Go" -Recurse -Force
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
set -eux -o pipefail
|
set -eux -o pipefail
|
||||||
|
|
||||||
GH_VERSION="2.78.0"
|
GH_VERSION="2.80.0"
|
||||||
|
|
||||||
echo "Installing latest version of gh"
|
echo "Installing latest version of gh"
|
||||||
curl -qLO "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_amd64.tar.gz"
|
curl -qLO "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_amd64.tar.gz"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ set -eux -o pipefail
|
||||||
|
|
||||||
function install_gotestsum() {
|
function install_gotestsum() {
|
||||||
rm -f $(which gotestsum)
|
rm -f $(which gotestsum)
|
||||||
GOBIN="$GOROOT/bin" go install gotest.tools/gotestsum@v1.12.3
|
GOBIN="$GOROOT/bin" go install gotest.tools/gotestsum@v1.13.0
|
||||||
}
|
}
|
||||||
|
|
||||||
which gotestsum || install_gotestsum
|
which gotestsum || install_gotestsum
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,14 @@ type interfaceInfo struct {
|
||||||
// The returned error.Kind can be used to provide a suggestion for resolving the
|
// The returned error.Kind can be used to provide a suggestion for resolving the
|
||||||
// issue.
|
// issue.
|
||||||
func ValidateHelper() error {
|
func ValidateHelper() error {
|
||||||
|
// Ideally minikube will not try to validate in download-only mode, but this
|
||||||
|
// is called from different places in different drivers, so the easier way
|
||||||
|
// to skip validation is to skip it here.
|
||||||
|
if viper.GetBool("download-only") {
|
||||||
|
log.Debug("Skipping vmnet-helper validation in download-only mode")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Is it installed?
|
// Is it installed?
|
||||||
if _, err := os.Stat(executablePath); err != nil {
|
if _, err := os.Stat(executablePath); err != nil {
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,7 @@ var Addons = map[string]*Addon{
|
||||||
"0640"),
|
"0640"),
|
||||||
}, false, "kong", "3rd party (Kong HQ)", "@gAmUssA", "https://minikube.sigs.k8s.io/docs/handbook/addons/kong-ingress/", map[string]string{
|
}, false, "kong", "3rd party (Kong HQ)", "@gAmUssA", "https://minikube.sigs.k8s.io/docs/handbook/addons/kong-ingress/", map[string]string{
|
||||||
"Kong": "kong:3.9.1@sha256:14c689c0caf1b8da1403a742016ec64d2f5b5b12ecdec2989f36b2c2c4aa1ac0",
|
"Kong": "kong:3.9.1@sha256:14c689c0caf1b8da1403a742016ec64d2f5b5b12ecdec2989f36b2c2c4aa1ac0",
|
||||||
"KongIngress": "kong/kubernetes-ingress-controller:3.5.1@sha256:4dc74b6fd7bcea07196900b53b6e1d5fabf6b7e56a7ed5d786e0d1c0ab950d1d",
|
"KongIngress": "kong/kubernetes-ingress-controller:3.5.2@sha256:472012b0f7dca838f2b9cd8fcf6e6daeb2572631b37adb0dbb0770defeb89f04",
|
||||||
}, map[string]string{
|
}, map[string]string{
|
||||||
"Kong": "docker.io",
|
"Kong": "docker.io",
|
||||||
"KongIngress": "docker.io",
|
"KongIngress": "docker.io",
|
||||||
|
|
@ -580,9 +580,9 @@ var Addons = map[string]*Addon{
|
||||||
"volcano-deployment.yaml",
|
"volcano-deployment.yaml",
|
||||||
"0640"),
|
"0640"),
|
||||||
}, false, "volcano", "third-party (volcano)", "hwdef", "", map[string]string{
|
}, false, "volcano", "third-party (volcano)", "hwdef", "", map[string]string{
|
||||||
"vc_webhook_manager": "volcanosh/vc-webhook-manager:v1.12.2@sha256:b7c3bd73e2d9240cf17662451d50e0d73654342235a66cdfb2ec221f1628ae35",
|
"vc_webhook_manager": "volcanosh/vc-webhook-manager:v1.13.0@sha256:03e36eb220766397b4cd9c2f42bab8666661a0112fa9033ae9bd80d2a9611001",
|
||||||
"vc_controller_manager": "volcanosh/vc-controller-manager:v1.12.2@sha256:286112e70bdbf88174a66895bb3c64dd9026b5a762025b61bcd8f6cac04e1b90",
|
"vc_controller_manager": "volcanosh/vc-controller-manager:v1.13.0@sha256:8dd7ce0cef2df19afb14ba26bec90e2999a3c0397ebe5c9d75a5f68d1c80d242",
|
||||||
"vc_scheduler": "volcanosh/vc-scheduler:v1.12.2@sha256:6e28f0f79d4cd09c1c34afaba41623c1b4d0fd7087cc99d6449a8a62e073b50e",
|
"vc_scheduler": "volcanosh/vc-scheduler:v1.13.0@sha256:b05b30b3c25eff5af77e1859f47fc6acfc3520d62dc2838f0623aa4309c40b34",
|
||||||
}, map[string]string{
|
}, map[string]string{
|
||||||
"vc_webhook_manager": "docker.io",
|
"vc_webhook_manager": "docker.io",
|
||||||
"vc_controller_manager": "docker.io",
|
"vc_controller_manager": "docker.io",
|
||||||
|
|
@ -751,7 +751,7 @@ var Addons = map[string]*Addon{
|
||||||
MustBinAsset(addons.NvidiaDevicePlugin, "nvidia-device-plugin/nvidia-device-plugin.yaml.tmpl", vmpath.GuestAddonsDir, "nvidia-device-plugin.yaml", "0640"),
|
MustBinAsset(addons.NvidiaDevicePlugin, "nvidia-device-plugin/nvidia-device-plugin.yaml.tmpl", vmpath.GuestAddonsDir, "nvidia-device-plugin.yaml", "0640"),
|
||||||
}, false, "nvidia-device-plugin", "3rd party (NVIDIA)", "", "https://minikube.sigs.k8s.io/docs/tutorials/nvidia/",
|
}, false, "nvidia-device-plugin", "3rd party (NVIDIA)", "", "https://minikube.sigs.k8s.io/docs/tutorials/nvidia/",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"NvidiaDevicePlugin": "nvidia/k8s-device-plugin:v0.17.3@sha256:630596340f8e83aa10b0bc13a46db76772e31b7dccfc34d3a4e41ab7e0aa6117",
|
"NvidiaDevicePlugin": "nvidia/k8s-device-plugin:v0.17.4@sha256:3c54348fe5a57e5700e7d8068e7531d2ef2d5f3ccb70c8f6bac0953432527abd",
|
||||||
}, map[string]string{
|
}, map[string]string{
|
||||||
"NvidiaDevicePlugin": "nvcr.io",
|
"NvidiaDevicePlugin": "nvcr.io",
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -866,7 +866,7 @@ spec:
|
||||||
type: Unconfined
|
type: Unconfined
|
||||||
containers:
|
containers:
|
||||||
- name: cilium-agent
|
- name: cilium-agent
|
||||||
image: "quay.io/cilium/cilium:v1.18.1@sha256:65ab17c052d8758b2ad157ce766285e04173722df59bdee1ea6d5fda7149f0e9"
|
image: "quay.io/cilium/cilium:v1.18.2@sha256:858f807ea4e20e85e3ea3240a762e1f4b29f1cb5bbd0463b8aa77e7b097c0667"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
command:
|
command:
|
||||||
- cilium-agent
|
- cilium-agent
|
||||||
|
|
@ -1030,7 +1030,7 @@ spec:
|
||||||
|
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: config
|
- name: config
|
||||||
image: "quay.io/cilium/cilium:v1.18.1@sha256:65ab17c052d8758b2ad157ce766285e04173722df59bdee1ea6d5fda7149f0e9"
|
image: "quay.io/cilium/cilium:v1.18.2@sha256:858f807ea4e20e85e3ea3240a762e1f4b29f1cb5bbd0463b8aa77e7b097c0667"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
command:
|
command:
|
||||||
- cilium-dbg
|
- cilium-dbg
|
||||||
|
|
@ -1053,7 +1053,7 @@ spec:
|
||||||
# Required to mount cgroup2 filesystem on the underlying Kubernetes node.
|
# Required to mount cgroup2 filesystem on the underlying Kubernetes node.
|
||||||
# We use nsenter command with host's cgroup and mount namespaces enabled.
|
# We use nsenter command with host's cgroup and mount namespaces enabled.
|
||||||
- name: mount-cgroup
|
- name: mount-cgroup
|
||||||
image: "quay.io/cilium/cilium:v1.18.1@sha256:65ab17c052d8758b2ad157ce766285e04173722df59bdee1ea6d5fda7149f0e9"
|
image: "quay.io/cilium/cilium:v1.18.2@sha256:858f807ea4e20e85e3ea3240a762e1f4b29f1cb5bbd0463b8aa77e7b097c0667"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
env:
|
env:
|
||||||
- name: CGROUP_ROOT
|
- name: CGROUP_ROOT
|
||||||
|
|
@ -1090,7 +1090,7 @@ spec:
|
||||||
drop:
|
drop:
|
||||||
- ALL
|
- ALL
|
||||||
- name: apply-sysctl-overwrites
|
- name: apply-sysctl-overwrites
|
||||||
image: "quay.io/cilium/cilium:v1.18.1@sha256:65ab17c052d8758b2ad157ce766285e04173722df59bdee1ea6d5fda7149f0e9"
|
image: "quay.io/cilium/cilium:v1.18.2@sha256:858f807ea4e20e85e3ea3240a762e1f4b29f1cb5bbd0463b8aa77e7b097c0667"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
env:
|
env:
|
||||||
- name: BIN_PATH
|
- name: BIN_PATH
|
||||||
|
|
@ -1128,7 +1128,7 @@ spec:
|
||||||
# from a privileged container because the mount propagation bidirectional
|
# from a privileged container because the mount propagation bidirectional
|
||||||
# only works from privileged containers.
|
# only works from privileged containers.
|
||||||
- name: mount-bpf-fs
|
- name: mount-bpf-fs
|
||||||
image: "quay.io/cilium/cilium:v1.18.1@sha256:65ab17c052d8758b2ad157ce766285e04173722df59bdee1ea6d5fda7149f0e9"
|
image: "quay.io/cilium/cilium:v1.18.2@sha256:858f807ea4e20e85e3ea3240a762e1f4b29f1cb5bbd0463b8aa77e7b097c0667"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
args:
|
args:
|
||||||
- 'mount | grep "/sys/fs/bpf type bpf" || mount -t bpf bpf /sys/fs/bpf'
|
- 'mount | grep "/sys/fs/bpf type bpf" || mount -t bpf bpf /sys/fs/bpf'
|
||||||
|
|
@ -1144,7 +1144,7 @@ spec:
|
||||||
mountPath: /sys/fs/bpf
|
mountPath: /sys/fs/bpf
|
||||||
mountPropagation: Bidirectional
|
mountPropagation: Bidirectional
|
||||||
- name: clean-cilium-state
|
- name: clean-cilium-state
|
||||||
image: "quay.io/cilium/cilium:v1.18.1@sha256:65ab17c052d8758b2ad157ce766285e04173722df59bdee1ea6d5fda7149f0e9"
|
image: "quay.io/cilium/cilium:v1.18.2@sha256:858f807ea4e20e85e3ea3240a762e1f4b29f1cb5bbd0463b8aa77e7b097c0667"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
command:
|
command:
|
||||||
- /init-container.sh
|
- /init-container.sh
|
||||||
|
|
@ -1191,7 +1191,7 @@ spec:
|
||||||
mountPath: /var/run/cilium # wait-for-kube-proxy
|
mountPath: /var/run/cilium # wait-for-kube-proxy
|
||||||
# Install the CNI binaries in an InitContainer so we don't have a writable host mount in the agent
|
# Install the CNI binaries in an InitContainer so we don't have a writable host mount in the agent
|
||||||
- name: install-cni-binaries
|
- name: install-cni-binaries
|
||||||
image: "quay.io/cilium/cilium:v1.18.1@sha256:65ab17c052d8758b2ad157ce766285e04173722df59bdee1ea6d5fda7149f0e9"
|
image: "quay.io/cilium/cilium:v1.18.2@sha256:858f807ea4e20e85e3ea3240a762e1f4b29f1cb5bbd0463b8aa77e7b097c0667"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
command:
|
command:
|
||||||
- "/install-plugin.sh"
|
- "/install-plugin.sh"
|
||||||
|
|
@ -1216,6 +1216,7 @@ spec:
|
||||||
automountServiceAccountToken: true
|
automountServiceAccountToken: true
|
||||||
terminationGracePeriodSeconds: 1
|
terminationGracePeriodSeconds: 1
|
||||||
hostNetwork: true
|
hostNetwork: true
|
||||||
|
|
||||||
affinity:
|
affinity:
|
||||||
podAntiAffinity:
|
podAntiAffinity:
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
|
@ -1374,7 +1375,7 @@ spec:
|
||||||
type: Unconfined
|
type: Unconfined
|
||||||
containers:
|
containers:
|
||||||
- name: cilium-envoy
|
- name: cilium-envoy
|
||||||
image: "quay.io/cilium/cilium-envoy:v1.34.4-1754895458-68cffdfa568b6b226d70a7ef81fc65dda3b890bf@sha256:247e908700012f7ef56f75908f8c965215c26a27762f296068645eb55450bda2"
|
image: "quay.io/cilium/cilium-envoy:v1.34.7-1757592137-1a52bb680a956879722f48c591a2ca90f7791324@sha256:7932d656b63f6f866b6732099d33355184322123cfe1182e6f05175a3bc2e0e0"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
command:
|
command:
|
||||||
- /usr/bin/cilium-envoy-starter
|
- /usr/bin/cilium-envoy-starter
|
||||||
|
|
@ -1552,7 +1553,7 @@ spec:
|
||||||
type: RuntimeDefault
|
type: RuntimeDefault
|
||||||
containers:
|
containers:
|
||||||
- name: cilium-operator
|
- name: cilium-operator
|
||||||
image: "quay.io/cilium/operator-generic:v1.18.1@sha256:97f4553afa443465bdfbc1cc4927c93f16ac5d78e4dd2706736e7395382201bc"
|
image: "quay.io/cilium/operator-generic:v1.18.2@sha256:cb4e4ffc5789fd5ff6a534e3b1460623df61cba00f5ea1c7b40153b5efb81805"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
command:
|
command:
|
||||||
- cilium-operator-generic
|
- cilium-operator-generic
|
||||||
|
|
@ -1633,6 +1634,8 @@ spec:
|
||||||
operator: Exists
|
operator: Exists
|
||||||
- key: node.kubernetes.io/not-ready
|
- key: node.kubernetes.io/not-ready
|
||||||
operator: Exists
|
operator: Exists
|
||||||
|
- key: node.cloudprovider.kubernetes.io/uninitialized
|
||||||
|
operator: Exists
|
||||||
- key: node.cilium.io/agent-not-ready
|
- key: node.cilium.io/agent-not-ready
|
||||||
operator: Exists
|
operator: Exists
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ var (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultKubernetesVersion is the default Kubernetes version
|
// DefaultKubernetesVersion is the default Kubernetes version
|
||||||
DefaultKubernetesVersion = "v1.34.0"
|
DefaultKubernetesVersion = "v1.34.1"
|
||||||
// NewestKubernetesVersion is the newest Kubernetes version to test against
|
// NewestKubernetesVersion is the newest Kubernetes version to test against
|
||||||
// NOTE: You may need to update coreDNS & etcd versions in pkg/minikube/bootstrapper/images/images.go
|
// NOTE: You may need to update coreDNS & etcd versions in pkg/minikube/bootstrapper/images/images.go
|
||||||
NewestKubernetesVersion = "v1.34.0"
|
NewestKubernetesVersion = "v1.34.1"
|
||||||
// OldestKubernetesVersion is the oldest Kubernetes version to test against
|
// OldestKubernetesVersion is the oldest Kubernetes version to test against
|
||||||
// TODO: upodate to 6 releases before from DefaultKubernetesVersion
|
// TODO: upodate to 6 releases before from DefaultKubernetesVersion
|
||||||
OldestKubernetesVersion = "v1.28.0"
|
OldestKubernetesVersion = "v1.28.0"
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,26 @@ package constants
|
||||||
|
|
||||||
var (
|
var (
|
||||||
KubeadmImages = map[string]map[string]string{
|
KubeadmImages = map[string]map[string]string{
|
||||||
|
"v1.34.1": {
|
||||||
|
"coredns/coredns": "v1.12.1",
|
||||||
|
"etcd": "3.6.4-0",
|
||||||
|
"pause": "3.10.1",
|
||||||
|
},
|
||||||
|
"v1.33.5": {
|
||||||
|
"coredns/coredns": "v1.12.0",
|
||||||
|
"etcd": "3.5.21-0",
|
||||||
|
"pause": "3.10",
|
||||||
|
},
|
||||||
|
"v1.32.9": {
|
||||||
|
"coredns/coredns": "v1.11.3",
|
||||||
|
"etcd": "3.5.16-0",
|
||||||
|
"pause": "3.10",
|
||||||
|
},
|
||||||
|
"v1.31.13": {
|
||||||
|
"coredns/coredns": "v1.11.3",
|
||||||
|
"etcd": "3.5.15-0",
|
||||||
|
"pause": "3.10",
|
||||||
|
},
|
||||||
"v1.34.0": {
|
"v1.34.0": {
|
||||||
"coredns/coredns": "v1.12.1",
|
"coredns/coredns": "v1.12.1",
|
||||||
"etcd": "3.6.4-0",
|
"etcd": "3.6.4-0",
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ package constants
|
||||||
// ValidKubernetesVersions is a list of Kubernetes versions in order from newest to oldest
|
// ValidKubernetesVersions is a list of Kubernetes versions in order from newest to oldest
|
||||||
// This is used when outputting Kubernetes versions and to select the latest patch version when unspecified
|
// This is used when outputting Kubernetes versions and to select the latest patch version when unspecified
|
||||||
var ValidKubernetesVersions = []string{
|
var ValidKubernetesVersions = []string{
|
||||||
|
"v1.34.1",
|
||||||
"v1.34.0",
|
"v1.34.0",
|
||||||
"v1.34.0-rc.2",
|
"v1.34.0-rc.2",
|
||||||
"v1.34.0-rc.1",
|
"v1.34.0-rc.1",
|
||||||
|
|
@ -29,6 +30,7 @@ var ValidKubernetesVersions = []string{
|
||||||
"v1.34.0-alpha.3",
|
"v1.34.0-alpha.3",
|
||||||
"v1.34.0-alpha.2",
|
"v1.34.0-alpha.2",
|
||||||
"v1.34.0-alpha.1",
|
"v1.34.0-alpha.1",
|
||||||
|
"v1.33.5",
|
||||||
"v1.33.4",
|
"v1.33.4",
|
||||||
"v1.33.3",
|
"v1.33.3",
|
||||||
"v1.33.2",
|
"v1.33.2",
|
||||||
|
|
@ -40,6 +42,7 @@ var ValidKubernetesVersions = []string{
|
||||||
"v1.33.0-alpha.3",
|
"v1.33.0-alpha.3",
|
||||||
"v1.33.0-alpha.2",
|
"v1.33.0-alpha.2",
|
||||||
"v1.33.0-alpha.1",
|
"v1.33.0-alpha.1",
|
||||||
|
"v1.32.9",
|
||||||
"v1.32.8",
|
"v1.32.8",
|
||||||
"v1.32.7",
|
"v1.32.7",
|
||||||
"v1.32.6",
|
"v1.32.6",
|
||||||
|
|
@ -56,6 +59,7 @@ var ValidKubernetesVersions = []string{
|
||||||
"v1.32.0-alpha.3",
|
"v1.32.0-alpha.3",
|
||||||
"v1.32.0-alpha.2",
|
"v1.32.0-alpha.2",
|
||||||
"v1.32.0-alpha.1",
|
"v1.32.0-alpha.1",
|
||||||
|
"v1.31.13",
|
||||||
"v1.31.12",
|
"v1.31.12",
|
||||||
"v1.31.11",
|
"v1.31.11",
|
||||||
"v1.31.10",
|
"v1.31.10",
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
|
"k8s.io/minikube/pkg/minikube/localpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Force download tests to run in serial.
|
// Force download tests to run in serial.
|
||||||
|
|
@ -33,7 +34,6 @@ func TestDownload(t *testing.T) {
|
||||||
t.Run("PreloadDownloadPreventsMultipleDownload", testPreloadDownloadPreventsMultipleDownload)
|
t.Run("PreloadDownloadPreventsMultipleDownload", testPreloadDownloadPreventsMultipleDownload)
|
||||||
t.Run("ImageToCache", testImageToCache)
|
t.Run("ImageToCache", testImageToCache)
|
||||||
t.Run("PreloadNotExists", testPreloadNotExists)
|
t.Run("PreloadNotExists", testPreloadNotExists)
|
||||||
t.Run("PreloadChecksumMismatch", testPreloadChecksumMismatch)
|
|
||||||
t.Run("PreloadExistsCaching", testPreloadExistsCaching)
|
t.Run("PreloadExistsCaching", testPreloadExistsCaching)
|
||||||
t.Run("PreloadWithCachedSizeZero", testPreloadWithCachedSizeZero)
|
t.Run("PreloadWithCachedSizeZero", testPreloadWithCachedSizeZero)
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +48,31 @@ func mockSleepDownload(downloadsCounter *int) func(src, dst string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// point each subtest at an isolated MINIKUBE_HOME, pre-create the preload cache directory,
|
||||||
|
//
|
||||||
|
// and automatically restore the global download/preload mocks after each run.
|
||||||
|
// Applied the helper across all download-related tests
|
||||||
|
func setupTestMiniHome(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
tmpHome := t.TempDir()
|
||||||
|
t.Setenv(localpath.MinikubeHome, tmpHome)
|
||||||
|
if err := os.MkdirAll(targetDir(), 0o755); err != nil {
|
||||||
|
t.Fatalf("failed to create preload cache dir: %v", err)
|
||||||
|
}
|
||||||
|
origDownloadMock := DownloadMock
|
||||||
|
origCheckCache := checkCache
|
||||||
|
origCheckPreloadExists := checkPreloadExists
|
||||||
|
origGetChecksumGCS := getChecksumGCS
|
||||||
|
t.Cleanup(func() {
|
||||||
|
DownloadMock = origDownloadMock
|
||||||
|
checkCache = origCheckCache
|
||||||
|
checkPreloadExists = origCheckPreloadExists
|
||||||
|
getChecksumGCS = origGetChecksumGCS
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func testBinaryDownloadPreventsMultipleDownload(t *testing.T) {
|
func testBinaryDownloadPreventsMultipleDownload(t *testing.T) {
|
||||||
|
setupTestMiniHome(t)
|
||||||
downloadNum := 0
|
downloadNum := 0
|
||||||
DownloadMock = mockSleepDownload(&downloadNum)
|
DownloadMock = mockSleepDownload(&downloadNum)
|
||||||
|
|
||||||
|
|
@ -79,6 +103,8 @@ func testBinaryDownloadPreventsMultipleDownload(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPreloadDownloadPreventsMultipleDownload(t *testing.T) {
|
func testPreloadDownloadPreventsMultipleDownload(t *testing.T) {
|
||||||
|
setupTestMiniHome(t)
|
||||||
|
|
||||||
downloadNum := 0
|
downloadNum := 0
|
||||||
DownloadMock = mockSleepDownload(&downloadNum)
|
DownloadMock = mockSleepDownload(&downloadNum)
|
||||||
f, err := os.CreateTemp("", "preload")
|
f, err := os.CreateTemp("", "preload")
|
||||||
|
|
@ -97,8 +123,7 @@ func testPreloadDownloadPreventsMultipleDownload(t *testing.T) {
|
||||||
return os.Stat(f.Name())
|
return os.Stat(f.Name())
|
||||||
}
|
}
|
||||||
checkPreloadExists = func(_, _, _ string, _ ...bool) bool { return true }
|
checkPreloadExists = func(_, _, _ string, _ ...bool) bool { return true }
|
||||||
getChecksum = func(_, _ string) ([]byte, error) { return []byte("check"), nil }
|
getChecksumGCS = func(_, _ string) ([]byte, error) { return []byte("check"), nil }
|
||||||
ensureChecksumValid = func(_, _, _ string, _ []byte) error { return nil }
|
|
||||||
|
|
||||||
var group sync.WaitGroup
|
var group sync.WaitGroup
|
||||||
group.Add(2)
|
group.Add(2)
|
||||||
|
|
@ -120,13 +145,13 @@ func testPreloadDownloadPreventsMultipleDownload(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPreloadNotExists(t *testing.T) {
|
func testPreloadNotExists(t *testing.T) {
|
||||||
|
setupTestMiniHome(t)
|
||||||
downloadNum := 0
|
downloadNum := 0
|
||||||
DownloadMock = mockSleepDownload(&downloadNum)
|
DownloadMock = mockSleepDownload(&downloadNum)
|
||||||
|
|
||||||
checkCache = func(_ string) (fs.FileInfo, error) { return nil, fmt.Errorf("cache not found") }
|
checkCache = func(_ string) (fs.FileInfo, error) { return nil, fmt.Errorf("cache not found") }
|
||||||
checkPreloadExists = func(_, _, _ string, _ ...bool) bool { return false }
|
checkPreloadExists = func(_, _, _ string, _ ...bool) bool { return false }
|
||||||
getChecksum = func(_, _ string) ([]byte, error) { return []byte("check"), nil }
|
getChecksumGCS = func(_, _ string) ([]byte, error) { return []byte("check"), nil }
|
||||||
ensureChecksumValid = func(_, _, _ string, _ []byte) error { return nil }
|
|
||||||
|
|
||||||
err := Preload(constants.DefaultKubernetesVersion, constants.Docker, "docker")
|
err := Preload(constants.DefaultKubernetesVersion, constants.Docker, "docker")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -138,27 +163,8 @@ func testPreloadNotExists(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPreloadChecksumMismatch(t *testing.T) {
|
|
||||||
downloadNum := 0
|
|
||||||
DownloadMock = mockSleepDownload(&downloadNum)
|
|
||||||
|
|
||||||
checkCache = func(_ string) (fs.FileInfo, error) { return nil, fmt.Errorf("cache not found") }
|
|
||||||
checkPreloadExists = func(_, _, _ string, _ ...bool) bool { return true }
|
|
||||||
getChecksum = func(_, _ string) ([]byte, error) { return []byte("check"), nil }
|
|
||||||
ensureChecksumValid = func(_, _, _ string, _ []byte) error {
|
|
||||||
return fmt.Errorf("checksum mismatch")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := Preload(constants.DefaultKubernetesVersion, constants.Docker, "docker")
|
|
||||||
expectedErrMsg := "checksum mismatch"
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error when checksum mismatches")
|
|
||||||
} else if err.Error() != expectedErrMsg {
|
|
||||||
t.Errorf("Expected error to be %s, got %s", expectedErrMsg, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testImageToCache(t *testing.T) {
|
func testImageToCache(t *testing.T) {
|
||||||
|
setupTestMiniHome(t)
|
||||||
downloadNum := 0
|
downloadNum := 0
|
||||||
DownloadMock = mockSleepDownload(&downloadNum)
|
DownloadMock = mockSleepDownload(&downloadNum)
|
||||||
|
|
||||||
|
|
@ -184,44 +190,72 @@ func testImageToCache(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validates that preload existence checks correctly caches values retrieved by remote checks.
|
// Validates that preload existence checks correctly caches values retrieved by remote checks.
|
||||||
|
// testPreloadExistsCaching verifies the caching semantics of PreloadExists when
|
||||||
|
// the local cache is absent and remote existence checks are required.
|
||||||
|
// In summary, this test enforces that:
|
||||||
|
// - PreloadExists performs remote checks only on cache misses.
|
||||||
|
// - Negative and positive results are cached per (k8sVersion, containerVersion, runtime) key.
|
||||||
|
// - GitHub is only consulted when GCS reports the preload as not existing.
|
||||||
|
// - Global state is correctly restored after the test.
|
||||||
func testPreloadExistsCaching(t *testing.T) {
|
func testPreloadExistsCaching(t *testing.T) {
|
||||||
|
setupTestMiniHome(t)
|
||||||
checkCache = func(_ string) (fs.FileInfo, error) {
|
checkCache = func(_ string) (fs.FileInfo, error) {
|
||||||
return nil, fmt.Errorf("cache not found")
|
return nil, fmt.Errorf("cache not found")
|
||||||
}
|
}
|
||||||
doesPreloadExist := false
|
doesPreloadExist := false
|
||||||
checkCalled := false
|
gcsCheckCalls := 0
|
||||||
checkRemotePreloadExists = func(_, _ string) bool {
|
ghCheckCalls := 0
|
||||||
checkCalled = true
|
savedGCSCheck := checkRemotePreloadExistsGCS
|
||||||
|
savedGHCheck := checkRemotePreloadExistsGitHub
|
||||||
|
preloadStates = make(map[string]map[string]preloadState)
|
||||||
|
checkRemotePreloadExistsGCS = func(_, _ string) bool {
|
||||||
|
gcsCheckCalls++
|
||||||
return doesPreloadExist
|
return doesPreloadExist
|
||||||
}
|
}
|
||||||
existence := PreloadExists("v1", "c1", "docker", true)
|
checkRemotePreloadExistsGitHub = func(_, _ string) bool {
|
||||||
if existence || !checkCalled {
|
ghCheckCalls++
|
||||||
t.Errorf("Expected preload not to exist and a check to be performed. Existence: %v, Check: %v", existence, checkCalled)
|
return false
|
||||||
}
|
}
|
||||||
checkCalled = false
|
t.Cleanup(func() {
|
||||||
|
checkRemotePreloadExistsGCS = savedGCSCheck
|
||||||
|
checkRemotePreloadExistsGitHub = savedGHCheck
|
||||||
|
preloadStates = make(map[string]map[string]preloadState)
|
||||||
|
})
|
||||||
|
|
||||||
|
existence := PreloadExists("v1", "c1", "docker", true)
|
||||||
|
if existence || gcsCheckCalls != 1 || ghCheckCalls != 1 {
|
||||||
|
t.Errorf("Expected preload not to exist and checks to be performed. Existence: %v, GCS Calls: %d, GH Calls: %d", existence, gcsCheckCalls, ghCheckCalls)
|
||||||
|
}
|
||||||
|
gcsCheckCalls = 0
|
||||||
|
ghCheckCalls = 0
|
||||||
existence = PreloadExists("v1", "c1", "docker", true)
|
existence = PreloadExists("v1", "c1", "docker", true)
|
||||||
if existence || checkCalled {
|
if existence || gcsCheckCalls != 0 || ghCheckCalls != 0 {
|
||||||
t.Errorf("Expected preload not to exist and no check to be performed. Existence: %v, Check: %v", existence, checkCalled)
|
t.Errorf("Expected preload not to exist and no checks to be performed. Existence: %v, GCS Calls: %d, GH Calls: %d", existence, gcsCheckCalls, ghCheckCalls)
|
||||||
}
|
}
|
||||||
doesPreloadExist = true
|
doesPreloadExist = true
|
||||||
checkCalled = false
|
gcsCheckCalls = 0
|
||||||
|
ghCheckCalls = 0
|
||||||
existence = PreloadExists("v2", "c1", "docker", true)
|
existence = PreloadExists("v2", "c1", "docker", true)
|
||||||
if !existence || !checkCalled {
|
if !existence || gcsCheckCalls != 1 || ghCheckCalls != 0 {
|
||||||
t.Errorf("Expected preload to exist and a check to be performed. Existence: %v, Check: %v", existence, checkCalled)
|
t.Errorf("Expected preload to exist via GCS. Existence: %v, GCS Calls: %d, GH Calls: %d", existence, gcsCheckCalls, ghCheckCalls)
|
||||||
}
|
}
|
||||||
checkCalled = false
|
gcsCheckCalls = 0
|
||||||
|
ghCheckCalls = 0
|
||||||
existence = PreloadExists("v2", "c2", "docker", true)
|
existence = PreloadExists("v2", "c2", "docker", true)
|
||||||
if !existence || !checkCalled {
|
if !existence || gcsCheckCalls != 1 || ghCheckCalls != 0 {
|
||||||
t.Errorf("Expected preload to exist and a check to be performed. Existence: %v, Check: %v", existence, checkCalled)
|
t.Errorf("Expected preload to exist via GCS for new runtime. Existence: %v, GCS Calls: %d, GH Calls: %d", existence, gcsCheckCalls, ghCheckCalls)
|
||||||
}
|
}
|
||||||
checkCalled = false
|
gcsCheckCalls = 0
|
||||||
|
ghCheckCalls = 0
|
||||||
existence = PreloadExists("v2", "c2", "docker", true)
|
existence = PreloadExists("v2", "c2", "docker", true)
|
||||||
if !existence || checkCalled {
|
if !existence || gcsCheckCalls != 0 || ghCheckCalls != 0 {
|
||||||
t.Errorf("Expected preload to exist and no check to be performed. Existence: %v, Check: %v", existence, checkCalled)
|
t.Errorf("Expected preload to exist and no checks to be performed. Existence: %v, GCS Calls: %d, GH Calls: %d", existence, gcsCheckCalls, ghCheckCalls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPreloadWithCachedSizeZero(t *testing.T) {
|
func testPreloadWithCachedSizeZero(t *testing.T) {
|
||||||
|
setupTestMiniHome(t)
|
||||||
|
|
||||||
downloadNum := 0
|
downloadNum := 0
|
||||||
DownloadMock = mockSleepDownload(&downloadNum)
|
DownloadMock = mockSleepDownload(&downloadNum)
|
||||||
f, err := os.CreateTemp("", "preload")
|
f, err := os.CreateTemp("", "preload")
|
||||||
|
|
@ -231,8 +265,7 @@ func testPreloadWithCachedSizeZero(t *testing.T) {
|
||||||
|
|
||||||
checkCache = func(_ string) (fs.FileInfo, error) { return os.Stat(f.Name()) }
|
checkCache = func(_ string) (fs.FileInfo, error) { return os.Stat(f.Name()) }
|
||||||
checkPreloadExists = func(_, _, _ string, _ ...bool) bool { return true }
|
checkPreloadExists = func(_, _, _ string, _ ...bool) bool { return true }
|
||||||
getChecksum = func(_, _ string) ([]byte, error) { return []byte("check"), nil }
|
getChecksumGCS = func(_, _ string) ([]byte, error) { return []byte("check"), nil }
|
||||||
ensureChecksumValid = func(_, _, _ string, _ []byte) error { return nil }
|
|
||||||
|
|
||||||
if err := Preload(constants.DefaultKubernetesVersion, constants.Docker, "docker"); err != nil {
|
if err := Preload(constants.DefaultKubernetesVersion, constants.Docker, "docker"); err != nil {
|
||||||
t.Errorf("Expected no error with cached preload of size zero")
|
t.Errorf("Expected no error with cached preload of size zero")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package gh provides helper utilities for interacting with the GitHub API
|
||||||
|
package gh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v74/github"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReleaseAssets retrieves a GitHub release by tag from org/project.
|
||||||
|
// Try to not call this too often. preferably cache and re-use. to avoid rate limits.
|
||||||
|
func ReleaseAssets(org, project, tag string) ([]*github.ReleaseAsset, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
// Use an authenticated client when GITHUB_TOKEN is set to avoid low rate limits.
|
||||||
|
httpClient := oauthClient(ctx, os.Getenv("GITHUB_TOKEN"))
|
||||||
|
ghc := github.NewClient(httpClient)
|
||||||
|
|
||||||
|
rel, _, err := ghc.Repositories.GetReleaseByTag(ctx, org, project, tag)
|
||||||
|
return rel.Assets, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetSHA256 returns the SHA-256 digest for the asset with the given name
|
||||||
|
// from the provided release assets from github API.
|
||||||
|
// to avoid rate limits. encouraged to call pass results of ReleaseAssets here.
|
||||||
|
func AssetSHA256(assetName string, assets []*github.ReleaseAsset) ([]byte, error) {
|
||||||
|
for _, asset := range assets {
|
||||||
|
if asset.GetName() != assetName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
d := asset.GetDigest() // e.g. "sha256:fdcb..."
|
||||||
|
if d == "" {
|
||||||
|
return []byte(""), fmt.Errorf("asset %q has no digest; id=%d url=%s", assetName, asset.GetID(), asset.GetBrowserDownloadURL())
|
||||||
|
}
|
||||||
|
const prefix = "sha256:"
|
||||||
|
d = strings.TrimPrefix(d, prefix)
|
||||||
|
return []byte(d), nil
|
||||||
|
}
|
||||||
|
return []byte(""), fmt.Errorf("asset %q not found", assetName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func oauthClient(ctx context.Context, token string) *http.Client {
|
||||||
|
if token == "" {
|
||||||
|
return nil // unauthenticated client (lower rate limit)
|
||||||
|
}
|
||||||
|
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
|
||||||
|
return oauth2.NewClient(ctx, ts)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package gh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v74/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAssetSHA256(t *testing.T) {
|
||||||
|
t.Run("found_with_sha256_prefix", func(t *testing.T) {
|
||||||
|
assets := []*github.ReleaseAsset{
|
||||||
|
{
|
||||||
|
Name: github.Ptr("minikube-linux-amd64"),
|
||||||
|
Digest: github.Ptr("sha256:abcdef123456"),
|
||||||
|
ID: github.Ptr(int64(101)),
|
||||||
|
BrowserDownloadURL: github.Ptr("http://example/minikube-linux-amd64"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got, err := AssetSHA256("minikube-linux-amd64", assets)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if string(got) != "abcdef123456" {
|
||||||
|
t.Fatalf("expected digest %q, got %q", "abcdef123456", string(got))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("found_without_prefix", func(t *testing.T) {
|
||||||
|
assets := []*github.ReleaseAsset{
|
||||||
|
{
|
||||||
|
Name: github.Ptr("minikube-darwin-arm64"),
|
||||||
|
Digest: github.Ptr("1234abcd"),
|
||||||
|
ID: github.Ptr(int64(102)),
|
||||||
|
BrowserDownloadURL: github.Ptr("http://example/minikube-darwin-arm64"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got, err := AssetSHA256("minikube-darwin-arm64", assets)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if string(got) != "1234abcd" {
|
||||||
|
t.Fatalf("expected digest %q, got %q", "1234abcd", string(got))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("asset_missing_digest", func(t *testing.T) {
|
||||||
|
assets := []*github.ReleaseAsset{
|
||||||
|
{
|
||||||
|
Name: github.Ptr("minikube-windows-amd64.exe"),
|
||||||
|
Digest: github.Ptr(""),
|
||||||
|
ID: github.Ptr(int64(103)),
|
||||||
|
BrowserDownloadURL: github.Ptr("http://example/minikube-windows-amd64.exe"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := AssetSHA256("minikube-windows-amd64.exe", assets)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error, got nil")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "has no digest") {
|
||||||
|
t.Fatalf("unexpected error message: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("asset_not_found", func(t *testing.T) {
|
||||||
|
assets := []*github.ReleaseAsset{
|
||||||
|
{
|
||||||
|
Name: github.Ptr("unrelated"),
|
||||||
|
Digest: github.Ptr("sha256:deadbeef"),
|
||||||
|
ID: github.Ptr(int64(104)),
|
||||||
|
BrowserDownloadURL: github.Ptr("http://example/unrelated"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := AssetSHA256("missing", assets)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error, got nil")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), `asset "missing" not found`) {
|
||||||
|
t.Fatalf("unexpected error message: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,6 @@ package download
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/md5"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -34,6 +33,7 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
"k8s.io/minikube/pkg/minikube/download/gh"
|
||||||
"k8s.io/minikube/pkg/minikube/driver"
|
"k8s.io/minikube/pkg/minikube/driver"
|
||||||
"k8s.io/minikube/pkg/minikube/localpath"
|
"k8s.io/minikube/pkg/minikube/localpath"
|
||||||
"k8s.io/minikube/pkg/minikube/out"
|
"k8s.io/minikube/pkg/minikube/out"
|
||||||
|
|
@ -47,10 +47,26 @@ const (
|
||||||
PreloadVersion = "v18"
|
PreloadVersion = "v18"
|
||||||
// PreloadBucket is the name of the GCS bucket where preloaded volume tarballs exist
|
// PreloadBucket is the name of the GCS bucket where preloaded volume tarballs exist
|
||||||
PreloadBucket = "minikube-preloaded-volume-tarballs"
|
PreloadBucket = "minikube-preloaded-volume-tarballs"
|
||||||
|
PreloadGitHubOrg = "kubernetes-sigs"
|
||||||
|
PreloadGitHubRepo = "minikube-preloads"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type preloadSource string
|
||||||
|
|
||||||
|
const (
|
||||||
|
preloadSourceNone preloadSource = ""
|
||||||
|
preloadSourceLocal preloadSource = "local"
|
||||||
|
preloadSourceGCS preloadSource = "gcs"
|
||||||
|
preloadSourceGitHub preloadSource = "github"
|
||||||
|
)
|
||||||
|
|
||||||
|
type preloadState struct {
|
||||||
|
exists bool
|
||||||
|
source preloadSource
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
preloadStates = make(map[string]map[string]bool)
|
preloadStates = make(map[string]map[string]preloadState)
|
||||||
)
|
)
|
||||||
|
|
||||||
// TarballName returns name of the tarball
|
// TarballName returns name of the tarball
|
||||||
|
|
@ -67,42 +83,56 @@ func TarballName(k8sVersion, containerRuntime string) string {
|
||||||
return fmt.Sprintf("preloaded-images-k8s-%s-%s-%s-%s-%s.tar.lz4", PreloadVersion, k8sVersion, containerRuntime, storageDriver, runtime.GOARCH)
|
return fmt.Sprintf("preloaded-images-k8s-%s-%s-%s-%s-%s.tar.lz4", PreloadVersion, k8sVersion, containerRuntime, storageDriver, runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the name of the checksum file
|
|
||||||
func checksumName(k8sVersion, containerRuntime string) string {
|
|
||||||
return fmt.Sprintf("%s.checksum", TarballName(k8sVersion, containerRuntime))
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns target dir for all cached items related to preloading
|
// returns target dir for all cached items related to preloading
|
||||||
func targetDir() string {
|
func targetDir() string {
|
||||||
return localpath.MakeMiniPath("cache", "preloaded-tarball")
|
return localpath.MakeMiniPath("cache", "preloaded-tarball")
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreloadChecksumPath returns the local path to the cached checksum file
|
|
||||||
func PreloadChecksumPath(k8sVersion, containerRuntime string) string {
|
|
||||||
return filepath.Join(targetDir(), checksumName(k8sVersion, containerRuntime))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TarballPath returns the local path to the cached preload tarball
|
// TarballPath returns the local path to the cached preload tarball
|
||||||
func TarballPath(k8sVersion, containerRuntime string) string {
|
func TarballPath(k8sVersion, containerRuntime string) string {
|
||||||
return filepath.Join(targetDir(), TarballName(k8sVersion, containerRuntime))
|
return filepath.Join(targetDir(), TarballName(k8sVersion, containerRuntime))
|
||||||
}
|
}
|
||||||
|
|
||||||
// remoteTarballURL returns the URL for the remote tarball in GCS
|
// remoteTarballURLGCS returns the URL for the remote tarball in GCS
|
||||||
func remoteTarballURL(k8sVersion, containerRuntime string) string {
|
func remoteTarballURLGCS(k8sVersion, containerRuntime string) string {
|
||||||
return fmt.Sprintf("https://%s/%s/%s/%s/%s", downloadHost, PreloadBucket, PreloadVersion, k8sVersion, TarballName(k8sVersion, containerRuntime))
|
return fmt.Sprintf("https://%s/%s/%s/%s/%s", downloadHost, PreloadBucket, PreloadVersion, k8sVersion, TarballName(k8sVersion, containerRuntime))
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPreloadState(k8sVersion, containerRuntime string, value bool) {
|
// remoteTarballURLGitHub returns the URL for the remote tarball hosted on GitHub releases
|
||||||
cRuntimes, ok := preloadStates[k8sVersion]
|
func remoteTarballURLGitHub(k8sVersion, containerRuntime string) string {
|
||||||
if !ok {
|
return fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/%s", PreloadGitHubOrg, PreloadGitHubRepo, PreloadVersion, TarballName(k8sVersion, containerRuntime))
|
||||||
cRuntimes = make(map[string]bool)
|
|
||||||
preloadStates[k8sVersion] = cRuntimes
|
|
||||||
}
|
|
||||||
cRuntimes[containerRuntime] = value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var checkRemotePreloadExists = func(k8sVersion, containerRuntime string) bool {
|
func remoteTarballURL(k8sVersion, containerRuntime string, source preloadSource) string {
|
||||||
url := remoteTarballURL(k8sVersion, containerRuntime)
|
switch source {
|
||||||
|
case preloadSourceGitHub:
|
||||||
|
return remoteTarballURLGitHub(k8sVersion, containerRuntime)
|
||||||
|
case preloadSourceGCS:
|
||||||
|
return remoteTarballURLGCS(k8sVersion, containerRuntime)
|
||||||
|
default:
|
||||||
|
return string(preloadSourceNone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPreloadState(k8sVersion, containerRuntime string, state preloadState) {
|
||||||
|
cRuntimes, ok := preloadStates[k8sVersion]
|
||||||
|
if !ok {
|
||||||
|
cRuntimes = make(map[string]preloadState)
|
||||||
|
preloadStates[k8sVersion] = cRuntimes
|
||||||
|
}
|
||||||
|
cRuntimes[containerRuntime] = state
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPreloadState(k8sVersion, containerRuntime string) (preloadState, bool) {
|
||||||
|
if cRuntimes, ok := preloadStates[k8sVersion]; ok {
|
||||||
|
if state, ok := cRuntimes[containerRuntime]; ok {
|
||||||
|
return state, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return preloadState{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func remotePreloadExists(url string) bool {
|
||||||
resp, err := http.Head(url)
|
resp, err := http.Head(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Warningf("%s fetch error: %v", url, err)
|
klog.Warningf("%s fetch error: %v", url, err)
|
||||||
|
|
@ -119,6 +149,28 @@ var checkRemotePreloadExists = func(k8sVersion, containerRuntime string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is a function variable so it can be overridden in tests
|
||||||
|
var checkRemotePreloadExistsGCS = func(k8sVersion, containerRuntime string) bool {
|
||||||
|
url := remoteTarballURLGCS(k8sVersion, containerRuntime)
|
||||||
|
return remotePreloadExists(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a function variable so it can be overridden in tests
|
||||||
|
var checkRemotePreloadExistsGitHub = func(k8sVersion, containerRuntime string) bool {
|
||||||
|
url := remoteTarballURLGitHub(k8sVersion, containerRuntime)
|
||||||
|
return remotePreloadExists(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreloadExistsGCS returns true if there is a preloaded tarball in GCS that can be used
|
||||||
|
func PreloadExistsGCS(k8sVersion, containerRuntime string) bool {
|
||||||
|
return checkRemotePreloadExistsGCS(k8sVersion, containerRuntime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreloadExistsGH returns true if there is a preloaded tarball in GitHub releases that can be used
|
||||||
|
func PreloadExistsGH(k8sVersion, containerRuntime string) bool {
|
||||||
|
return checkRemotePreloadExistsGitHub(k8sVersion, containerRuntime)
|
||||||
|
}
|
||||||
|
|
||||||
// PreloadExists returns true if there is a preloaded tarball that can be used
|
// PreloadExists returns true if there is a preloaded tarball that can be used
|
||||||
func PreloadExists(k8sVersion, containerRuntime, driverName string, forcePreload ...bool) bool {
|
func PreloadExists(k8sVersion, containerRuntime, driverName string, forcePreload ...bool) bool {
|
||||||
// TODO (#8166): Get rid of the need for this and viper at all
|
// TODO (#8166): Get rid of the need for this and viper at all
|
||||||
|
|
@ -136,21 +188,30 @@ func PreloadExists(k8sVersion, containerRuntime, driverName string, forcePreload
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the preload existence is cached, just return that value.
|
// If the preload existence is cached, just return that value.
|
||||||
if preloadState, ok := preloadStates[k8sVersion][containerRuntime]; ok {
|
if state, ok := getPreloadState(k8sVersion, containerRuntime); ok {
|
||||||
return preloadState
|
return state.exists
|
||||||
}
|
}
|
||||||
|
|
||||||
// Omit remote check if tarball exists locally
|
// Omit remote check if tarball exists locally
|
||||||
targetPath := TarballPath(k8sVersion, containerRuntime)
|
targetPath := TarballPath(k8sVersion, containerRuntime)
|
||||||
if f, err := checkCache(targetPath); err == nil && f.Size() != 0 {
|
if f, err := checkCache(targetPath); err == nil && f.Size() != 0 {
|
||||||
klog.Infof("Found local preload: %s", targetPath)
|
klog.Infof("Found local preload: %s", targetPath)
|
||||||
setPreloadState(k8sVersion, containerRuntime, true)
|
setPreloadState(k8sVersion, containerRuntime, preloadState{exists: true, source: preloadSourceLocal})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
existence := checkRemotePreloadExists(k8sVersion, containerRuntime)
|
if PreloadExistsGCS(k8sVersion, containerRuntime) {
|
||||||
setPreloadState(k8sVersion, containerRuntime, existence)
|
setPreloadState(k8sVersion, containerRuntime, preloadState{exists: true, source: preloadSourceGCS})
|
||||||
return existence
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if PreloadExistsGH(k8sVersion, containerRuntime) {
|
||||||
|
setPreloadState(k8sVersion, containerRuntime, preloadState{exists: true, source: preloadSourceGitHub})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
setPreloadState(k8sVersion, containerRuntime, preloadState{exists: false, source: preloadSourceNone})
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var checkPreloadExists = PreloadExists
|
var checkPreloadExists = PreloadExists
|
||||||
|
|
@ -180,31 +241,34 @@ func Preload(k8sVersion, containerRuntime, driverName string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Step(style.FileDownload, "Downloading Kubernetes {{.version}} preload ...", out.V{"version": k8sVersion})
|
out.Step(style.FileDownload, "Downloading Kubernetes {{.version}} preload ...", out.V{"version": k8sVersion})
|
||||||
url := remoteTarballURL(k8sVersion, containerRuntime)
|
state, ok := getPreloadState(k8sVersion, containerRuntime)
|
||||||
|
source := preloadSourceNone
|
||||||
|
if ok && state.source != preloadSourceNone {
|
||||||
|
source = state.source
|
||||||
|
}
|
||||||
|
url := remoteTarballURL(k8sVersion, containerRuntime, source)
|
||||||
|
var checksum []byte
|
||||||
|
var chksErr error
|
||||||
|
checksum, chksErr = getChecksum(source, k8sVersion, containerRuntime)
|
||||||
|
|
||||||
checksum, err := getChecksum(k8sVersion, containerRuntime)
|
|
||||||
var realPath string
|
var realPath string
|
||||||
if err != nil {
|
if chksErr != nil {
|
||||||
klog.Warningf("No checksum for preloaded tarball for k8s version %s: %v", k8sVersion, err)
|
klog.Warningf("No checksum for preloaded tarball for k8s version %s: %v", k8sVersion, chksErr)
|
||||||
realPath = targetPath
|
realPath = targetPath
|
||||||
tmp, err := os.CreateTemp(targetDir(), TarballName(k8sVersion, containerRuntime)+".*")
|
tmp, err := os.CreateTemp(targetDir(), TarballName(k8sVersion, containerRuntime)+".*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "tempfile")
|
return errors.Wrap(err, "tempfile")
|
||||||
}
|
}
|
||||||
targetPath = tmp.Name()
|
targetPath = tmp.Name()
|
||||||
} else if checksum != nil {
|
} else if checksum != nil { // add URL parameter for go-getter to automatically verify the checksum
|
||||||
// add URL parameter for go-getter to automatically verify the checksum
|
url = addChecksumToURL(url, source, checksum)
|
||||||
url += fmt.Sprintf("?checksum=md5:%s", hex.EncodeToString(checksum))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := download(url, targetPath); err != nil {
|
if err := download(url, targetPath); err != nil {
|
||||||
return errors.Wrapf(err, "download failed: %s", url)
|
return errors.Wrapf(err, "download failed: %s", url)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ensureChecksumValid(k8sVersion, containerRuntime, targetPath, checksum); err != nil {
|
// to avoid partial/corrupt files in final dest. only rename tmp if download didn't error out.
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if realPath != "" {
|
if realPath != "" {
|
||||||
klog.Infof("renaming tempfile to %s ...", TarballName(k8sVersion, containerRuntime))
|
klog.Infof("renaming tempfile to %s ...", TarballName(k8sVersion, containerRuntime))
|
||||||
err := os.Rename(targetPath, realPath)
|
err := os.Rename(targetPath, realPath)
|
||||||
|
|
@ -214,10 +278,23 @@ func Preload(k8sVersion, containerRuntime, driverName string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the download was successful, mark off that the preload exists in the cache.
|
// If the download was successful, mark off that the preload exists in the cache.
|
||||||
setPreloadState(k8sVersion, containerRuntime, true)
|
setPreloadState(k8sVersion, containerRuntime, preloadState{exists: true, source: source})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addChecksumToURL appends the checksum query parameter to the URL for go-getter (so it can verify before/after download)
|
||||||
|
func addChecksumToURL(url string, ps preloadSource, checksum []byte) string {
|
||||||
|
switch ps {
|
||||||
|
case preloadSourceGCS: // GCS API gives us MD5 checksums only
|
||||||
|
url += fmt.Sprintf("?checksum=md5:%s", hex.EncodeToString(checksum))
|
||||||
|
klog.Infof("Got checksum from GCS API %q", hex.EncodeToString(checksum))
|
||||||
|
case preloadSourceGitHub: // GCS API gives us sha256
|
||||||
|
url += fmt.Sprintf("?checksum=sha256:%s", checksum)
|
||||||
|
klog.Infof("Got checksum from Github API %q", checksum)
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
func getStorageAttrs(name string) (*storage.ObjectAttrs, error) {
|
func getStorageAttrs(name string) (*storage.ObjectAttrs, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
client, err := storage.NewClient(ctx, option.WithoutAuthentication())
|
client, err := storage.NewClient(ctx, option.WithoutAuthentication())
|
||||||
|
|
@ -231,9 +308,9 @@ func getStorageAttrs(name string) (*storage.ObjectAttrs, error) {
|
||||||
return attrs, nil
|
return attrs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getChecksum returns the MD5 checksum of the preload tarball
|
// getChecksumGCS returns the MD5 checksum of the preload tarball
|
||||||
var getChecksum = func(k8sVersion, containerRuntime string) ([]byte, error) {
|
var getChecksumGCS = func(k8sVersion, containerRuntime string) ([]byte, error) {
|
||||||
klog.Infof("getting checksum for %s ...", TarballName(k8sVersion, containerRuntime))
|
klog.Infof("getting checksum for %s from gcs api...", TarballName(k8sVersion, containerRuntime))
|
||||||
filename := fmt.Sprintf("%s/%s/%s", PreloadVersion, k8sVersion, TarballName(k8sVersion, containerRuntime))
|
filename := fmt.Sprintf("%s/%s/%s", PreloadVersion, k8sVersion, TarballName(k8sVersion, containerRuntime))
|
||||||
attrs, err := getStorageAttrs(filename)
|
attrs, err := getStorageAttrs(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -242,46 +319,25 @@ var getChecksum = func(k8sVersion, containerRuntime string) ([]byte, error) {
|
||||||
return attrs.MD5, nil
|
return attrs.MD5, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// saveChecksumFile saves the checksum to a local file for later verification
|
// getChecksumGithub returns the SHA256 checksum of the preload tarball
|
||||||
func saveChecksumFile(k8sVersion, containerRuntime string, checksum []byte) error {
|
var getChecksumGithub = func(k8sVersion, containerRuntime string) ([]byte, error) {
|
||||||
klog.Infof("saving checksum for %s ...", TarballName(k8sVersion, containerRuntime))
|
klog.Infof("getting checksum for %s from github api...", TarballName(k8sVersion, containerRuntime))
|
||||||
return os.WriteFile(PreloadChecksumPath(k8sVersion, containerRuntime), checksum, 0o644)
|
assets, err := gh.ReleaseAssets(PreloadGitHubRepo, PreloadGitHubRepo, PreloadVersion)
|
||||||
|
if err != nil { // could not find release or rate limited
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return gh.AssetSHA256(TarballName(k8sVersion, containerRuntime), assets)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyChecksum returns true if the checksum of the local binary matches
|
func getChecksum(ps preloadSource, k8sVersion, containerRuntime string) ([]byte, error) {
|
||||||
// the checksum of the remote binary
|
switch ps {
|
||||||
func verifyChecksum(k8sVersion, containerRuntime, binaryPath string) error {
|
case preloadSourceGCS:
|
||||||
klog.Infof("verifying checksum of %s ...", binaryPath)
|
return getChecksumGCS(k8sVersion, containerRuntime)
|
||||||
// get md5 checksum of tarball path
|
case preloadSourceGitHub:
|
||||||
contents, err := os.ReadFile(binaryPath)
|
return getChecksumGithub(k8sVersion, containerRuntime)
|
||||||
if err != nil {
|
default:
|
||||||
return errors.Wrap(err, "reading tarball")
|
return nil, fmt.Errorf("unknown preload source: %s", ps)
|
||||||
}
|
}
|
||||||
checksum := md5.Sum(contents)
|
|
||||||
|
|
||||||
remoteChecksum, err := os.ReadFile(PreloadChecksumPath(k8sVersion, containerRuntime))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "reading checksum file")
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a slice of checksum, which is [16]byte
|
|
||||||
if string(remoteChecksum) != string(checksum[:]) {
|
|
||||||
return fmt.Errorf("checksum of %s does not match remote checksum (%s != %s)", binaryPath, string(remoteChecksum), string(checksum[:]))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensureChecksumValid saves and verifies local binary checksum matches remote binary checksum
|
|
||||||
var ensureChecksumValid = func(k8sVersion, containerRuntime, targetPath string, checksum []byte) error {
|
|
||||||
if err := saveChecksumFile(k8sVersion, containerRuntime, checksum); err != nil {
|
|
||||||
return errors.Wrap(err, "saving checksum file")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := verifyChecksum(k8sVersion, containerRuntime, targetPath); err != nil {
|
|
||||||
return errors.Wrap(err, "verify")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CleanUpOlderPreloads deletes preload files belonging to older minikube versions
|
// CleanUpOlderPreloads deletes preload files belonging to older minikube versions
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ minikube start [flags]
|
||||||
--interactive Allow user prompts for more information (default true)
|
--interactive Allow user prompts for more information (default true)
|
||||||
--iso-url strings Locations to fetch the minikube ISO from. The list depends on the machine architecture.
|
--iso-url strings Locations to fetch the minikube ISO from. The list depends on the machine architecture.
|
||||||
--keep-context This will keep the existing kubectl context and will create a minikube context.
|
--keep-context This will keep the existing kubectl context and will create a minikube context.
|
||||||
--kubernetes-version string The Kubernetes version that the minikube VM will use (ex: v1.2.3, 'stable' for v1.34.0, 'latest' for v1.34.0). Defaults to 'stable'.
|
--kubernetes-version string The Kubernetes version that the minikube VM will use (ex: v1.2.3, 'stable' for v1.34.1, 'latest' for v1.34.1). Defaults to 'stable'.
|
||||||
--kvm-gpu Enable experimental NVIDIA GPU support in minikube
|
--kvm-gpu Enable experimental NVIDIA GPU support in minikube
|
||||||
--kvm-hidden Hide the hypervisor signature from the guest in minikube (kvm2 driver only)
|
--kvm-hidden Hide the hypervisor signature from the guest in minikube (kvm2 driver only)
|
||||||
--kvm-network string The KVM default network name. (kvm2 driver only) (default "default")
|
--kvm-network string The KVM default network name. (kvm2 driver only) (default "default")
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/md5"
|
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -235,23 +234,19 @@ func TestDownloadOnlyKic(t *testing.T) {
|
||||||
|
|
||||||
// Make sure the downloaded image tarball exists
|
// Make sure the downloaded image tarball exists
|
||||||
tarball := download.TarballPath(constants.DefaultKubernetesVersion, cRuntime)
|
tarball := download.TarballPath(constants.DefaultKubernetesVersion, cRuntime)
|
||||||
contents, err := os.ReadFile(tarball)
|
fi, err := os.Stat(tarball)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to read tarball file %q: %v", tarball, err)
|
t.Errorf("expected tarball file %q to exist, but got error: %v", tarball, err)
|
||||||
|
} else {
|
||||||
|
const minSize int64 = 200 * 1024 * 1024 // 200 MB
|
||||||
|
if fi.Size() <= minSize {
|
||||||
|
t.Errorf("expected tarball file %q to be larger than 200MB (>%d bytes), got %d bytes", tarball, minSize, fi.Size())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if arm64Platform() {
|
if arm64Platform() {
|
||||||
t.Skip("Skip for arm64 platform. See https://github.com/kubernetes/minikube/issues/10144")
|
t.Skip("Skip for arm64 platform. See https://github.com/kubernetes/minikube/issues/10144")
|
||||||
}
|
}
|
||||||
// Make sure it has the correct checksum
|
|
||||||
checksum := md5.Sum(contents)
|
|
||||||
remoteChecksum, err := os.ReadFile(download.PreloadChecksumPath(constants.DefaultKubernetesVersion, cRuntime))
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to read checksum file %q : %v", download.PreloadChecksumPath(constants.DefaultKubernetesVersion, cRuntime), err)
|
|
||||||
}
|
|
||||||
if string(remoteChecksum) != string(checksum[:]) {
|
|
||||||
t.Errorf("failed to verify checksum. checksum of %q does not match remote checksum (%q != %q)", tarball, string(remoteChecksum), string(checksum[:]))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// createSha256File is a helper function which creates sha256 checksum file from given file
|
// createSha256File is a helper function which creates sha256 checksum file from given file
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue