2021-09-13 18:58:43 +00:00
//go:build integration
2019-12-18 23:15:48 +00:00
/ *
Copyright 2019 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 integration
import (
2020-12-04 01:46:41 +00:00
"bufio"
"bytes"
2019-12-18 23:15:48 +00:00
"context"
2020-03-03 00:54:05 +00:00
"crypto/md5"
2022-01-10 22:34:06 +00:00
"crypto/sha256"
2020-12-04 01:46:41 +00:00
"encoding/json"
2019-12-18 23:15:48 +00:00
"fmt"
2022-01-10 22:34:06 +00:00
"net/http"
"net/http/httptest"
2019-12-18 23:15:48 +00:00
"os"
"os/exec"
"path/filepath"
2020-02-12 06:23:37 +00:00
"runtime"
2019-12-18 23:15:48 +00:00
"strings"
"testing"
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
"k8s.io/minikube/pkg/minikube/constants"
2020-03-05 02:57:12 +00:00
"k8s.io/minikube/pkg/minikube/download"
2019-12-18 23:15:48 +00:00
"k8s.io/minikube/pkg/minikube/localpath"
)
2021-04-16 20:42:41 +00:00
// TestDownloadOnly makes sure the --download-only parameter in minikube start caches the appropriate images and tarballs.
2024-01-11 21:21:56 +00:00
func TestDownloadOnly ( t * testing . T ) { // nolint:gocyclo
2021-01-21 20:12:33 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , Minutes ( 30 ) )
2024-01-11 21:21:56 +00:00
// separate each k8s version testrun into individual profiles to avoid ending up with subsequently mixed up configs like:
// {Name:download-only-062906 ... KubernetesConfig:{KubernetesVersion:v1.28.4 ...} Nodes:[{Name: IP: Port:8443 KubernetesVersion:v1.16.0 ...}] ...}
// that will then get artifacts for node's not cluster's KubernetesVersion and fail checks thereafter
// at the end, cleanup all profiles
profiles := [ ] string { }
defer func ( ) {
for _ , profile := range profiles {
Cleanup ( t , profile , cancel )
}
} ( )
2021-01-21 20:12:33 +00:00
containerRuntime := ContainerRuntime ( )
2021-01-22 18:31:37 +00:00
2021-01-21 20:12:33 +00:00
versions := [ ] string {
constants . OldestKubernetesVersion ,
constants . DefaultKubernetesVersion ,
constants . NewestKubernetesVersion ,
}
2019-12-18 23:15:48 +00:00
2021-01-25 17:48:13 +00:00
// Small optimization, don't run the exact same set of tests twice
if constants . DefaultKubernetesVersion == constants . NewestKubernetesVersion {
versions = versions [ : len ( versions ) - 1 ]
}
2021-01-22 18:31:37 +00:00
2021-01-21 20:12:33 +00:00
for _ , v := range versions {
t . Run ( v , func ( t * testing . T ) {
2024-01-11 21:21:56 +00:00
profile := UniqueProfileName ( "download-only" )
profiles = append ( profiles , profile )
2021-01-21 20:12:33 +00:00
defer PostMortemLogs ( t , profile )
2020-05-08 20:12:30 +00:00
2021-01-25 22:37:35 +00:00
t . Run ( "json-events" , func ( t * testing . T ) {
2021-01-25 17:48:13 +00:00
// --force to avoid uid check
args := append ( [ ] string { "start" , "-o=json" , "--download-only" , "-p" , profile , "--force" , "--alsologtostderr" , fmt . Sprintf ( "--kubernetes-version=%s" , v ) , fmt . Sprintf ( "--container-runtime=%s" , containerRuntime ) } , StartArgs ( ) ... )
rt , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , args ... ) )
if err != nil {
t . Errorf ( "failed to download only. args: %q %v" , args , err )
}
2021-01-22 18:31:37 +00:00
2021-01-21 20:12:33 +00:00
s := bufio . NewScanner ( bytes . NewReader ( rt . Stdout . Bytes ( ) ) )
for s . Scan ( ) {
var rtObj map [ string ] interface { }
2021-01-25 17:48:13 +00:00
err := json . Unmarshal ( s . Bytes ( ) , & rtObj )
2020-03-21 14:53:03 +00:00
if err != nil {
2021-01-21 20:12:33 +00:00
t . Errorf ( "failed to parse output: %v" , err )
} else if step , ok := rtObj [ "data" ] ; ok {
if stepMap , ok := step . ( map [ string ] interface { } ) ; ok {
if stepMap [ "currentstep" ] == "" {
t . Errorf ( "Empty step number for %v" , stepMap [ "name" ] )
2021-01-22 18:31:37 +00:00
}
}
2020-03-21 14:53:03 +00:00
}
2021-01-21 20:12:33 +00:00
}
2023-03-31 18:15:34 +00:00
if err := s . Err ( ) ; err != nil {
t . Errorf ( "failed to read output: %v" , err )
}
2021-01-21 20:12:33 +00:00
} )
2020-02-12 06:23:37 +00:00
2021-01-25 17:48:13 +00:00
preloadExists := false
2021-01-25 22:37:35 +00:00
t . Run ( "preload-exists" , func ( t * testing . T ) {
2021-01-25 17:48:13 +00:00
// skip for none, as none driver does not have preload feature.
if NoneDriver ( ) {
t . Skip ( "None driver does not have preload" )
}
2021-05-27 21:25:26 +00:00
// Driver does not matter here, since the only exception is none driver,
// which cannot occur here.
2023-03-31 18:15:34 +00:00
if ! download . PreloadExists ( v , containerRuntime , "docker" , true ) {
2021-01-25 17:48:13 +00:00
t . Skip ( "No preload image" )
}
2023-03-31 18:15:34 +00:00
// Just make sure the tarball path exists
if _ , err := os . Stat ( download . TarballPath ( v , containerRuntime ) ) ; err != nil {
t . Errorf ( "failed to verify preloaded tarball file exists: %v" , err )
}
preloadExists = true
2021-01-25 17:48:13 +00:00
} )
2020-05-08 20:12:30 +00:00
2021-01-25 22:37:35 +00:00
t . Run ( "cached-images" , func ( t * testing . T ) {
2021-01-25 17:48:13 +00:00
// skip verify for cache images if --driver=none
if NoneDriver ( ) {
t . Skip ( "None driver has no cache" )
2020-03-21 14:53:03 +00:00
}
2021-01-25 17:48:13 +00:00
if preloadExists {
t . Skip ( "Preload exists, images won't be cached" )
}
imgs , err := images . Kubeadm ( "" , v )
2020-03-21 14:53:03 +00:00
if err != nil {
2021-01-25 17:48:13 +00:00
t . Errorf ( "failed to get kubeadm images for %v: %+v" , v , err )
2021-01-21 20:12:33 +00:00
}
2021-01-25 17:48:13 +00:00
2021-01-21 20:12:33 +00:00
for _ , img := range imgs {
2024-01-11 21:21:56 +00:00
pathToImage := [ ] string { localpath . MiniPath ( ) , "cache" , "images" , runtime . GOARCH }
2021-01-21 20:12:33 +00:00
img = strings . Replace ( img , ":" , "_" , 1 ) // for example kube-scheduler:v1.15.2 --> kube-scheduler_v1.15.2
2023-10-12 20:55:50 +00:00
imagePath := strings . Split ( img , "/" ) // changes "gcr.io/k8s-minikube/storage-provisioner_v5" into ["gcr.io", "k8s-minikube", "storage-provisioner_v5"] to match cache folder structure
pathToImage = append ( pathToImage , imagePath ... )
fp := filepath . Join ( pathToImage ... )
2021-01-21 20:12:33 +00:00
_ , err := os . Stat ( fp )
if err != nil {
t . Errorf ( "expected image file exist at %q but got error: %v" , fp , err )
2019-12-18 23:15:48 +00:00
}
2020-03-21 14:53:03 +00:00
}
} )
2020-05-08 20:12:30 +00:00
2021-01-25 22:37:35 +00:00
t . Run ( "binaries" , func ( t * testing . T ) {
2021-05-26 22:34:13 +00:00
if preloadExists {
t . Skip ( "Preload exists, binaries are present within." )
}
2021-01-25 17:48:13 +00:00
// checking binaries downloaded (kubelet,kubeadm)
for _ , bin := range constants . KubernetesReleaseBinaries {
2022-02-03 18:29:13 +00:00
fp := filepath . Join ( localpath . MiniPath ( ) , "cache" , "linux" , runtime . GOARCH , v , bin )
2021-01-25 17:48:13 +00:00
_ , err := os . Stat ( fp )
if err != nil {
t . Errorf ( "expected the file for binary exist at %q but got error %v" , fp , err )
}
2020-03-21 14:53:03 +00:00
}
2021-01-25 17:48:13 +00:00
} )
2021-01-25 22:37:35 +00:00
t . Run ( "kubectl" , func ( t * testing . T ) {
2021-01-25 17:48:13 +00:00
// If we are on darwin/windows, check to make sure OS specific kubectl has been downloaded
// as well for the `minikube kubectl` command
if runtime . GOOS == "linux" {
t . Skip ( "Test for darwin and windows" )
}
binary := "kubectl"
if runtime . GOOS == "windows" {
binary = "kubectl.exe"
}
2022-02-03 18:29:13 +00:00
fp := filepath . Join ( localpath . MiniPath ( ) , "cache" , runtime . GOOS , runtime . GOARCH , v , binary )
2021-01-25 17:48:13 +00:00
if _ , err := os . Stat ( fp ) ; err != nil {
2021-01-21 20:12:33 +00:00
t . Errorf ( "expected the file for binary exist at %q but got error %v" , fp , err )
2020-03-21 14:53:03 +00:00
}
} )
2021-01-25 17:48:13 +00:00
2021-05-04 23:12:19 +00:00
// checks if the duration of `minikube logs` takes longer than 5 seconds
t . Run ( "LogsDuration" , func ( t * testing . T ) {
2021-05-04 01:02:59 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , Seconds ( 5 ) )
2021-05-04 16:40:01 +00:00
defer cancel ( )
args := [ ] string { "logs" , "-p" , profile }
2021-05-04 23:30:29 +00:00
if _ , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , args ... ) ) ; err != nil {
t . Logf ( "minikube logs failed with error: %v" , err )
}
2021-05-04 20:41:40 +00:00
if err := ctx . Err ( ) ; err == context . DeadlineExceeded {
2021-05-04 16:40:01 +00:00
t . Error ( "minikube logs expected to finish by 5 seconds, but took longer" )
}
2021-05-04 01:02:59 +00:00
} )
2024-01-11 21:21:56 +00:00
// This is a weird place to test profile deletion, but this test is serial, and we have a profile to delete!
t . Run ( "DeleteAll" , func ( t * testing . T ) {
if ! CanCleanup ( ) {
t . Skip ( "skipping, as cleanup is disabled" )
}
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "delete" , "--all" ) )
if err != nil {
t . Errorf ( "failed to delete all. args: %q : %v" , rr . Command ( ) , err )
}
} )
2021-01-21 20:12:33 +00:00
2024-01-11 21:21:56 +00:00
// Delete should always succeed, even if previously partially or fully deleted.
t . Run ( "DeleteAlwaysSucceeds" , func ( t * testing . T ) {
if ! CanCleanup ( ) {
t . Skip ( "skipping, as cleanup is disabled" )
}
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "delete" , "-p" , profile ) )
if err != nil {
t . Errorf ( "failed to delete. args: %q: %v" , rr . Command ( ) , err )
}
} )
} )
}
2019-12-18 23:15:48 +00:00
}
2020-03-21 14:53:03 +00:00
2021-04-16 20:42:41 +00:00
// TestDownloadOnlyKic makes sure --download-only caches the docker driver images as well.
2020-03-24 13:07:51 +00:00
func TestDownloadOnlyKic ( t * testing . T ) {
if ! KicDriver ( ) {
t . Skip ( "skipping, only for docker or podman driver" )
2020-03-03 00:54:05 +00:00
}
profile := UniqueProfileName ( "download-docker" )
2020-03-24 13:07:51 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , Minutes ( 15 ) )
2020-03-03 00:54:05 +00:00
defer Cleanup ( t , profile , cancel )
2021-01-22 21:49:05 +00:00
cRuntime := ContainerRuntime ( )
2020-03-25 00:25:27 +00:00
2023-02-08 19:55:24 +00:00
args := [ ] string { "start" , "--download-only" , "-p" , profile , "--alsologtostderr" }
2020-03-24 13:07:51 +00:00
args = append ( args , StartArgs ( ) ... )
2020-03-26 05:15:24 +00:00
2020-08-11 18:38:28 +00:00
cmd := exec . CommandContext ( ctx , Target ( ) , args ... )
if _ , err := Run ( t , cmd ) ; err != nil {
2020-03-26 05:15:24 +00:00
t . Errorf ( "start with download only failed %q : %v" , args , err )
2020-03-03 00:54:05 +00:00
}
2020-03-05 02:57:12 +00:00
// Make sure the downloaded image tarball exists
2020-03-23 19:32:36 +00:00
tarball := download . TarballPath ( constants . DefaultKubernetesVersion , cRuntime )
2021-09-28 10:58:01 +00:00
contents , err := os . ReadFile ( tarball )
2020-03-03 00:54:05 +00:00
if err != nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "failed to read tarball file %q: %v" , tarball , err )
2020-03-03 00:54:05 +00:00
}
2021-01-14 20:30:28 +00:00
if arm64Platform ( ) {
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 )
2021-09-28 10:58:01 +00:00
remoteChecksum , err := os . ReadFile ( download . PreloadChecksumPath ( constants . DefaultKubernetesVersion , cRuntime ) )
2021-01-14 20:30:28 +00:00
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 [ : ] ) )
2020-03-03 00:54:05 +00:00
}
}
2022-01-10 22:34:06 +00:00
// createSha256File is a helper function which creates sha256 checksum file from given file
func createSha256File ( filePath string ) error {
dat , _ := os . ReadFile ( filePath )
sum := sha256 . Sum256 ( dat )
f , err := os . Create ( filePath + ".sha256" )
if err != nil {
return err
}
defer f . Close ( )
_ , err = f . WriteString ( fmt . Sprintf ( "%x" , sum [ : ] ) )
if err != nil {
return err
}
return nil
}
// TestBinaryMirror tests functionality of --binary-mirror flag
func TestBinaryMirror ( t * testing . T ) {
profile := UniqueProfileName ( "binary-mirror" )
ctx , cancel := context . WithTimeout ( context . Background ( ) , Minutes ( 10 ) )
defer Cleanup ( t , profile , cancel )
2022-04-02 02:18:20 +00:00
tmpDir := t . TempDir ( )
2022-01-10 22:34:06 +00:00
// Start test server which will serve binary files
ts := httptest . NewServer (
http . FileServer ( http . Dir ( tmpDir ) ) ,
)
defer ts . Close ( )
binaryName := "kubectl"
if runtime . GOOS == "windows" {
binaryName = "kubectl.exe"
}
binaryPath , err := download . Binary ( binaryName , constants . DefaultKubernetesVersion , runtime . GOOS , runtime . GOARCH , "" )
if err != nil {
t . Errorf ( "Failed to download binary: %+v" , err )
}
newBinaryDir := filepath . Join ( tmpDir , constants . DefaultKubernetesVersion , "bin" , runtime . GOOS , runtime . GOARCH )
if err := os . MkdirAll ( newBinaryDir , os . ModePerm ) ; err != nil {
t . Errorf ( "Failed to create %s directories" , newBinaryDir )
}
newBinaryPath := filepath . Join ( newBinaryDir , binaryName )
if err := os . Rename ( binaryPath , newBinaryPath ) ; err != nil {
t . Errorf ( "Failed to move binary file: %+v" , err )
}
if err := createSha256File ( newBinaryPath ) ; err != nil {
t . Errorf ( "Failed to generate sha256 checksum file: %+v" , err )
}
2022-01-13 20:23:18 +00:00
args := append ( [ ] string { "start" , "--download-only" , "-p" , profile , "--alsologtostderr" , "--binary-mirror" , ts . URL } , StartArgs ( ) ... )
2022-01-10 22:34:06 +00:00
cmd := exec . CommandContext ( ctx , Target ( ) , args ... )
if _ , err := Run ( t , cmd ) ; err != nil {
t . Errorf ( "start with --binary-mirror failed %q : %v" , args , err )
}
}