2021-09-13 18:58:43 +00:00
//go:build integration
2016-12-05 22:49:52 +00:00
/ *
Copyright 2016 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 (
2021-02-18 20:34:13 +00:00
"bufio"
2019-09-11 16:59:38 +00:00
"bytes"
"context"
"encoding/json"
"fmt"
2021-09-28 10:58:01 +00:00
"io"
2019-09-11 16:59:38 +00:00
"net/http"
"net/url"
"os"
"os/exec"
2020-03-04 22:48:40 +00:00
"path"
2019-09-11 16:59:38 +00:00
"path/filepath"
2019-10-11 14:43:00 +00:00
"regexp"
2019-11-06 22:14:56 +00:00
"runtime"
2019-09-11 16:59:38 +00:00
"strings"
2016-12-05 22:49:52 +00:00
"testing"
2019-09-11 16:59:38 +00:00
"time"
2019-11-07 01:20:52 +00:00
"github.com/google/go-cmp/cmp"
2020-12-09 19:06:17 +00:00
"k8s.io/minikube/pkg/drivers/kic/oci"
2020-04-07 04:03:12 +00:00
"k8s.io/minikube/pkg/minikube/config"
2022-01-06 17:56:54 +00:00
"k8s.io/minikube/pkg/minikube/detect"
2019-11-07 01:20:52 +00:00
"k8s.io/minikube/pkg/minikube/localpath"
2020-08-31 18:21:23 +00:00
"k8s.io/minikube/pkg/minikube/reason"
2020-04-07 04:26:45 +00:00
"k8s.io/minikube/pkg/util/retry"
2019-11-07 01:20:52 +00:00
2021-06-30 21:21:19 +00:00
"github.com/blang/semver/v4"
2019-09-11 16:59:38 +00:00
"github.com/elazarl/goproxy"
2021-05-05 20:28:39 +00:00
"github.com/hashicorp/go-retryablehttp"
2022-05-16 19:48:41 +00:00
cp "github.com/otiai10/copy"
2019-09-11 16:59:38 +00:00
"github.com/phayes/freeport"
"github.com/pkg/errors"
"golang.org/x/build/kubernetes/api"
2016-12-05 22:49:52 +00:00
)
2021-09-16 20:34:26 +00:00
const addonResizer = "gcr.io/google-containers/addon-resizer"
2019-09-11 16:59:38 +00:00
// validateFunc are for subtests that share a single setup
type validateFunc func ( context . Context , * testing . T , string )
2020-04-07 20:14:30 +00:00
// used in validateStartWithProxy and validateSoftStart
var apiPortTest = 8441
2021-06-24 17:05:47 +00:00
// Store the proxy session so we can clean it up at the end
var mitm * StartSession
2022-01-06 17:56:54 +00:00
var runCorpProxy = detect . GithubActionRunner ( ) && runtime . GOOS == "linux" && ! arm64Platform ( )
2021-06-24 22:41:04 +00:00
2019-09-11 16:59:38 +00:00
// TestFunctional are functionality tests which can safely share a profile in parallel
2017-05-30 20:23:24 +00:00
func TestFunctional ( t * testing . T ) {
2019-09-11 16:59:38 +00:00
profile := UniqueProfileName ( "functional" )
2020-02-21 00:19:59 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , Minutes ( 40 ) )
2020-02-12 22:26:38 +00:00
defer func ( ) {
2020-03-04 22:48:40 +00:00
if ! * cleanup {
return
}
2020-02-12 22:26:38 +00:00
p := localSyncTestPath ( )
if err := os . Remove ( p ) ; err != nil {
2020-03-26 04:43:32 +00:00
t . Logf ( "unable to remove %q: %v" , p , err )
2020-02-12 22:26:38 +00:00
}
2020-04-08 22:04:12 +00:00
2020-05-08 20:12:30 +00:00
Cleanup ( t , profile , cancel )
2020-02-12 22:26:38 +00:00
} ( )
2019-09-11 16:59:38 +00:00
// Serial tests
t . Run ( "serial" , func ( t * testing . T ) {
tests := [ ] struct {
name string
validator validateFunc
} {
2020-02-12 17:54:17 +00:00
{ "CopySyncFile" , setupFileSync } , // Set file for the file sync test case
{ "StartWithProxy" , validateStartWithProxy } , // Set everything else up for success
2021-02-20 04:49:41 +00:00
{ "AuditLog" , validateAuditAfterStart } , // check audit feature works
2022-01-29 00:41:41 +00:00
{ "SoftStart" , validateSoftStart } , // do a soft start. ensure config didn't change.
2020-02-12 17:54:17 +00:00
{ "KubeContext" , validateKubeContext } , // Racy: must come immediately after "minikube start"
{ "KubectlGetPods" , validateKubectlGetPods } , // Make sure apiserver is up
{ "CacheCmd" , validateCacheCmd } , // Caches images needed for subsequent tests because of proxy
{ "MinikubeKubectlCmd" , validateMinikubeKubectl } , // Make sure `minikube kubectl` works
2020-08-17 11:26:26 +00:00
{ "MinikubeKubectlCmdDirectly" , validateMinikubeKubectlDirectCall } ,
2020-11-28 20:40:09 +00:00
{ "ExtraConfig" , validateExtraConfig } , // Ensure extra cmdline config change is saved
2021-01-29 21:03:02 +00:00
{ "ComponentHealth" , validateComponentHealth } ,
2021-07-13 20:24:13 +00:00
{ "LogsCmd" , validateLogsCmd } ,
{ "LogsFileCmd" , validateLogsFileCmd } ,
2019-09-11 16:59:38 +00:00
}
for _ , tc := range tests {
tc := tc
2020-08-22 17:18:15 +00:00
if ctx . Err ( ) == context . DeadlineExceeded {
t . Fatalf ( "Unable to run more tests (deadline exceeded)" )
}
2021-06-24 22:41:04 +00:00
if tc . name == "StartWithProxy" && runCorpProxy {
2021-06-25 18:36:18 +00:00
tc . name = "StartWithCustomCerts"
tc . validator = validateStartWithCustomCerts
2021-06-24 22:41:04 +00:00
}
2019-09-11 16:59:38 +00:00
t . Run ( tc . name , func ( t * testing . T ) {
2020-04-07 04:26:45 +00:00
tc . validator ( ctx , t , profile )
2019-09-11 16:59:38 +00:00
} )
2019-07-30 04:52:05 +00:00
}
2019-09-11 16:59:38 +00:00
} )
2019-07-30 04:52:05 +00:00
2021-06-24 17:05:47 +00:00
defer func ( ) {
cleanupUnwantedImages ( ctx , t , profile )
2021-06-24 22:41:04 +00:00
if runCorpProxy {
2021-06-24 17:05:47 +00:00
mitm . Stop ( t )
}
} ( )
2021-03-10 02:53:22 +00:00
2019-09-11 16:59:38 +00:00
// Parallelized tests
t . Run ( "parallel" , func ( t * testing . T ) {
tests := [ ] struct {
name string
validator validateFunc
} {
2021-01-29 21:03:02 +00:00
{ "ConfigCmd" , validateConfigCmd } ,
{ "DashboardCmd" , validateDashboardCmd } ,
{ "DryRun" , validateDryRun } ,
2021-06-18 16:55:58 +00:00
{ "InternationalLanguage" , validateInternationalLanguage } ,
2021-01-29 21:03:02 +00:00
{ "StatusCmd" , validateStatusCmd } ,
{ "MountCmd" , validateMountCmd } ,
{ "ProfileCmd" , validateProfileCmd } ,
{ "ServiceCmd" , validateServiceCmd } ,
2022-03-07 14:56:50 +00:00
{ "ServiceCmdConnect" , validateServiceCmdConnect } ,
2021-01-29 21:03:02 +00:00
{ "AddonsCmd" , validateAddonsCmd } ,
{ "PersistentVolumeClaim" , validatePersistentVolumeClaim } ,
{ "TunnelCmd" , validateTunnelCmd } ,
{ "SSHCmd" , validateSSHCmd } ,
2021-02-25 07:28:45 +00:00
{ "CpCmd" , validateCpCmd } ,
2021-01-29 21:03:02 +00:00
{ "MySQL" , validateMySQL } ,
{ "FileSync" , validateFileSync } ,
{ "CertSync" , validateCertSync } ,
{ "UpdateContextCmd" , validateUpdateContextCmd } ,
{ "DockerEnv" , validateDockerEnv } ,
2021-05-05 20:28:39 +00:00
{ "PodmanEnv" , validatePodmanEnv } ,
2021-01-29 21:03:02 +00:00
{ "NodeLabels" , validateNodeLabels } ,
2021-09-17 17:52:01 +00:00
{ "ImageCommands" , validateImageCommands } ,
2021-05-27 01:19:53 +00:00
{ "NonActiveRuntimeDisabled" , validateNotActiveRuntimeDisabled } ,
2021-06-30 21:04:50 +00:00
{ "Version" , validateVersionCmd } ,
2019-09-11 16:59:38 +00:00
}
for _ , tc := range tests {
tc := tc
2020-08-22 17:18:15 +00:00
if ctx . Err ( ) == context . DeadlineExceeded {
t . Fatalf ( "Unable to run more tests (deadline exceeded)" )
}
2019-09-11 16:59:38 +00:00
t . Run ( tc . name , func ( t * testing . T ) {
MaybeParallel ( t )
tc . validator ( ctx , t , profile )
} )
}
2019-07-30 04:52:05 +00:00
} )
2021-03-10 02:53:22 +00:00
}
func cleanupUnwantedImages ( ctx context . Context , t * testing . T , profile string ) {
_ , err := exec . LookPath ( oci . Docker )
if err != nil {
t . Skipf ( "docker is not installed, cannot delete docker images" )
} else {
2021-09-16 20:34:26 +00:00
t . Run ( "delete addon-resizer images" , func ( t * testing . T ) {
2021-09-17 17:52:01 +00:00
tags := [ ] string { "1.8.8" , profile }
2021-09-16 20:34:26 +00:00
for _ , tag := range tags {
image := fmt . Sprintf ( "%s:%s" , addonResizer , tag )
rr , err := Run ( t , exec . CommandContext ( ctx , "docker" , "rmi" , "-f" , image ) )
if err != nil {
t . Logf ( "failed to remove image %q from docker images. args %q: %v" , image , rr . Command ( ) , err )
}
2021-05-01 11:44:32 +00:00
}
2021-03-10 02:53:22 +00:00
} )
2021-04-23 20:00:17 +00:00
t . Run ( "delete my-image image" , func ( t * testing . T ) {
newImage := fmt . Sprintf ( "localhost/my-image:%s" , profile )
rr , err := Run ( t , exec . CommandContext ( ctx , "docker" , "rmi" , "-f" , newImage ) )
if err != nil {
t . Logf ( "failed to remove image my-image from docker images. args %q: %v" , rr . Command ( ) , err )
}
} )
2021-03-10 02:53:22 +00:00
t . Run ( "delete minikube cached images" , func ( t * testing . T ) {
img := "minikube-local-cache-test:" + profile
rr , err := Run ( t , exec . CommandContext ( ctx , "docker" , "rmi" , "-f" , img ) )
if err != nil {
t . Logf ( "failed to remove image minikube local cache test images from docker. args %q: %v" , rr . Command ( ) , err )
}
} )
}
2019-09-11 16:59:38 +00:00
}
2020-02-20 21:57:09 +00:00
// validateNodeLabels checks if minikube cluster is created with correct kubernetes's node label
func validateNodeLabels ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-10-11 01:46:44 +00:00
// docs: Get the node labels from the cluster with `kubectl get nodes`
2020-02-22 00:01:47 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "nodes" , "--output=go-template" , "--template='{{range $k, $v := (index .items 0).metadata.labels}}{{$k}} {{end}}'" ) )
2020-02-20 21:57:09 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to 'kubectl get nodes' with args %q: %v" , rr . Command ( ) , err )
2020-02-20 21:57:09 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: check if the node labels matches with the expected Minikube labels: `minikube.k8s.io/*`
2020-02-20 21:57:09 +00:00
expectedLabels := [ ] string { "minikube.k8s.io/commit" , "minikube.k8s.io/version" , "minikube.k8s.io/updated_at" , "minikube.k8s.io/name" }
for _ , el := range expectedLabels {
2020-02-22 00:01:47 +00:00
if ! strings . Contains ( rr . Output ( ) , el ) {
2020-04-02 04:34:37 +00:00
t . Errorf ( "expected to have label %q in node labels but got : %s" , el , rr . Output ( ) )
2020-02-20 21:57:09 +00:00
}
}
}
2021-11-07 06:28:19 +00:00
// tagAndLoadImage is a helper function to pull, tag, load image (decreases cyclomatic complexity for linter).
func tagAndLoadImage ( ctx context . Context , t * testing . T , profile , taggedImage string ) {
newPulledImage := fmt . Sprintf ( "%s:%s" , addonResizer , "1.8.9" )
rr , err := Run ( t , exec . CommandContext ( ctx , "docker" , "pull" , newPulledImage ) )
if err != nil {
t . Fatalf ( "failed to setup test (pull image): %v\n%s" , err , rr . Output ( ) )
}
rr , err = Run ( t , exec . CommandContext ( ctx , "docker" , "tag" , newPulledImage , taggedImage ) )
if err != nil {
t . Fatalf ( "failed to setup test (tag image) : %v\n%s" , err , rr . Output ( ) )
}
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "load" , "--daemon" , taggedImage ) )
if err != nil {
t . Fatalf ( "loading image into minikube from daemon: %v\n%s" , err , rr . Output ( ) )
}
checkImageExists ( ctx , t , profile , taggedImage )
}
2021-12-21 23:57:03 +00:00
// runImageList is a helper function to run 'image ls' command test.
2022-01-19 17:54:05 +00:00
func runImageList ( ctx context . Context , t * testing . T , profile , testName , format , expectedFormat string ) {
expectedResult := expectedImageFormat ( expectedFormat )
2021-10-11 01:46:44 +00:00
// docs: Make sure image listing works by `minikube image ls`
2021-12-21 23:57:03 +00:00
t . Run ( testName , func ( t * testing . T ) {
2021-09-17 17:52:01 +00:00
MaybeParallel ( t )
2021-09-16 20:34:26 +00:00
2021-12-21 23:57:03 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "ls" , "--format" , format ) )
2021-09-17 17:52:01 +00:00
if err != nil {
t . Fatalf ( "listing image with minikube: %v\n%s" , err , rr . Output ( ) )
}
if rr . Stdout . Len ( ) > 0 {
t . Logf ( "(dbg) Stdout: %s:\n%s" , rr . Command ( ) , rr . Stdout )
}
if rr . Stderr . Len ( ) > 0 {
t . Logf ( "(dbg) Stderr: %s:\n%s" , rr . Command ( ) , rr . Stderr )
}
2021-09-16 20:34:26 +00:00
2021-09-17 17:52:01 +00:00
list := rr . Output ( )
2021-12-21 23:57:03 +00:00
for _ , theImage := range expectedResult {
2021-09-17 17:52:01 +00:00
if ! strings . Contains ( list , theImage ) {
t . Fatalf ( "expected %s to be listed with minikube but the image is not there" , theImage )
}
}
} )
2021-12-21 23:57:03 +00:00
}
2022-01-19 00:33:03 +00:00
func expectedImageFormat ( format string ) [ ] string {
return [ ] string {
fmt . Sprintf ( format , "k8s.gcr.io/pause" ) ,
2022-08-31 22:01:18 +00:00
fmt . Sprintf ( format , "registry.k8s.io/kube-apiserver" ) ,
2022-01-19 00:33:03 +00:00
}
}
2021-12-21 23:57:03 +00:00
// validateImageCommands runs tests on all the `minikube image` commands, ex. `minikube image load`, `minikube image list`, etc.
func validateImageCommands ( ctx context . Context , t * testing . T , profile string ) {
// docs(skip): Skips on `none` driver as image loading is not supported
if NoneDriver ( ) {
t . Skip ( "image commands are not available on the none driver" )
}
// docs(skip): Skips on GitHub Actions and macOS as this test case requires a running docker daemon
2022-01-06 17:56:54 +00:00
if detect . GithubActionRunner ( ) && runtime . GOOS == "darwin" {
2021-12-21 23:57:03 +00:00
t . Skip ( "skipping on darwin github action runners, as this test requires a running docker daemon" )
}
2022-01-19 17:54:05 +00:00
runImageList ( ctx , t , profile , "ImageListShort" , "short" , "%s" )
runImageList ( ctx , t , profile , "ImageListTable" , "table" , "| %s" )
runImageList ( ctx , t , profile , "ImageListJson" , "json" , "[\"%s" )
runImageList ( ctx , t , profile , "ImageListYaml" , "yaml" , "- %s" )
2021-09-16 20:34:26 +00:00
2021-10-11 01:46:44 +00:00
// docs: Make sure image building works by `minikube image build`
2021-09-17 17:52:01 +00:00
t . Run ( "ImageBuild" , func ( t * testing . T ) {
MaybeParallel ( t )
2021-03-25 20:20:12 +00:00
2021-10-01 21:30:00 +00:00
if _ , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , "pgrep" , "buildkitd" ) ) ; err == nil {
2021-10-01 19:02:34 +00:00
t . Errorf ( "buildkitd process is running, should not be running until `minikube image build` is ran" )
}
2021-09-17 17:52:01 +00:00
newImage := fmt . Sprintf ( "localhost/my-image:%s" , profile )
2021-03-25 20:20:12 +00:00
2021-09-17 17:52:01 +00:00
// try to build the new image with minikube
2021-10-01 21:30:00 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "build" , "-t" , newImage , filepath . Join ( * testdataDir , "build" ) ) )
2021-09-17 17:52:01 +00:00
if err != nil {
t . Fatalf ( "building image with minikube: %v\n%s" , err , rr . Output ( ) )
}
if rr . Stdout . Len ( ) > 0 {
t . Logf ( "(dbg) Stdout: %s:\n%s" , rr . Command ( ) , rr . Stdout )
}
if rr . Stderr . Len ( ) > 0 {
t . Logf ( "(dbg) Stderr: %s:\n%s" , rr . Command ( ) , rr . Stderr )
}
2021-08-06 22:01:38 +00:00
2021-09-17 17:52:01 +00:00
checkImageExists ( ctx , t , profile , newImage )
} )
2021-08-09 20:41:44 +00:00
2021-09-17 17:52:01 +00:00
taggedImage := fmt . Sprintf ( "%s:%s" , addonResizer , profile )
imageFile := "addon-resizer-save.tar"
var imagePath string
2021-08-06 22:01:38 +00:00
defer os . Remove ( imageFile )
2021-09-17 17:52:01 +00:00
t . Run ( "Setup" , func ( t * testing . T ) {
var err error
imagePath , err = filepath . Abs ( imageFile )
if err != nil {
t . Fatalf ( "failed to get absolute path of file %q: %v" , imageFile , err )
}
2021-03-10 02:53:22 +00:00
2021-09-17 17:52:01 +00:00
pulledImage := fmt . Sprintf ( "%s:%s" , addonResizer , "1.8.8" )
rr , err := Run ( t , exec . CommandContext ( ctx , "docker" , "pull" , pulledImage ) )
if err != nil {
t . Fatalf ( "failed to setup test (pull image): %v\n%s" , err , rr . Output ( ) )
}
2021-02-05 22:26:44 +00:00
2021-09-17 17:52:01 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , "docker" , "tag" , pulledImage , taggedImage ) )
if err != nil {
t . Fatalf ( "failed to setup test (tag image) : %v\n%s" , err , rr . Output ( ) )
}
} )
2021-08-15 18:25:37 +00:00
2021-10-11 01:46:44 +00:00
// docs: Make sure image loading from Docker daemon works by `minikube image load --daemon`
2021-09-17 17:52:01 +00:00
t . Run ( "ImageLoadDaemon" , func ( t * testing . T ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "load" , "--daemon" , taggedImage ) )
if err != nil {
t . Fatalf ( "loading image into minikube from daemon: %v\n%s" , err , rr . Output ( ) )
}
2021-08-15 18:25:37 +00:00
2021-09-17 17:52:01 +00:00
checkImageExists ( ctx , t , profile , taggedImage )
} )
2021-08-15 18:25:37 +00:00
2021-11-07 06:28:19 +00:00
// docs: Try to load image already loaded and make sure `minikube image load --daemon` works
t . Run ( "ImageReloadDaemon" , func ( t * testing . T ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "load" , "--daemon" , taggedImage ) )
if err != nil {
t . Fatalf ( "loading image into minikube from daemon: %v\n%s" , err , rr . Output ( ) )
}
checkImageExists ( ctx , t , profile , taggedImage )
} )
// docs: Make sure a new updated tag works by `minikube image load --daemon`
t . Run ( "ImageTagAndLoadDaemon" , func ( t * testing . T ) {
tagAndLoadImage ( ctx , t , profile , taggedImage )
} )
2021-10-11 01:46:44 +00:00
// docs: Make sure image saving works by `minikube image load --daemon`
2021-09-17 17:52:01 +00:00
t . Run ( "ImageSaveToFile" , func ( t * testing . T ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "save" , taggedImage , imagePath ) )
if err != nil {
t . Fatalf ( "saving image from minikube to file: %v\n%s" , err , rr . Output ( ) )
}
2021-08-15 18:25:37 +00:00
2021-09-17 17:52:01 +00:00
if _ , err := os . Stat ( imagePath ) ; err != nil {
t . Fatalf ( "expected %q to exist after `image save`, but doesn't exist" , imagePath )
}
} )
2021-08-15 18:25:37 +00:00
2021-10-11 01:46:44 +00:00
// docs: Make sure image removal works by `minikube image rm`
2021-09-17 17:52:01 +00:00
t . Run ( "ImageRemove" , func ( t * testing . T ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "rm" , taggedImage ) )
if err != nil {
t . Fatalf ( "removing image from minikube: %v\n%s" , err , rr . Output ( ) )
}
2021-08-15 18:25:37 +00:00
2021-09-17 17:52:01 +00:00
// make sure the image was removed
rr , err = listImages ( ctx , t , profile )
if err != nil {
t . Fatalf ( "listing images: %v\n%s" , err , rr . Output ( ) )
}
if strings . Contains ( rr . Output ( ) , taggedImage ) {
t . Fatalf ( "expected %q to be removed from minikube but still exists" , taggedImage )
}
} )
2021-08-15 18:25:37 +00:00
2021-10-11 01:46:44 +00:00
// docs: Make sure image loading from file works by `minikube image load`
2021-09-17 17:52:01 +00:00
t . Run ( "ImageLoadFromFile" , func ( t * testing . T ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "load" , imagePath ) )
if err != nil || rr . Stderr . String ( ) != "" {
t . Fatalf ( "loading image into minikube from file: %v\n%s" , err , rr . Output ( ) )
}
2021-08-15 18:25:37 +00:00
2021-09-17 17:52:01 +00:00
checkImageExists ( ctx , t , profile , taggedImage )
} )
2021-08-15 18:25:37 +00:00
2021-10-11 01:46:44 +00:00
// docs: Make sure image saving to Docker daemon works by `minikube image load`
2021-09-17 17:52:01 +00:00
t . Run ( "ImageSaveDaemon" , func ( t * testing . T ) {
rr , err := Run ( t , exec . CommandContext ( ctx , "docker" , "rmi" , taggedImage ) )
if err != nil {
t . Fatalf ( "failed to remove image from docker: %v\n%s" , err , rr . Output ( ) )
}
2021-08-15 18:25:37 +00:00
2021-09-17 17:52:01 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "save" , "--daemon" , taggedImage ) )
if err != nil {
t . Fatalf ( "saving image from minikube to daemon: %v\n%s" , err , rr . Output ( ) )
}
2021-04-23 20:00:17 +00:00
2021-09-17 17:52:01 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , "docker" , "image" , "inspect" , taggedImage ) )
if err != nil {
t . Fatalf ( "expected image to be loaded into Docker, but image was not found: %v\n%s" , err , rr . Output ( ) )
}
} )
2021-03-25 20:20:12 +00:00
}
2021-09-17 17:52:01 +00:00
func checkImageExists ( ctx context . Context , t * testing . T , profile string , image string ) {
// make sure the image was correctly loaded
rr , err := listImages ( ctx , t , profile )
2021-04-23 15:40:19 +00:00
if err != nil {
t . Fatalf ( "listing images: %v\n%s" , err , rr . Output ( ) )
}
2021-09-17 17:52:01 +00:00
if ! strings . Contains ( rr . Output ( ) , image ) {
t . Fatalf ( "expected %q to be loaded into minikube but the image is not there" , image )
2021-04-23 15:40:19 +00:00
}
}
2021-09-17 17:52:01 +00:00
func listImages ( ctx context . Context , t * testing . T , profile string ) ( * RunResult , error ) {
return Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "image" , "ls" ) )
2021-05-01 11:45:13 +00:00
}
2021-05-05 20:28:39 +00:00
// check functionality of minikube after evaluating docker-env
2020-02-13 09:17:11 +00:00
func validateDockerEnv ( ctx context . Context , t * testing . T , profile string ) {
2021-10-11 01:46:44 +00:00
// docs(skip): Skips on `none` drive since `docker-env` is not supported
2021-03-11 18:23:16 +00:00
if NoneDriver ( ) {
t . Skipf ( "none driver does not support docker-env" )
}
2021-10-11 01:46:44 +00:00
// docs(skip): Skips on non-docker container runtime
2021-01-22 23:03:18 +00:00
if cr := ContainerRuntime ( ) ; cr != "docker" {
t . Skipf ( "only validate docker env with docker container runtime, currently testing %s" , cr )
}
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-08-23 23:04:06 +00:00
type ShellTest struct {
name string
commandPrefix [ ] string
formatArg string
2020-02-13 09:17:11 +00:00
}
2021-08-23 23:04:06 +00:00
2021-10-11 01:46:44 +00:00
// docs: Run `eval $(minikube docker-env)` to configure current environment to use minikube's Docker daemon
2021-08-23 23:04:06 +00:00
windowsTests := [ ] ShellTest {
{ "powershell" , [ ] string { "powershell.exe" , "-NoProfile" , "-NonInteractive" } , "%[1]s -p %[2]s docker-env | Invoke-Expression ; " } ,
2020-02-13 09:17:11 +00:00
}
2021-08-23 23:04:06 +00:00
posixTests := [ ] ShellTest {
{ "bash" , [ ] string { "/bin/bash" , "-c" } , "eval $(%[1]s -p %[2]s docker-env) && " } ,
2020-02-13 09:17:11 +00:00
}
2021-08-23 23:04:06 +00:00
tests := posixTests
if runtime . GOOS == "windows" {
tests = windowsTests
2020-05-24 11:46:35 +00:00
}
2021-08-23 23:04:06 +00:00
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
mctx , cancel := context . WithTimeout ( ctx , Seconds ( 120 ) )
defer cancel ( )
2020-05-24 11:46:35 +00:00
2021-08-23 23:04:06 +00:00
command := make ( [ ] string , len ( tc . commandPrefix ) + 1 )
2022-05-16 19:48:41 +00:00
copy ( command , tc . commandPrefix )
2020-05-24 22:20:58 +00:00
2021-08-23 23:04:06 +00:00
formattedArg := fmt . Sprintf ( tc . formatArg , Target ( ) , profile )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube status` to get the minikube status
2021-08-23 23:04:06 +00:00
// we should be able to get minikube status with a shell which evaled docker-env
command [ len ( command ) - 1 ] = formattedArg + Target ( ) + " status -p " + profile
c := exec . CommandContext ( mctx , command [ 0 ] , command [ 1 : ] ... )
rr , err := Run ( t , c )
2020-02-13 09:17:11 +00:00
2021-08-23 23:04:06 +00:00
if mctx . Err ( ) == context . DeadlineExceeded {
t . Errorf ( "failed to run the command by deadline. exceeded timeout. %s" , rr . Command ( ) )
}
if err != nil {
t . Fatalf ( "failed to do status after eval-ing docker-env. error: %v" , err )
}
2021-10-11 01:46:44 +00:00
// docs: Make sure minikube components have status `Running`
2021-08-23 23:04:06 +00:00
if ! strings . Contains ( rr . Output ( ) , "Running" ) {
t . Fatalf ( "expected status output to include 'Running' after eval docker-env but got: *%s*" , rr . Output ( ) )
}
2021-10-11 01:46:44 +00:00
// docs: Make sure `docker-env` has status `in-use`
2021-08-23 23:04:06 +00:00
if ! strings . Contains ( rr . Output ( ) , "in-use" ) {
t . Fatalf ( "expected status output to include `in-use` after eval docker-env but got *%s*" , rr . Output ( ) )
}
mctx , cancel = context . WithTimeout ( ctx , Seconds ( 60 ) )
defer cancel ( )
2021-10-11 01:46:44 +00:00
// docs: Run eval `$(minikube -p profile docker-env)` and check if we are point to docker inside minikube
2021-08-23 23:04:06 +00:00
command [ len ( command ) - 1 ] = formattedArg + "docker images"
c = exec . CommandContext ( mctx , command [ 0 ] , command [ 1 : ] ... )
rr , err = Run ( t , c )
if mctx . Err ( ) == context . DeadlineExceeded {
t . Errorf ( "failed to run the command in 30 seconds. exceeded 30s timeout. %s" , rr . Command ( ) )
}
if err != nil {
t . Fatalf ( "failed to run minikube docker-env. args %q : %v " , rr . Command ( ) , err )
}
2021-10-11 01:46:44 +00:00
// docs: Make sure `docker images` hits the minikube's Docker daemon by check if `gcr.io/k8s-minikube/storage-provisioner` is in the output of `docker images`
2021-08-23 23:04:06 +00:00
expectedImgInside := "gcr.io/k8s-minikube/storage-provisioner"
if ! strings . Contains ( rr . Output ( ) , expectedImgInside ) {
t . Fatalf ( "expected 'docker images' to have %q inside minikube. but the output is: *%s*" , expectedImgInside , rr . Output ( ) )
}
} )
2020-02-13 09:17:11 +00:00
}
}
2021-05-05 20:28:39 +00:00
// check functionality of minikube after evaluating podman-env
func validatePodmanEnv ( ctx context . Context , t * testing . T , profile string ) {
2021-10-11 01:46:44 +00:00
// docs(skip): Skips on `none` drive since `podman-env` is not supported
2021-05-05 20:28:39 +00:00
if NoneDriver ( ) {
t . Skipf ( "none driver does not support podman-env" )
}
2021-10-11 01:46:44 +00:00
// docs(skip): Skips on non-docker container runtime
2021-05-05 20:28:39 +00:00
if cr := ContainerRuntime ( ) ; cr != "podman" {
t . Skipf ( "only validate podman env with docker container runtime, currently testing %s" , cr )
}
2021-10-11 01:46:44 +00:00
// docs(skip): Skips on non-Linux platforms
2021-05-05 20:28:39 +00:00
if runtime . GOOS != "linux" {
t . Skipf ( "only validate podman env on linux, currently testing %s" , runtime . GOOS )
}
defer PostMortemLogs ( t , profile )
mctx , cancel := context . WithTimeout ( ctx , Seconds ( 120 ) )
defer cancel ( )
2021-10-11 01:46:44 +00:00
// docs: Run `eval $(minikube podman-env)` to configure current environment to use minikube's Podman daemon, and `minikube status` to get the minikube status
2021-05-05 20:28:39 +00:00
c := exec . CommandContext ( mctx , "/bin/bash" , "-c" , "eval $(" + Target ( ) + " -p " + profile + " podman-env) && " + Target ( ) + " status -p " + profile )
// we should be able to get minikube status with a bash which evaluated podman-env
rr , err := Run ( t , c )
if mctx . Err ( ) == context . DeadlineExceeded {
t . Errorf ( "failed to run the command by deadline. exceeded timeout. %s" , rr . Command ( ) )
}
if err != nil {
t . Fatalf ( "failed to do status after eval-ing podman-env. error: %v" , err )
}
2021-10-11 01:46:44 +00:00
// docs: Make sure minikube components have status `Running`
2021-05-05 20:28:39 +00:00
if ! strings . Contains ( rr . Output ( ) , "Running" ) {
t . Fatalf ( "expected status output to include 'Running' after eval podman-env but got: *%s*" , rr . Output ( ) )
}
2021-10-11 01:46:44 +00:00
// docs: Make sure `podman-env` has status `in-use`
2021-05-05 20:28:39 +00:00
if ! strings . Contains ( rr . Output ( ) , "in-use" ) {
t . Fatalf ( "expected status output to include `in-use` after eval podman-env but got *%s*" , rr . Output ( ) )
}
mctx , cancel = context . WithTimeout ( ctx , Seconds ( 60 ) )
defer cancel ( )
2021-10-11 01:46:44 +00:00
// docs: Run `eval $(minikube docker-env)` again and `docker images` to list the docker images using the minikube's Docker daemon
2021-05-05 20:28:39 +00:00
c = exec . CommandContext ( mctx , "/bin/bash" , "-c" , "eval $(" + Target ( ) + " -p " + profile + " podman-env) && docker images" )
rr , err = Run ( t , c )
if mctx . Err ( ) == context . DeadlineExceeded {
t . Errorf ( "failed to run the command in 30 seconds. exceeded 30s timeout. %s" , rr . Command ( ) )
}
if err != nil {
t . Fatalf ( "failed to run minikube podman-env. args %q : %v " , rr . Command ( ) , err )
}
2021-10-11 01:46:44 +00:00
// docs: Make sure `docker images` hits the minikube's Podman daemon by check if `gcr.io/k8s-minikube/storage-provisioner` is in the output of `docker images`
2021-05-05 20:28:39 +00:00
expectedImgInside := "gcr.io/k8s-minikube/storage-provisioner"
if ! strings . Contains ( rr . Output ( ) , expectedImgInside ) {
t . Fatalf ( "expected 'docker images' to have %q inside minikube. but the output is: *%s*" , expectedImgInside , rr . Output ( ) )
}
}
2021-04-16 20:42:41 +00:00
// validateStartWithProxy makes sure minikube start respects the HTTP_PROXY environment variable
2020-04-07 04:26:45 +00:00
func validateStartWithProxy ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-10-11 01:46:44 +00:00
// docs: Start a local HTTP proxy
2019-09-11 16:59:38 +00:00
srv , err := startHTTPProxy ( t )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Fatalf ( "failed to set up the test proxy: %s" , err )
2019-09-11 16:59:38 +00:00
}
2019-11-06 23:17:09 +00:00
2021-10-11 01:46:44 +00:00
// docs: Start minikube with the environment variable `HTTP_PROXY` set to the local HTTP proxy
2021-06-24 22:41:04 +00:00
startMinikubeWithProxy ( ctx , t , profile , "HTTP_PROXY" , srv . Addr )
}
2019-09-11 16:59:38 +00:00
2021-06-30 23:59:08 +00:00
// validateStartWithCustomCerts makes sure minikube start respects the HTTPS_PROXY environment variable and works with custom certs
// a proxy is started by calling the mitmdump binary in the background, then installing the certs generated by the binary
// mitmproxy/dump creates the proxy at localhost at port 8080
2022-04-25 07:57:45 +00:00
// only runs on GitHub Actions for amd64 linux, otherwise validateStartWithProxy runs instead
2021-06-25 18:36:18 +00:00
func validateStartWithCustomCerts ( ctx context . Context , t * testing . T , profile string ) {
2021-06-24 22:41:04 +00:00
defer PostMortemLogs ( t , profile )
2021-06-30 16:16:25 +00:00
err := startProxyWithCustomCerts ( ctx , t )
2021-06-24 22:41:04 +00:00
if err != nil {
t . Fatalf ( "failed to set up the test proxy: %s" , err )
2019-09-11 16:59:38 +00:00
}
2021-01-21 00:30:48 +00:00
2021-06-24 22:41:04 +00:00
startMinikubeWithProxy ( ctx , t , profile , "HTTPS_PROXY" , "127.0.0.1:8080" )
2021-02-20 04:49:41 +00:00
}
2021-04-16 20:42:41 +00:00
// validateAuditAfterStart makes sure the audit log contains the correct logging after minikube start
2021-02-20 04:49:41 +00:00
func validateAuditAfterStart ( ctx context . Context , t * testing . T , profile string ) {
2021-10-11 01:46:44 +00:00
// docs: Read the audit log file and make sure it contains the current minikube profile name
2021-02-20 04:49:41 +00:00
got , err := auditContains ( profile )
if err != nil {
t . Fatalf ( "failed to check audit log: %v" , err )
}
if ! got {
t . Errorf ( "audit.json does not contain the profile %q" , profile )
}
2019-09-11 16:59:38 +00:00
}
2021-10-11 01:46:44 +00:00
// validateSoftStart validates that after minikube already started, a `minikube start` should not change the configs.
2020-04-07 04:26:45 +00:00
func validateSoftStart ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2020-04-07 04:06:27 +00:00
start := time . Now ( )
2021-10-11 01:46:44 +00:00
// docs: The test `validateStartWithProxy` should have start minikube, make sure the configured node port is `8441`
2020-04-07 04:26:45 +00:00
beforeCfg , err := config . LoadProfile ( profile )
if err != nil {
2020-05-28 21:42:00 +00:00
t . Fatalf ( "error reading cluster config before soft start: %v" , err )
2020-04-07 04:26:45 +00:00
}
2020-04-07 20:14:30 +00:00
if beforeCfg . Config . KubernetesConfig . NodePort != apiPortTest {
t . Errorf ( "expected cluster config node port before soft start to be %d but got %d" , apiPortTest , beforeCfg . Config . KubernetesConfig . NodePort )
2020-04-07 04:03:12 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube start` again as a soft start
2020-08-10 21:48:44 +00:00
softStartArgs := [ ] string { "start" , "-p" , profile , "--alsologtostderr" , "-v=8" }
2020-04-07 04:03:12 +00:00
c := exec . CommandContext ( ctx , Target ( ) , softStartArgs ... )
2020-04-07 04:26:45 +00:00
rr , err := Run ( t , c )
2020-04-07 04:03:12 +00:00
if err != nil {
t . Errorf ( "failed to soft start minikube. args %q: %v" , rr . Command ( ) , err )
}
2020-04-07 04:06:27 +00:00
t . Logf ( "soft start took %s for %q cluster." , time . Since ( start ) , profile )
2020-04-07 04:03:12 +00:00
2021-10-11 01:46:44 +00:00
// docs: Make sure the configured node port is not changed
2020-04-07 04:26:45 +00:00
afterCfg , err := config . LoadProfile ( profile )
if err != nil {
t . Errorf ( "error reading cluster config after soft start: %v" , err )
}
2020-04-07 20:14:30 +00:00
if afterCfg . Config . KubernetesConfig . NodePort != apiPortTest {
t . Errorf ( "expected node port in the config not change after soft start. exepceted node port to be %d but got %d." , apiPortTest , afterCfg . Config . KubernetesConfig . NodePort )
2020-04-07 04:03:12 +00:00
}
}
2019-09-11 16:59:38 +00:00
// validateKubeContext asserts that kubectl is properly configured (race-condition prone!)
func validateKubeContext ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-10-11 01:46:44 +00:00
// docs: Run `kubectl config current-context`
2019-09-11 16:59:38 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "config" , "current-context" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to get current-context. args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Make sure the current minikube profile name is in the output of the command
2019-09-11 16:59:38 +00:00
if ! strings . Contains ( rr . Stdout . String ( ) , profile ) {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected current-context = %q, but got *%q*" , profile , rr . Stdout . String ( ) )
2019-09-11 16:59:38 +00:00
}
}
2019-10-28 23:50:01 +00:00
// validateKubectlGetPods asserts that `kubectl get pod -A` returns non-zero content
func validateKubectlGetPods ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-10-11 01:46:44 +00:00
// docs: Run `kubectl get po -A` to get all pods in the current minikube profile
2019-11-13 05:38:31 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "po" , "-A" ) )
2019-10-28 23:50:01 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to get kubectl pods: args %q : %v" , rr . Command ( ) , err )
2019-10-28 23:50:01 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Make sure the output is not empty and contains `kube-system` components
2019-11-13 05:38:31 +00:00
if rr . Stderr . String ( ) != "" {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected stderr to be empty but got *%q*: args %q" , rr . Stderr , rr . Command ( ) )
2019-11-13 05:38:31 +00:00
}
2019-11-12 22:19:52 +00:00
if ! strings . Contains ( rr . Stdout . String ( ) , "kube-system" ) {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected stdout to include *kube-system* but got *%q*. args: %q" , rr . Stdout , rr . Command ( ) )
2019-10-28 23:50:01 +00:00
}
}
2020-02-12 17:54:17 +00:00
// validateMinikubeKubectl validates that the `minikube kubectl` command returns content
func validateMinikubeKubectl ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube kubectl -- get pods` to get the pods in the current minikube profile
2020-03-25 21:57:27 +00:00
// Must set the profile so that it knows what version of Kubernetes to use
kubectlArgs := [ ] string { "-p" , profile , "kubectl" , "--" , "--context" , profile , "get" , "pods" }
2020-02-13 21:34:05 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , kubectlArgs ... ) )
2021-10-11 01:46:44 +00:00
// docs: Make sure the command doesn't raise any error
2020-02-12 17:54:17 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to get pods. args %q: %v" , rr . Command ( ) , err )
2020-02-12 17:54:17 +00:00
}
}
2020-08-17 02:52:21 +00:00
// validateMinikubeKubectlDirectCall validates that calling minikube's kubectl
func validateMinikubeKubectlDirectCall ( ctx context . Context , t * testing . T , profile string ) {
defer PostMortemLogs ( t , profile )
dir := filepath . Dir ( Target ( ) )
2021-06-30 20:41:11 +00:00
newName := "kubectl"
if runtime . GOOS == "windows" {
newName += ".exe"
}
dstfn := filepath . Join ( dir , newName )
2020-08-17 02:52:21 +00:00
err := os . Link ( Target ( ) , dstfn )
if err != nil {
t . Fatal ( err )
}
defer os . Remove ( dstfn ) // clean up
2021-10-11 01:46:44 +00:00
// docs: Run `kubectl get pods` by calling the minikube's `kubectl` binary file directly
2020-10-28 19:16:02 +00:00
kubectlArgs := [ ] string { "--context" , profile , "get" , "pods" }
2020-08-17 02:52:21 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , dstfn , kubectlArgs ... ) )
2021-10-11 01:46:44 +00:00
// docs: Make sure the command doesn't raise any error
2020-08-17 02:52:21 +00:00
if err != nil {
2020-10-27 17:00:41 +00:00
t . Fatalf ( "failed to run kubectl directly. args %q: %v" , rr . Command ( ) , err )
2020-08-17 02:52:21 +00:00
}
}
2021-04-16 20:42:41 +00:00
// validateExtraConfig verifies minikube with --extra-config works as expected
2020-11-28 20:40:09 +00:00
func validateExtraConfig ( ctx context . Context , t * testing . T , profile string ) {
defer PostMortemLogs ( t , profile )
start := time . Now ( )
2021-10-11 01:46:44 +00:00
// docs: The tests before this already created a profile
// docs: Soft-start minikube with different `--extra-config` command line option
2021-02-12 02:13:06 +00:00
startArgs := [ ] string { "start" , "-p" , profile , "--extra-config=apiserver.enable-admission-plugins=NamespaceAutoProvision" , "--wait=all" }
2020-11-28 20:40:09 +00:00
c := exec . CommandContext ( ctx , Target ( ) , startArgs ... )
rr , err := Run ( t , c )
if err != nil {
t . Errorf ( "failed to restart minikube. args %q: %v" , rr . Command ( ) , err )
}
t . Logf ( "restart took %s for %q cluster." , time . Since ( start ) , profile )
2021-10-11 01:46:44 +00:00
// docs: Load the profile's config
2020-11-28 20:40:09 +00:00
afterCfg , err := config . LoadProfile ( profile )
if err != nil {
t . Errorf ( "error reading cluster config after soft start: %v" , err )
}
2021-10-11 01:46:44 +00:00
// docs: Make sure the specified `--extra-config` is correctly returned
2020-11-28 20:40:09 +00:00
expectedExtraOptions := "apiserver.enable-admission-plugins=NamespaceAutoProvision"
2022-01-12 21:48:49 +00:00
if ! strings . Contains ( afterCfg . Config . KubernetesConfig . ExtraOptions . String ( ) , expectedExtraOptions ) {
t . Errorf ( "expected ExtraOptions to contain %s but got %s" , expectedExtraOptions , afterCfg . Config . KubernetesConfig . ExtraOptions . String ( ) )
}
2020-11-28 20:40:09 +00:00
}
2021-01-14 20:34:46 +00:00
// imageID returns a docker image id for image `image` and current architecture
// 'image' is supposed to be one commonly used in minikube integration tests,
// like k8s 'pause'
2021-01-13 21:58:55 +00:00
func imageID ( image string ) string {
ids := map [ string ] map [ string ] string {
"pause" : {
2021-03-05 19:43:53 +00:00
"amd64" : "0184c1613d929" ,
"arm64" : "3d18732f8686c" ,
2021-01-13 21:58:55 +00:00
} ,
}
if imgIds , ok := ids [ image ] ; ok {
if id , ok := imgIds [ runtime . GOARCH ] ; ok {
return id
}
panic ( fmt . Sprintf ( "unexpected architecture for image %q: %v" , image , runtime . GOARCH ) )
}
panic ( "unexpected image name: " + image )
}
2019-09-11 16:59:38 +00:00
// validateComponentHealth asserts that all Kubernetes components are healthy
2021-04-16 20:42:41 +00:00
// NOTE: It expects all components to be Ready, so it makes sense to run it close after only those tests that include '--wait=all' start flag
2019-09-11 16:59:38 +00:00
func validateComponentHealth ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2020-08-21 23:07:39 +00:00
// The ComponentStatus API is deprecated in v1.19, so do the next closest thing.
found := map [ string ] bool {
"etcd" : false ,
"kube-apiserver" : false ,
"kube-controller-manager" : false ,
"kube-scheduler" : false ,
}
2021-10-11 01:46:44 +00:00
// docs: Run `kubectl get po po -l tier=control-plane -n kube-system -o=json` to get all the Kubernetes conponents
2020-08-21 23:07:39 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "po" , "-l" , "tier=control-plane" , "-n" , "kube-system" , "-o=json" ) )
2019-09-11 16:59:38 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to get components. args %q: %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
2020-08-21 23:07:39 +00:00
cs := api . PodList { }
2019-09-11 16:59:38 +00:00
d := json . NewDecoder ( bytes . NewReader ( rr . Stdout . Bytes ( ) ) )
if err := d . Decode ( & cs ) ; err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to decode kubectl json output: args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: For each component, make sure the pod status is `Running`
2019-09-11 16:59:38 +00:00
for _ , i := range cs . Items {
2020-08-21 23:07:39 +00:00
for _ , l := range i . Labels {
2021-02-09 19:51:26 +00:00
if _ , ok := found [ l ] ; ok { // skip irrelevant (eg, repeating/redundant '"tier": "control-plane"') labels
2020-08-21 23:07:39 +00:00
found [ l ] = true
2021-02-09 19:51:26 +00:00
t . Logf ( "%s phase: %s" , l , i . Status . Phase )
if i . Status . Phase != api . PodRunning {
2020-08-21 23:07:39 +00:00
t . Errorf ( "%s is not Running: %+v" , l , i . Status )
2021-02-09 19:51:26 +00:00
continue
}
for _ , c := range i . Status . Conditions {
if c . Type == api . PodReady {
if c . Status != api . ConditionTrue {
t . Errorf ( "%s is not Ready: %+v" , l , i . Status )
} else {
t . Logf ( "%s status: %s" , l , c . Type )
}
break
}
2020-08-21 23:07:39 +00:00
}
2019-09-11 16:59:38 +00:00
}
}
2020-08-21 23:07:39 +00:00
}
for k , v := range found {
if ! v {
t . Errorf ( "expected component %q was not found" , k )
2019-09-11 16:59:38 +00:00
}
}
}
2021-10-11 01:46:44 +00:00
// validateStatusCmd makes sure `minikube status` outputs correctly
2019-10-13 15:24:40 +00:00
func validateStatusCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2019-10-21 18:00:01 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "status" ) )
2019-10-13 15:24:40 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to run minikube status. args %q : %v" , rr . Command ( ) , err )
2019-10-13 15:24:40 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube status` with custom format `host:{{.Host}},kublet:{{.Kubelet}},apiserver:{{.APIServer}},kubeconfig:{{.Kubeconfig}}`
2019-10-21 18:00:01 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "status" , "-f" , "host:{{.Host}},kublet:{{.Kubelet}},apiserver:{{.APIServer}},kubeconfig:{{.Kubeconfig}}" ) )
2019-10-13 15:24:40 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to run minikube status with custom format: args %q: %v" , rr . Command ( ) , err )
2019-10-13 15:24:40 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Make sure `host`, `kublete`, `apiserver` and `kubeconfig` statuses are shown in the output
2020-03-26 04:43:32 +00:00
re := ` host:([A-z]+),kublet:([A-z]+),apiserver:([A-z]+),kubeconfig:([A-z]+) `
match , _ := regexp . MatchString ( re , rr . Stdout . String ( ) )
2019-10-13 15:24:40 +00:00
if ! match {
2020-04-02 04:40:09 +00:00
t . Errorf ( "failed to match regex %q for minikube status with custom format. args %q. output: %s" , re , rr . Command ( ) , rr . Output ( ) )
2019-10-13 15:24:40 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube status` again as JSON output
2019-10-21 18:00:01 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "status" , "-o" , "json" ) )
2019-10-13 15:24:40 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to run minikube status with json output. args %q : %v" , rr . Command ( ) , err )
2019-10-13 15:24:40 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Make sure `host`, `kublete`, `apiserver` and `kubeconfig` statuses are set in the JSON output
2019-10-13 15:24:40 +00:00
var jsonObject map [ string ] interface { }
err = json . Unmarshal ( rr . Stdout . Bytes ( ) , & jsonObject )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to decode json from minikube status. args %q. %v" , rr . Command ( ) , err )
2019-10-13 15:24:40 +00:00
}
if _ , ok := jsonObject [ "Host" ] ; ! ok {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%q failed: %v. Missing key %s in json object" , rr . Command ( ) , err , "Host" )
2019-10-13 15:24:40 +00:00
}
if _ , ok := jsonObject [ "Kubelet" ] ; ! ok {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%q failed: %v. Missing key %s in json object" , rr . Command ( ) , err , "Kubelet" )
2019-10-13 15:24:40 +00:00
}
if _ , ok := jsonObject [ "APIServer" ] ; ! ok {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%q failed: %v. Missing key %s in json object" , rr . Command ( ) , err , "APIServer" )
2019-10-13 15:24:40 +00:00
}
if _ , ok := jsonObject [ "Kubeconfig" ] ; ! ok {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%q failed: %v. Missing key %s in json object" , rr . Command ( ) , err , "Kubeconfig" )
2019-10-13 15:24:40 +00:00
}
}
2019-09-11 16:59:38 +00:00
// validateDashboardCmd asserts that the dashboard command works
func validateDashboardCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-02-18 20:34:13 +00:00
mctx , cancel := context . WithTimeout ( ctx , Seconds ( 300 ) )
defer cancel ( )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube dashboard --url` to start minikube dashboard and return the URL of it
2021-07-03 14:27:32 +00:00
args := [ ] string { "dashboard" , "--url" , "--port" , "36195" , "-p" , profile , "--alsologtostderr" , "-v=1" }
2021-02-18 20:34:13 +00:00
ss , err := Start ( t , exec . CommandContext ( mctx , Target ( ) , args ... ) )
2019-09-11 16:59:38 +00:00
if err != nil {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed to run minikube dashboard. args %q : %v" , args , err )
2019-09-11 16:59:38 +00:00
}
defer func ( ) {
ss . Stop ( t )
} ( )
2021-02-19 00:42:06 +00:00
s , err := dashboardURL ( ss . Stdout )
2019-09-11 16:59:38 +00:00
if err != nil {
2019-11-06 22:14:56 +00:00
if runtime . GOOS == "windows" {
2021-02-18 20:34:13 +00:00
t . Skip ( err )
2019-11-06 22:14:56 +00:00
}
2021-02-18 20:34:13 +00:00
t . Fatal ( err )
2019-09-11 16:59:38 +00:00
}
u , err := url . Parse ( strings . TrimSpace ( s ) )
if err != nil {
t . Fatalf ( "failed to parse %q: %v" , s , err )
}
2021-10-11 01:46:44 +00:00
// docs: Send a GET request to the dashboard URL
2019-09-11 16:59:38 +00:00
resp , err := retryablehttp . Get ( u . String ( ) )
if err != nil {
2020-04-02 17:51:15 +00:00
t . Fatalf ( "failed to http get %q: %v\nresponse: %+v" , u . String ( ) , err , resp )
2019-09-11 16:59:38 +00:00
}
2020-04-02 17:51:15 +00:00
2021-10-11 01:46:44 +00:00
// docs: Make sure HTTP status OK is returned
2019-09-11 16:59:38 +00:00
if resp . StatusCode != http . StatusOK {
2021-09-28 10:58:01 +00:00
body , err := io . ReadAll ( resp . Body )
2019-09-11 16:59:38 +00:00
if err != nil {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed to read http response body from dashboard %q: %v" , u . String ( ) , err )
2019-09-11 16:59:38 +00:00
}
t . Errorf ( "%s returned status code %d, expected %d.\nbody:\n%s" , u , resp . StatusCode , http . StatusOK , body )
}
}
2019-07-30 04:52:05 +00:00
2021-02-18 20:34:13 +00:00
// dashboardURL gets the dashboard URL from the command stdout.
2021-02-19 00:42:06 +00:00
func dashboardURL ( b * bufio . Reader ) ( string , error ) {
2021-02-19 00:34:22 +00:00
// match http://127.0.0.1:XXXXX/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/
2021-02-19 00:42:06 +00:00
dashURLRegexp := regexp . MustCompile ( ` ^http:\/\/127\.0\.0\.1:[0-9] { 5}\/api\/v1\/namespaces\/kubernetes-dashboard\/services\/http:kubernetes-dashboard:\/proxy\/$ ` )
2021-02-19 00:34:22 +00:00
2021-02-19 00:44:23 +00:00
s := bufio . NewScanner ( b )
for s . Scan ( ) {
t := s . Text ( )
if dashURLRegexp . MatchString ( t ) {
return t , nil
2021-02-18 20:34:13 +00:00
}
}
2021-02-19 01:27:55 +00:00
if err := s . Err ( ) ; err != nil {
return "" , fmt . Errorf ( "failed reading input: %v" , err )
}
2021-02-18 20:34:13 +00:00
return "" , fmt . Errorf ( "output didn't produce a URL" )
}
2020-01-09 19:10:23 +00:00
// validateDryRun asserts that the dry-run mode quickly exits with the right code
func validateDryRun ( ctx context . Context , t * testing . T , profile string ) {
2022-01-05 00:53:13 +00:00
// dry-run mode should always be able to finish quickly (<5s) expect Docker Windows
timeout := Seconds ( 5 )
if runtime . GOOS == "windows" && DockerDriver ( ) {
2022-01-25 22:12:57 +00:00
timeout = Seconds ( 10 )
2022-01-05 00:53:13 +00:00
}
mctx , cancel := context . WithTimeout ( ctx , timeout )
2020-01-09 19:10:23 +00:00
defer cancel ( )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube start --dry-run --memory 250MB`
2020-01-09 19:10:23 +00:00
// Too little memory!
2021-01-14 23:01:24 +00:00
startArgs := append ( [ ] string { "start" , "-p" , profile , "--dry-run" , "--memory" , "250MB" , "--alsologtostderr" } , StartArgs ( ) ... )
2020-01-09 19:10:23 +00:00
c := exec . CommandContext ( mctx , Target ( ) , startArgs ... )
rr , err := Run ( t , c )
2021-10-11 01:46:44 +00:00
// docs: Since the 250MB memory is less than the required 2GB, minikube should exit with an exit code `ExInsufficientMemory`
2020-08-31 18:21:23 +00:00
wantCode := reason . ExInsufficientMemory
2020-01-09 19:10:23 +00:00
if rr . ExitCode != wantCode {
2021-04-19 21:37:40 +00:00
if HyperVDriver ( ) {
t . Skip ( "skipping this error on HyperV till this issue is solved https://github.com/kubernetes/minikube/issues/9785" )
} else {
t . Errorf ( "dry-run(250MB) exit code = %d, wanted = %d: %v" , rr . ExitCode , wantCode , err )
}
2020-01-09 19:10:23 +00:00
}
2022-01-25 22:12:57 +00:00
dctx , cancel := context . WithTimeout ( ctx , timeout )
2020-01-09 19:10:23 +00:00
defer cancel ( )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube start --dry-run`
2020-01-22 20:14:05 +00:00
startArgs = append ( [ ] string { "start" , "-p" , profile , "--dry-run" , "--alsologtostderr" , "-v=1" } , StartArgs ( ) ... )
2020-01-09 19:10:23 +00:00
c = exec . CommandContext ( dctx , Target ( ) , startArgs ... )
rr , err = Run ( t , c )
2021-10-11 01:46:44 +00:00
// docs: Make sure the command doesn't raise any error
2020-01-09 19:10:23 +00:00
if rr . ExitCode != 0 || err != nil {
2021-04-19 21:35:54 +00:00
if HyperVDriver ( ) {
2021-04-19 21:37:40 +00:00
t . Skip ( "skipping this error on HyperV till this issue is solved https://github.com/kubernetes/minikube/issues/9785" )
2021-04-19 21:35:54 +00:00
} else {
t . Errorf ( "dry-run exit code = %d, wanted = %d: %v" , rr . ExitCode , 0 , err )
}
2020-01-09 19:10:23 +00:00
}
}
2021-06-18 16:55:58 +00:00
// validateInternationalLanguage asserts that the language used can be changed with environment variables
func validateInternationalLanguage ( ctx context . Context , t * testing . T , profile string ) {
2022-01-05 00:53:13 +00:00
// dry-run mode should always be able to finish quickly (<5s) except Docker Windows
timeout := Seconds ( 5 )
if runtime . GOOS == "windows" && DockerDriver ( ) {
timeout = Seconds ( 10 )
}
mctx , cancel := context . WithTimeout ( ctx , timeout )
2021-06-18 16:55:58 +00:00
defer cancel ( )
// Too little memory!
startArgs := append ( [ ] string { "start" , "-p" , profile , "--dry-run" , "--memory" , "250MB" , "--alsologtostderr" } , StartArgs ( ) ... )
c := exec . CommandContext ( mctx , Target ( ) , startArgs ... )
2021-10-11 01:46:44 +00:00
// docs: Set environment variable `LC_ALL=fr` to enable minikube translation to French
2021-06-18 16:55:58 +00:00
c . Env = append ( os . Environ ( ) , "LC_ALL=fr" )
2021-10-11 01:46:44 +00:00
// docs: Start minikube with memory of 250MB which is too little: `minikube start --dry-run --memory 250MB`
2021-06-18 16:55:58 +00:00
rr , err := Run ( t , c )
wantCode := reason . ExInsufficientMemory
if rr . ExitCode != wantCode {
if HyperVDriver ( ) {
t . Skip ( "skipping this error on HyperV till this issue is solved https://github.com/kubernetes/minikube/issues/9785" )
} else {
t . Errorf ( "dry-run(250MB) exit code = %d, wanted = %d: %v" , rr . ExitCode , wantCode , err )
}
}
2021-10-11 01:46:44 +00:00
// docs: Make sure the dry-run output message is in French
2021-06-18 16:55:58 +00:00
if ! strings . Contains ( rr . Stdout . String ( ) , "Utilisation du pilote" ) {
t . Errorf ( "dry-run output was expected to be in French. Expected \"Utilisation du pilote\", but not present in output:\n%s" , rr . Stdout . String ( ) )
}
}
2019-11-27 00:08:07 +00:00
// validateCacheCmd tests functionality of cache command (cache add, delete, list)
2019-09-11 16:59:38 +00:00
func validateCacheCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2019-09-11 16:59:38 +00:00
if NoneDriver ( ) {
t . Skipf ( "skipping: cache unsupported by none" )
}
2020-09-02 14:25:43 +00:00
2019-11-27 00:19:29 +00:00
t . Run ( "cache" , func ( t * testing . T ) {
2021-10-11 01:46:44 +00:00
// docs: Run `minikube cache add` and make sure we can add a remote image to the cache
2020-09-10 19:58:14 +00:00
t . Run ( "add_remote" , func ( t * testing . T ) {
2021-03-02 00:56:56 +00:00
for _ , img := range [ ] string { "k8s.gcr.io/pause:3.1" , "k8s.gcr.io/pause:3.3" , "k8s.gcr.io/pause:latest" } {
2020-03-26 04:43:32 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "cache" , "add" , img ) )
2019-11-27 00:19:29 +00:00
if err != nil {
2020-09-10 19:58:14 +00:00
t . Errorf ( "failed to 'cache add' remote image %q. args %q err %v" , img , rr . Command ( ) , err )
2019-11-27 00:19:29 +00:00
}
}
} )
2020-09-02 14:25:43 +00:00
2021-10-11 01:46:44 +00:00
// docs: Run `minikube cache add` and make sure we can build and add a local image to the cache
2020-09-02 14:25:43 +00:00
t . Run ( "add_local" , func ( t * testing . T ) {
2022-01-06 17:56:54 +00:00
if detect . GithubActionRunner ( ) && runtime . GOOS == "darwin" {
2020-10-08 21:24:02 +00:00
t . Skipf ( "skipping this test because Docker can not run in macos on github action free version. https://github.community/t/is-it-possible-to-install-and-configure-docker-on-macos-runner/16981" )
2020-12-09 19:06:17 +00:00
}
2020-10-08 21:24:02 +00:00
2020-12-09 19:06:17 +00:00
_ , err := exec . LookPath ( oci . Docker )
if err != nil {
t . Skipf ( "docker is not installed, skipping local image test" )
2020-10-08 21:24:02 +00:00
}
2022-04-02 02:18:20 +00:00
dname := t . TempDir ( )
2020-09-02 14:25:43 +00:00
message := [ ] byte ( "FROM scratch\nADD Dockerfile /x" )
2021-09-28 10:58:01 +00:00
err = os . WriteFile ( filepath . Join ( dname , "Dockerfile" ) , message , 0644 )
2020-09-02 14:25:43 +00:00
if err != nil {
2020-09-10 19:58:14 +00:00
t . Fatalf ( "unable to write Dockerfile: %v" , err )
2020-09-02 14:25:43 +00:00
}
img := "minikube-local-cache-test:" + profile
2021-03-10 02:53:22 +00:00
2020-09-02 15:21:35 +00:00
_ , err = Run ( t , exec . CommandContext ( ctx , "docker" , "build" , "-t" , img , dname ) )
2020-09-02 14:25:43 +00:00
if err != nil {
2020-12-09 19:06:17 +00:00
t . Skipf ( "failed to build docker image, skipping local test: %v" , err )
2020-09-02 14:25:43 +00:00
}
2021-07-08 20:43:49 +00:00
defer func ( ) {
_ , err := Run ( t , exec . CommandContext ( ctx , "docker" , "rmi" , img ) )
if err != nil {
t . Errorf ( "failed to delete local image %q, err %v" , img , err )
}
} ( )
2020-09-02 15:21:35 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "cache" , "add" , img ) )
2020-09-02 14:25:43 +00:00
if err != nil {
2020-09-10 19:58:14 +00:00
t . Errorf ( "failed to 'cache add' local image %q. args %q err %v" , img , rr . Command ( ) , err )
2020-09-02 14:25:43 +00:00
}
2021-07-08 20:43:49 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "cache" , "delete" , img ) )
if err != nil {
t . Errorf ( "failed to 'cache delete' local image %q. args %q err %v" , img , rr . Command ( ) , err )
2020-09-02 14:25:43 +00:00
}
} )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube cache delete` and make sure we can delete an image from the cache
2020-09-10 19:58:14 +00:00
t . Run ( "delete_k8s.gcr.io/pause:3.3" , func ( t * testing . T ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "cache" , "delete" , "k8s.gcr.io/pause:3.3" ) )
2019-11-27 00:19:29 +00:00
if err != nil {
2020-09-10 19:58:14 +00:00
t . Errorf ( "failed to delete image k8s.gcr.io/pause:3.3 from cache. args %q: %v" , rr . Command ( ) , err )
2019-11-27 00:19:29 +00:00
}
} )
2019-11-27 00:08:07 +00:00
2021-10-11 01:46:44 +00:00
// docs: Run `minikube cache list` and make sure we can list the images in the cache
2019-11-27 00:19:29 +00:00
t . Run ( "list" , func ( t * testing . T ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "cache" , "list" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to do cache list. args %q: %v" , rr . Command ( ) , err )
2019-11-27 00:19:29 +00:00
}
if ! strings . Contains ( rr . Output ( ) , "k8s.gcr.io/pause" ) {
2020-09-10 19:58:14 +00:00
t . Errorf ( "expected 'cache list' output to include 'k8s.gcr.io/pause' but got: ***%s***" , rr . Output ( ) )
2019-11-27 00:19:29 +00:00
}
2020-09-10 19:58:14 +00:00
if strings . Contains ( rr . Output ( ) , "k8s.gcr.io/pause:3.3" ) {
t . Errorf ( "expected 'cache list' output not to include k8s.gcr.io/pause:3.3 but got: ***%s***" , rr . Output ( ) )
2019-11-27 00:19:29 +00:00
}
} )
2019-11-27 00:08:07 +00:00
2021-10-11 01:46:44 +00:00
// docs: Run `minikube ssh sudo crictl images` and make sure we can list the images in the cache with `crictl`
2020-02-13 02:11:44 +00:00
t . Run ( "verify_cache_inside_node" , func ( t * testing . T ) {
2019-12-10 20:15:20 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , "sudo" , "crictl" , "images" ) )
2019-11-27 00:19:29 +00:00
if err != nil {
2019-12-11 05:01:12 +00:00
t . Errorf ( "failed to get images by %q ssh %v" , rr . Command ( ) , err )
2019-11-27 00:19:29 +00:00
}
2021-01-13 21:58:55 +00:00
pauseID := imageID ( "pause" )
2020-12-01 00:06:06 +00:00
if ! strings . Contains ( rr . Output ( ) , pauseID ) {
2021-01-13 21:58:55 +00:00
t . Errorf ( "expected sha for pause:3.3 %q to be in the output but got *%s*" , pauseID , rr . Output ( ) )
2019-11-27 00:19:29 +00:00
}
} )
2019-12-11 05:01:12 +00:00
2021-10-11 01:46:44 +00:00
// docs: Delete an image from minikube node and run `minikube cache reload` to make sure the image is brought back correctly
2020-02-13 02:11:44 +00:00
t . Run ( "cache_reload" , func ( t * testing . T ) { // deleting image inside minikube node manually and expecting reload to bring it back
2021-03-02 00:56:56 +00:00
img := "k8s.gcr.io/pause:latest"
2019-12-11 05:01:12 +00:00
// deleting image inside minikube node manually
2021-01-22 23:30:26 +00:00
var binary string
switch ContainerRuntime ( ) {
case "docker" :
binary = "docker"
case "containerd" , "crio" :
binary = "crictl"
}
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , "sudo" , binary , "rmi" , img ) )
2020-05-26 02:58:28 +00:00
2019-12-11 05:01:12 +00:00
if err != nil {
2020-09-16 22:01:15 +00:00
t . Errorf ( "failed to manually delete image %q : %v" , rr . Command ( ) , err )
2019-12-11 05:01:12 +00:00
}
// make sure the image is deleted.
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , "sudo" , "crictl" , "inspecti" , img ) )
if err == nil {
2020-09-10 19:58:14 +00:00
t . Errorf ( "expected an error but got no error. image should not exist. ! cmd: %q" , rr . Command ( ) )
2019-12-11 05:01:12 +00:00
}
2019-12-11 05:06:17 +00:00
// minikube cache reload.
2019-12-11 05:01:12 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "cache" , "reload" ) )
if err != nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "expected %q to run successfully but got error: %v" , rr . Command ( ) , err )
2019-12-11 05:01:12 +00:00
}
2019-12-11 05:06:17 +00:00
// make sure 'cache reload' brought back the manually deleted image.
2019-12-11 05:01:12 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , "sudo" , "crictl" , "inspecti" , img ) )
if err != nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "expected %q to run successfully but got error: %v" , rr . Command ( ) , err )
2019-12-11 05:01:12 +00:00
}
} )
2020-06-22 20:29:41 +00:00
// delete will clean up the cached images since they are global and all other tests will load it for no reason
t . Run ( "delete" , func ( t * testing . T ) {
2021-03-02 00:56:56 +00:00
for _ , img := range [ ] string { "k8s.gcr.io/pause:3.1" , "k8s.gcr.io/pause:latest" } {
2020-06-22 20:29:41 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "cache" , "delete" , img ) )
if err != nil {
t . Errorf ( "failed to delete %s from cache. args %q: %v" , img , rr . Command ( ) , err )
}
}
} )
2019-11-27 00:19:29 +00:00
} )
2019-09-11 16:59:38 +00:00
}
// validateConfigCmd asserts basic "config" command functionality
func validateConfigCmd ( ctx context . Context , t * testing . T , profile string ) {
2021-10-11 01:46:44 +00:00
// docs: Run `minikube config set/get/unset` to make sure configuration is modified correctly
2019-09-11 16:59:38 +00:00
tests := [ ] struct {
args [ ] string
wantOut string
wantErr string
} {
{ [ ] string { "unset" , "cpus" } , "" , "" } ,
{ [ ] string { "get" , "cpus" } , "" , "Error: specified key could not be found in config" } ,
2020-04-02 19:27:19 +00:00
{ [ ] string { "set" , "cpus" , "2" } , "" , "! These changes will take effect upon a minikube delete and then a minikube start" } ,
2019-09-11 16:59:38 +00:00
{ [ ] string { "get" , "cpus" } , "2" , "" } ,
{ [ ] string { "unset" , "cpus" } , "" , "" } ,
{ [ ] string { "get" , "cpus" } , "" , "Error: specified key could not be found in config" } ,
}
for _ , tc := range tests {
args := append ( [ ] string { "-p" , profile , "config" } , tc . args ... )
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , args ... ) )
if err != nil && tc . wantErr == "" {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to config minikube. args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
got := strings . TrimSpace ( rr . Stdout . String ( ) )
if got != tc . wantOut {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected config output for %q to be -%q- but got *%q*" , rr . Command ( ) , tc . wantOut , got )
2019-09-11 16:59:38 +00:00
}
got = strings . TrimSpace ( rr . Stderr . String ( ) )
if got != tc . wantErr {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected config error for %q to be -%q- but got *%q*" , rr . Command ( ) , tc . wantErr , got )
2019-09-11 16:59:38 +00:00
}
}
}
2021-05-04 22:59:00 +00:00
func checkSaneLogs ( t * testing . T , logs string ) {
2021-02-19 01:39:35 +00:00
expectedWords := [ ] string { "apiserver" , "Linux" , "kubelet" , "Audit" , "Last Start" }
2021-01-22 23:47:19 +00:00
switch ContainerRuntime ( ) {
case "docker" :
expectedWords = append ( expectedWords , "Docker" )
case "containerd" :
expectedWords = append ( expectedWords , "containerd" )
case "crio" :
expectedWords = append ( expectedWords , "crio" )
}
for _ , word := range expectedWords {
2021-05-04 22:59:00 +00:00
if ! strings . Contains ( logs , word ) {
t . Errorf ( "expected minikube logs to include word: -%q- but got \n***%s***\n" , word , logs )
2019-09-11 16:59:38 +00:00
}
}
}
2021-05-04 22:59:00 +00:00
// validateLogsCmd asserts basic "logs" command functionality
func validateLogsCmd ( ctx context . Context , t * testing . T , profile string ) {
2021-10-11 01:46:44 +00:00
// docs: Run `minikube logs` and make sure the logs contains some keywords like `apiserver`, `Audit` and `Last Start`
2021-05-04 22:59:00 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "logs" ) )
if err != nil {
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
}
checkSaneLogs ( t , rr . Stdout . String ( ) )
}
// validateLogsFileCmd asserts "logs --file" command functionality
func validateLogsFileCmd ( ctx context . Context , t * testing . T , profile string ) {
2022-04-02 02:18:20 +00:00
dname := t . TempDir ( )
2021-05-04 22:59:00 +00:00
logFileName := filepath . Join ( dname , "logs.txt" )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube logs --file logs.txt` to save the logs to a local file
2021-05-04 22:59:00 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "logs" , "--file" , logFileName ) )
if err != nil {
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
}
if rr . Stdout . String ( ) != "" {
t . Errorf ( "expected empty minikube logs output, but got: \n***%s***\n" , rr . Output ( ) )
}
2021-09-28 10:58:01 +00:00
logs , err := os . ReadFile ( logFileName )
2021-05-04 22:59:00 +00:00
if err != nil {
t . Errorf ( "Failed to read logs output '%s': %v" , logFileName , err )
}
2021-10-11 01:46:44 +00:00
// docs: Make sure the logs are correctly written
2021-05-04 22:59:00 +00:00
checkSaneLogs ( t , string ( logs ) )
}
2019-10-11 17:16:26 +00:00
// validateProfileCmd asserts "profile" command functionality
2019-09-11 16:59:38 +00:00
func validateProfileCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-02-20 06:30:47 +00:00
t . Run ( "profile_not_create" , func ( t * testing . T ) {
// Profile command should not create a nonexistent profile
nonexistentProfile := "lis"
2021-10-11 01:46:44 +00:00
// docs: Run `minikube profile lis` and make sure the command doesn't fail for the non-existent profile `lis`
2020-02-20 06:30:47 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , nonexistentProfile ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube profile list --output json` to make sure the previous command doesn't create a new profile
2020-02-20 06:30:47 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , "list" , "--output" , "json" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
var profileJSON map [ string ] [ ] map [ string ] interface { }
err = json . Unmarshal ( rr . Stdout . Bytes ( ) , & profileJSON )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
for profileK := range profileJSON {
for _ , p := range profileJSON [ profileK ] {
var name = p [ "Name" ]
if name == nonexistentProfile {
t . Errorf ( "minikube profile %s should not exist" , nonexistentProfile )
}
2020-02-20 03:56:32 +00:00
}
2020-02-18 12:10:27 +00:00
}
2020-02-20 06:30:47 +00:00
} )
2020-02-18 12:10:27 +00:00
2021-10-11 01:46:44 +00:00
// docs: Run `minikube profile list` and make sure the profiles are correctly listed
2020-02-20 06:30:47 +00:00
t . Run ( "profile_list" , func ( t * testing . T ) {
2021-01-09 03:21:16 +00:00
// helper function to run command then, return target profile line from table output.
extractrofileListFunc := func ( rr * RunResult ) string {
listLines := strings . Split ( strings . TrimSpace ( rr . Stdout . String ( ) ) , "\n" )
for i := 3 ; i < ( len ( listLines ) - 1 ) ; i ++ {
profileLine := listLines [ i ]
if strings . Contains ( profileLine , profile ) {
return profileLine
}
}
return ""
}
2020-02-20 06:30:47 +00:00
// List profiles
2021-01-09 03:21:16 +00:00
start := time . Now ( )
2020-02-20 06:41:23 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , "list" ) )
2021-01-09 03:21:16 +00:00
elapsed := time . Since ( start )
2020-02-20 06:30:47 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to list profiles: args %q : %v" , rr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
2021-01-09 03:21:16 +00:00
t . Logf ( "Took %q to run %q" , elapsed , rr . Command ( ) )
2019-10-11 17:16:26 +00:00
2021-01-09 03:21:16 +00:00
profileLine := extractrofileListFunc ( rr )
if profileLine == "" {
2020-03-26 05:21:19 +00:00
t . Errorf ( "expected 'profile list' output to include %q but got *%q*. args: %q" , profile , rr . Stdout . String ( ) , rr . Command ( ) )
2019-10-11 17:16:26 +00:00
}
2021-01-09 03:21:16 +00:00
// List profiles with light option.
start = time . Now ( )
lrr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , "list" , "-l" ) )
lightElapsed := time . Since ( start )
if err != nil {
t . Errorf ( "failed to list profiles: args %q : %v" , lrr . Command ( ) , err )
}
t . Logf ( "Took %q to run %q" , lightElapsed , lrr . Command ( ) )
profileLine = extractrofileListFunc ( lrr )
if profileLine == "" || ! strings . Contains ( profileLine , "Skipped" ) {
t . Errorf ( "expected 'profile list' output to include %q with 'Skipped' status but got *%q*. args: %q" , profile , rr . Stdout . String ( ) , rr . Command ( ) )
}
if lightElapsed > 3 * time . Second {
t . Errorf ( "expected running time of '%q' is less than 3 seconds. Took %q " , lrr . Command ( ) , lightElapsed )
}
2020-02-20 06:30:47 +00:00
} )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube profile list -o JSON` and make sure the profiles are correctly listed as JSON output
2020-02-20 06:30:47 +00:00
t . Run ( "profile_json_output" , func ( t * testing . T ) {
2021-01-09 03:21:16 +00:00
// helper function to run command then, return target profile object from json output.
extractProfileObjFunc := func ( rr * RunResult ) * config . Profile {
var jsonObject map [ string ] [ ] config . Profile
err := json . Unmarshal ( rr . Stdout . Bytes ( ) , & jsonObject )
if err != nil {
t . Errorf ( "failed to decode json from profile list: args %q: %v" , rr . Command ( ) , err )
return nil
}
for _ , profileObject := range jsonObject [ "valid" ] {
if profileObject . Name == profile {
return & profileObject
}
}
return nil
}
start := time . Now ( )
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , "list" , "-o" , "json" ) )
elapsed := time . Since ( start )
2020-02-20 06:30:47 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to list profiles with json format. args %q: %v" , rr . Command ( ) , err )
2019-10-11 17:16:26 +00:00
}
2021-01-09 03:21:16 +00:00
t . Logf ( "Took %q to run %q" , elapsed , rr . Command ( ) )
pr := extractProfileObjFunc ( rr )
if pr == nil {
t . Errorf ( "expected the json of 'profile list' to include %q but got *%q*. args: %q" , profile , rr . Stdout . String ( ) , rr . Command ( ) )
}
start = time . Now ( )
lrr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , "list" , "-o" , "json" , "--light" ) )
lightElapsed := time . Since ( start )
2020-02-20 06:30:47 +00:00
if err != nil {
2021-01-09 03:21:16 +00:00
t . Errorf ( "failed to list profiles with json format. args %q: %v" , lrr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
2021-01-09 03:21:16 +00:00
t . Logf ( "Took %q to run %q" , lightElapsed , lrr . Command ( ) )
pr = extractProfileObjFunc ( lrr )
if pr == nil || pr . Status != "Skipped" {
t . Errorf ( "expected the json of 'profile list' to include 'Skipped' status for %q but got *%q*. args: %q" , profile , lrr . Stdout . String ( ) , lrr . Command ( ) )
2020-02-20 06:30:47 +00:00
}
2021-01-09 03:21:16 +00:00
if lightElapsed > 3 * time . Second {
t . Errorf ( "expected running time of '%q' is less than 3 seconds. Took %q " , lrr . Command ( ) , lightElapsed )
}
2020-02-20 06:30:47 +00:00
} )
2019-09-11 16:59:38 +00:00
}
2022-03-07 14:56:50 +00:00
func killContext ( cmdContext * exec . Cmd , killDelay time . Duration , t * testing . T ) {
time . Sleep ( killDelay )
err := cmdContext . Process . Signal ( os . Interrupt )
if err != nil {
t . Error ( "Failed to sent interrupt to proc" , err )
}
}
2019-09-11 16:59:38 +00:00
// validateServiceCmd asserts basic "service" command functionality
2019-10-30 17:44:54 +00:00
func validateServiceCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2020-05-07 23:44:42 +00:00
defer func ( ) {
if t . Failed ( ) {
t . Logf ( "service test failed - dumping debug information" )
2020-11-19 19:53:04 +00:00
t . Logf ( "-----------------------service failure post-mortem--------------------------------" )
ctx , cancel := context . WithTimeout ( context . Background ( ) , Minutes ( 2 ) )
defer cancel ( )
2020-05-07 23:44:42 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "describe" , "po" , "hello-node" ) )
if err != nil {
t . Logf ( "%q failed: %v" , rr . Command ( ) , err )
}
t . Logf ( "hello-node pod describe:\n%s" , rr . Stdout )
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "logs" , "-l" , "app=hello-node" ) )
if err != nil {
t . Logf ( "%q failed: %v" , rr . Command ( ) , err )
}
t . Logf ( "hello-node logs:\n%s" , rr . Stdout )
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "describe" , "svc" , "hello-node" ) )
if err != nil {
t . Logf ( "%q failed: %v" , rr . Command ( ) , err )
}
t . Logf ( "hello-node svc describe:\n%s" , rr . Stdout )
}
} ( )
2021-01-14 23:13:03 +00:00
var rr * RunResult
var err error
2021-10-11 01:46:44 +00:00
// docs: Create a new `k8s.gcr.io/echoserver` deployment
2021-01-14 23:13:03 +00:00
// k8s.gcr.io/echoserver is not multi-arch
2021-01-14 18:51:57 +00:00
if arm64Platform ( ) {
2021-01-14 23:13:03 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "deployment" , "hello-node" , "--image=k8s.gcr.io/echoserver-arm:1.8" ) )
2020-12-01 00:06:06 +00:00
} else {
2021-01-14 23:13:03 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "deployment" , "hello-node" , "--image=k8s.gcr.io/echoserver:1.8" ) )
2020-12-01 00:06:06 +00:00
}
2019-10-30 17:44:54 +00:00
if err != nil {
2020-11-20 22:46:22 +00:00
t . Fatalf ( "failed to create hello-node deployment with this command %q: %v." , rr . Command ( ) , err )
2019-10-30 17:44:54 +00:00
}
2019-10-30 20:57:08 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "expose" , "deployment" , "hello-node" , "--type=NodePort" , "--port=8080" ) )
2019-10-30 17:44:54 +00:00
if err != nil {
2020-11-20 22:46:22 +00:00
t . Fatalf ( "failed to expose hello-node deployment: %q : %v" , rr . Command ( ) , err )
2019-10-30 17:44:54 +00:00
}
2020-02-21 00:40:18 +00:00
if _ , err := PodWait ( ctx , t , profile , "default" , "app=hello-node" , Minutes ( 10 ) ) ; err != nil {
2020-03-26 04:43:32 +00:00
t . Fatalf ( "failed waiting for hello-node pod: %v" , err )
2019-10-30 20:57:08 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube service list` to make sure the newly created service is correctly listed in the output
2019-10-30 17:44:54 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "service" , "list" ) )
2019-09-11 16:59:38 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to do service list. args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
2019-10-30 20:57:08 +00:00
if ! strings . Contains ( rr . Stdout . String ( ) , "hello-node" ) {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected 'service list' to contain *hello-node* but got -%q-" , rr . Stdout . String ( ) )
2019-10-30 17:44:54 +00:00
}
2022-03-07 14:56:50 +00:00
// docs: Run `minikube service` with `--https --url` to make sure the HTTPS endpoint URL of the service is printed
cmdContext := exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "service" , "--namespace=default" , "--https" , "--url" , "hello-node" )
2020-04-02 17:51:15 +00:00
if NeedsPortForward ( ) {
2022-03-07 14:56:50 +00:00
go killContext ( cmdContext , 2 * time . Second , t )
2020-04-02 17:51:15 +00:00
}
2022-03-07 14:56:50 +00:00
rr , err = Run ( t , cmdContext )
if err != nil && ! strings . Contains ( err . Error ( ) , "interrupt" ) {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to get service url. args %q : %v" , rr . Command ( ) , err )
2019-10-30 20:57:08 +00:00
}
2020-05-08 20:12:30 +00:00
2022-01-17 22:39:44 +00:00
splits := strings . Split ( rr . Stdout . String ( ) , "|" )
var endpoint string
// get the last endpoint in the output to test http to https
for _ , v := range splits {
if strings . Contains ( v , "http" ) {
endpoint = strings . TrimSpace ( v )
}
}
2020-05-08 20:12:30 +00:00
t . Logf ( "found endpoint: %s" , endpoint )
2020-05-09 00:19:32 +00:00
2019-10-30 17:44:54 +00:00
u , err := url . Parse ( endpoint )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Fatalf ( "failed to parse service url endpoint %q: %v" , endpoint , err )
2019-10-30 17:44:54 +00:00
}
if u . Scheme != "https" {
2020-05-08 20:12:30 +00:00
t . Errorf ( "expected scheme for %s to be 'https' but got %q" , endpoint , u . Scheme )
2019-10-30 17:44:54 +00:00
}
2022-03-07 14:56:50 +00:00
cmdContext = exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "service" , "hello-node" , "--url" , "--format={{.IP}}" )
if NeedsPortForward ( ) {
go killContext ( cmdContext , 2 * time . Second , t )
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube service` with `--url --format={{.IP}}` to make sure the IP address of the service is printed
2022-03-07 14:56:50 +00:00
rr , err = Run ( t , cmdContext )
if err != nil && ! strings . Contains ( err . Error ( ) , "interrupt" ) {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to get service url with custom format. args %q: %v" , rr . Command ( ) , err )
2019-10-30 17:44:54 +00:00
}
2022-03-07 14:56:50 +00:00
2019-10-30 20:57:08 +00:00
if strings . TrimSpace ( rr . Stdout . String ( ) ) != u . Hostname ( ) {
2020-03-26 05:21:19 +00:00
t . Errorf ( "expected 'service --format={{.IP}}' output to be -%q- but got *%q* . args %q." , u . Hostname ( ) , rr . Stdout . String ( ) , rr . Command ( ) )
2019-10-30 17:44:54 +00:00
}
2022-03-07 14:56:50 +00:00
cmdContext = exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "service" , "hello-node" , "--url" )
if NeedsPortForward ( ) {
go killContext ( cmdContext , 2 * time . Second , t )
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube service` with a regular `--url` to make sure the HTTP endpoint URL of the service is printed
2022-03-07 14:56:50 +00:00
rr , err = Run ( t , cmdContext )
2019-10-30 17:44:54 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to get service url. args: %q: %v" , rr . Command ( ) , err )
2019-10-30 17:44:54 +00:00
}
2019-10-30 20:57:08 +00:00
endpoint = strings . TrimSpace ( rr . Stdout . String ( ) )
2020-05-07 23:44:42 +00:00
t . Logf ( "found endpoint for hello-node: %s" , endpoint )
2019-10-30 20:57:08 +00:00
u , err = url . Parse ( endpoint )
if err != nil {
t . Fatalf ( "failed to parse %q: %v" , endpoint , err )
}
2020-05-07 23:44:42 +00:00
2019-10-30 20:57:08 +00:00
if u . Scheme != "http" {
2020-03-26 05:15:24 +00:00
t . Fatalf ( "expected scheme to be -%q- got scheme: *%q*" , "http" , u . Scheme )
2019-10-30 20:57:08 +00:00
}
2022-03-07 14:56:50 +00:00
}
func validateServiceCmdConnect ( ctx context . Context , t * testing . T , profile string ) {
defer PostMortemLogs ( t , profile )
defer func ( ) {
if t . Failed ( ) {
t . Logf ( "service test failed - dumping debug information" )
t . Logf ( "-----------------------service failure post-mortem--------------------------------" )
ctx , cancel := context . WithTimeout ( context . Background ( ) , Minutes ( 2 ) )
defer cancel ( )
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "describe" , "po" , "hello-node-connect" ) )
if err != nil {
t . Logf ( "%q failed: %v" , rr . Command ( ) , err )
}
t . Logf ( "hello-node pod describe:\n%s" , rr . Stdout )
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "logs" , "-l" , "app=hello-node-connect" ) )
if err != nil {
t . Logf ( "%q failed: %v" , rr . Command ( ) , err )
}
t . Logf ( "hello-node logs:\n%s" , rr . Stdout )
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "describe" , "svc" , "hello-node-connect" ) )
if err != nil {
t . Logf ( "%q failed: %v" , rr . Command ( ) , err )
}
t . Logf ( "hello-node svc describe:\n%s" , rr . Stdout )
}
} ( )
var rr * RunResult
var err error
// docs: Create a new `k8s.gcr.io/echoserver` deployment
// k8s.gcr.io/echoserver is not multi-arch
if arm64Platform ( ) {
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "deployment" , "hello-node-connect" , "--image=k8s.gcr.io/echoserver-arm:1.8" ) )
} else {
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "deployment" , "hello-node-connect" , "--image=k8s.gcr.io/echoserver:1.8" ) )
}
if err != nil {
t . Fatalf ( "failed to create hello-node deployment with this command %q: %v." , rr . Command ( ) , err )
}
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "expose" , "deployment" , "hello-node-connect" , "--type=NodePort" , "--port=8080" ) )
if err != nil {
t . Fatalf ( "failed to expose hello-node deployment: %q : %v" , rr . Command ( ) , err )
}
if _ , err := PodWait ( ctx , t , profile , "default" , "app=hello-node-connect" , Minutes ( 10 ) ) ; err != nil {
t . Fatalf ( "failed waiting for hello-node pod: %v" , err )
}
cmdContext := exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "service" , "hello-node-connect" , "--url" )
if NeedsPortForward ( ) {
t . Skipf ( "test is broken for port-forwarded drivers: https://github.com/kubernetes/minikube/issues/7383" )
}
// docs: Run `minikube service` with a regular `--url` to make sure the HTTP endpoint URL of the service is printed
rr , err = Run ( t , cmdContext )
if err != nil {
t . Errorf ( "failed to get service url. args: %q: %v" , rr . Command ( ) , err )
}
2019-10-30 20:57:08 +00:00
2022-03-07 14:56:50 +00:00
endpoint := strings . TrimSpace ( rr . Stdout . String ( ) )
t . Logf ( "found endpoint for hello-node-connect: %s" , endpoint )
2020-05-07 23:44:42 +00:00
2021-10-11 01:46:44 +00:00
// docs: Make sure we can hit the endpoint URL with an HTTP GET request
2020-05-07 23:44:42 +00:00
fetch := func ( ) error {
resp , err := http . Get ( endpoint )
if err != nil {
t . Logf ( "error fetching %s: %v" , endpoint , err )
return err
}
defer resp . Body . Close ( )
2021-09-28 10:58:01 +00:00
body , err := io . ReadAll ( resp . Body )
2020-05-07 23:44:42 +00:00
if err != nil {
t . Logf ( "error reading body from %s: %v" , endpoint , err )
return err
}
if resp . StatusCode != http . StatusOK {
t . Logf ( "%s: unexpected status code %d - body:\n%s" , endpoint , resp . StatusCode , body )
} else {
t . Logf ( "%s: success! body:\n%s" , endpoint , body )
}
return nil
2019-10-30 17:44:54 +00:00
}
2020-05-07 23:44:42 +00:00
if err = retry . Expo ( fetch , 1 * time . Second , Seconds ( 30 ) ) ; err != nil {
t . Errorf ( "failed to fetch %s: %v" , endpoint , err )
2019-09-11 16:59:38 +00:00
}
}
2019-10-11 14:43:00 +00:00
// validateAddonsCmd asserts basic "addon" command functionality
func validateAddonsCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube addons list` to list the addons in a tabular format
2019-10-11 14:43:00 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "addons" , "list" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to do addon list: args %q : %v" , rr . Command ( ) , err )
2019-10-11 14:43:00 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Make sure `dashboard`, `ingress` and `ingress-dns` is listed as available addons
2020-01-11 00:39:17 +00:00
for _ , a := range [ ] string { "dashboard" , "ingress" , "ingress-dns" } {
if ! strings . Contains ( rr . Output ( ) , a ) {
2020-04-02 04:40:09 +00:00
t . Errorf ( "expected 'addon list' output to include -%q- but got *%s*" , a , rr . Output ( ) )
2019-10-11 14:43:00 +00:00
}
}
2019-10-11 18:34:50 +00:00
2021-10-11 01:46:44 +00:00
// docs: Run `minikube addons list -o JSON` lists the addons in JSON format
2019-10-11 18:34:50 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "addons" , "list" , "-o" , "json" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to do addon list with json output. args %q: %v" , rr . Command ( ) , err )
2019-10-11 18:34:50 +00:00
}
var jsonObject map [ string ] interface { }
err = json . Unmarshal ( rr . Stdout . Bytes ( ) , & jsonObject )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed to decode addon list json output : %v" , err )
2019-10-11 18:34:50 +00:00
}
2019-10-11 14:43:00 +00:00
}
2019-09-11 16:59:38 +00:00
// validateSSHCmd asserts basic "ssh" command functionality
func validateSSHCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2019-09-11 16:59:38 +00:00
if NoneDriver ( ) {
t . Skipf ( "skipping: ssh unsupported by none" )
}
2020-05-27 20:56:16 +00:00
mctx , cancel := context . WithTimeout ( ctx , Minutes ( 1 ) )
defer cancel ( )
2020-05-27 06:52:55 +00:00
2020-05-27 22:54:07 +00:00
want := "hello"
2020-05-27 06:52:55 +00:00
2021-10-11 01:46:44 +00:00
// docs: Run `minikube ssh echo hello` to make sure we can SSH into the minikube container and run an command
2020-05-27 20:56:16 +00:00
rr , err := Run ( t , exec . CommandContext ( mctx , Target ( ) , "-p" , profile , "ssh" , "echo hello" ) )
if mctx . Err ( ) == context . DeadlineExceeded {
2020-05-27 04:53:07 +00:00
t . Errorf ( "failed to run command by deadline. exceeded timeout : %s" , rr . Command ( ) )
}
if err != nil {
t . Errorf ( "failed to run an ssh command. args %q : %v" , rr . Command ( ) , err )
}
2020-05-27 23:55:55 +00:00
// trailing whitespace differs between native and external SSH clients, so let's trim it and call it a day
2020-05-27 23:56:54 +00:00
if strings . TrimSpace ( rr . Stdout . String ( ) ) != want {
2020-05-27 04:53:07 +00:00
t . Errorf ( "expected minikube ssh command output to be -%q- but got *%q*. args %q" , want , rr . Stdout . String ( ) , rr . Command ( ) )
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube ssh cat /etc/hostname` as well to make sure the command is run inside minikube
2020-05-27 20:45:27 +00:00
// because it is not clear if echo was run inside minikube on the powershell
2020-05-27 20:56:16 +00:00
// so better to test something inside minikube, that is meaningful per profile
2020-05-27 20:45:27 +00:00
// in this case /etc/hostname is same as the profile name
2020-05-27 23:55:55 +00:00
want = profile
2020-05-27 20:56:16 +00:00
rr , err = Run ( t , exec . CommandContext ( mctx , Target ( ) , "-p" , profile , "ssh" , "cat /etc/hostname" ) )
2020-05-27 20:45:27 +00:00
if mctx . Err ( ) == context . DeadlineExceeded {
2020-05-27 04:53:07 +00:00
t . Errorf ( "failed to run command by deadline. exceeded timeout : %s" , rr . Command ( ) )
2020-05-25 22:55:54 +00:00
}
2019-09-11 16:59:38 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to run an ssh command. args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
2020-05-27 23:54:03 +00:00
// trailing whitespace differs between native and external SSH clients, so let's trim it and call it a day
2020-05-27 22:54:07 +00:00
if strings . TrimSpace ( rr . Stdout . String ( ) ) != want {
2020-03-26 05:21:19 +00:00
t . Errorf ( "expected minikube ssh command output to be -%q- but got *%q*. args %q" , want , rr . Stdout . String ( ) , rr . Command ( ) )
2019-09-11 16:59:38 +00:00
}
}
2021-05-06 04:56:51 +00:00
// validateCpCmd asserts basic "cp" command functionality
func validateCpCmd ( ctx context . Context , t * testing . T , profile string ) {
2021-10-11 01:46:44 +00:00
// docs(skip): Skips `none` driver since `cp` is not supported
2021-05-06 04:56:51 +00:00
if NoneDriver ( ) {
t . Skipf ( "skipping: cp is unsupported by none driver" )
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube cp ...` to copy a file to the minikube node
// docs: Run `minikube ssh sudo cat ...` to print out the copied file within minikube
// docs: make sure the file is correctly copied
2021-05-06 04:56:51 +00:00
srcPath := cpTestLocalPath ( )
dstPath := cpTestMinikubePath ( )
// copy to node
testCpCmd ( ctx , t , profile , "" , srcPath , "" , dstPath )
// copy from node
2022-04-02 02:18:20 +00:00
tmpDir := t . TempDir ( )
2021-05-06 04:56:51 +00:00
tmpPath := filepath . Join ( tmpDir , "cp-test.txt" )
testCpCmd ( ctx , t , profile , profile , dstPath , "" , tmpPath )
2021-05-06 04:56:51 +00:00
}
2019-10-29 05:31:57 +00:00
// validateMySQL validates a minimalist MySQL deployment
func validateMySQL ( ctx context . Context , t * testing . T , profile string ) {
2021-10-11 01:46:44 +00:00
// docs(skip): Skips for ARM64 architecture since it's not supported by MySQL
2021-01-14 18:51:57 +00:00
if arm64Platform ( ) {
2021-01-14 19:50:56 +00:00
t . Skip ( "arm64 is not supported by mysql. Skip the test. See https://github.com/kubernetes/minikube/issues/10144" )
2020-12-01 00:06:06 +00:00
}
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-10-11 01:46:44 +00:00
// docs: Run `kubectl replace --force -f testdata/mysql/yaml`
2019-10-29 05:31:57 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "replace" , "--force" , "-f" , filepath . Join ( * testdataDir , "mysql.yaml" ) ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to kubectl replace mysql: args %q failed: %v" , rr . Command ( ) , err )
2019-10-29 05:31:57 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Wait for the `mysql` pod to be running
2020-02-21 00:40:18 +00:00
names , err := PodWait ( ctx , t , profile , "default" , "app=mysql" , Minutes ( 10 ) )
2019-11-06 23:17:09 +00:00
if err != nil {
2020-03-26 04:43:32 +00:00
t . Fatalf ( "failed waiting for mysql pod: %v" , err )
2019-11-06 23:17:09 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Run `mysql -e show databases;` inside the MySQL pod to verify MySQL is up and running
// docs: Retry with exponential backoff if failed, as `mysqld` first comes up without users configured. Scan for names in case of a reschedule.
2019-10-29 20:13:33 +00:00
mysql := func ( ) error {
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "exec" , names [ 0 ] , "--" , "mysql" , "-ppassword" , "-e" , "show databases;" ) )
return err
2019-10-29 05:31:57 +00:00
}
2020-04-03 07:08:32 +00:00
if err = retry . Expo ( mysql , 1 * time . Second , Minutes ( 5 ) ) ; err != nil {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed to exec 'mysql -ppassword -e show databases;': %v" , err )
2019-10-29 05:31:57 +00:00
}
}
2020-02-12 22:26:38 +00:00
// vmSyncTestPath is where the test file will be synced into the VM
func vmSyncTestPath ( ) string {
return fmt . Sprintf ( "/etc/test/nested/copy/%d/hosts" , os . Getpid ( ) )
}
// localSyncTestPath is where the test file will be synced into the VM
func localSyncTestPath ( ) string {
return filepath . Join ( localpath . MiniPath ( ) , "/files" , vmSyncTestPath ( ) )
}
2020-03-04 22:48:40 +00:00
// testCert is name of the test certificate installed
func testCert ( ) string {
return fmt . Sprintf ( "%d.pem" , os . Getpid ( ) )
}
2021-07-22 01:01:39 +00:00
// testFileCert is name of the test certificate installed
func testFileCert ( ) string {
return fmt . Sprintf ( "%d2.pem" , os . Getpid ( ) )
}
// localTestCertPath is where certs can be synced from the local host into the VM
// precisely, it's $MINIKUBE_HOME/certs
2020-03-04 22:48:40 +00:00
func localTestCertPath ( ) string {
return filepath . Join ( localpath . MiniPath ( ) , "/certs" , testCert ( ) )
}
2021-07-22 01:01:39 +00:00
// localTestCertFilesPath is an alternate location where certs can be synced into the minikube VM
// precisely, it's $MINIKUBE_HOME/files/etc/ssl/certs
func localTestCertFilesPath ( ) string {
return filepath . Join ( localpath . MiniPath ( ) , "/files/etc/ssl/certs" , testFileCert ( ) )
}
2020-04-08 22:04:12 +00:00
// localEmptyCertPath is where the test file will be synced into the VM
func localEmptyCertPath ( ) string {
return filepath . Join ( localpath . MiniPath ( ) , "/certs" , fmt . Sprintf ( "%d_empty.pem" , os . Getpid ( ) ) )
}
2019-11-07 01:20:52 +00:00
// Copy extra file into minikube home folder for file sync test
func setupFileSync ( ctx context . Context , t * testing . T , profile string ) {
2020-02-12 22:26:38 +00:00
p := localSyncTestPath ( )
t . Logf ( "local sync path: %s" , p )
2020-08-04 18:57:10 +00:00
syncFile := filepath . Join ( * testdataDir , "sync.test" )
2022-05-16 19:48:41 +00:00
err := cp . Copy ( syncFile , p )
2019-11-07 01:20:52 +00:00
if err != nil {
2020-08-04 18:57:10 +00:00
t . Fatalf ( "failed to copy testdata/sync.test: %v" , err )
2019-11-07 01:20:52 +00:00
}
2020-03-04 22:48:40 +00:00
2020-08-04 18:57:10 +00:00
testPem := filepath . Join ( * testdataDir , "minikube_test.pem" )
2020-04-08 22:04:12 +00:00
2020-04-10 15:32:41 +00:00
// Write to a temp file for an atomic write
tmpPem := localTestCertPath ( ) + ".pem"
2022-05-16 19:48:41 +00:00
if err := cp . Copy ( testPem , tmpPem ) ; err != nil {
2020-04-08 22:04:12 +00:00
t . Fatalf ( "failed to copy %s: %v" , testPem , err )
}
2020-04-10 15:32:41 +00:00
if err := os . Rename ( tmpPem , localTestCertPath ( ) ) ; err != nil {
t . Fatalf ( "failed to rename %s: %v" , tmpPem , err )
}
2020-04-08 22:04:12 +00:00
want , err := os . Stat ( testPem )
if err != nil {
t . Fatalf ( "stat failed: %v" , err )
}
got , err := os . Stat ( localTestCertPath ( ) )
if err != nil {
t . Fatalf ( "stat failed: %v" , err )
}
if want . Size ( ) != got . Size ( ) {
t . Errorf ( "%s size=%d, want %d" , localTestCertPath ( ) , got . Size ( ) , want . Size ( ) )
}
2021-07-22 01:01:39 +00:00
testPem2 := filepath . Join ( * testdataDir , "minikube_test2.pem" )
tmpPem2 := localTestCertFilesPath ( ) + ".pem"
2022-05-16 19:48:41 +00:00
if err := cp . Copy ( testPem2 , tmpPem2 ) ; err != nil {
2021-07-22 01:01:39 +00:00
t . Fatalf ( "failed to copy %s: %v" , testPem2 , err )
}
if err := os . Rename ( tmpPem2 , localTestCertFilesPath ( ) ) ; err != nil {
t . Fatalf ( "failed to rename %s: %v" , tmpPem2 , err )
}
want , err = os . Stat ( testPem2 )
if err != nil {
t . Fatalf ( "stat failed: %v" , err )
}
got , err = os . Stat ( localTestCertFilesPath ( ) )
if err != nil {
t . Fatalf ( "stat failed: %v" , err )
}
if want . Size ( ) != got . Size ( ) {
t . Errorf ( "%s size=%d, want %d" , localTestCertFilesPath ( ) , got . Size ( ) , want . Size ( ) )
}
2020-04-08 22:04:12 +00:00
// Create an empty file just to mess with people
if _ , err := os . Create ( localEmptyCertPath ( ) ) ; err != nil {
t . Fatalf ( "create failed: %v" , err )
2020-03-04 22:48:40 +00:00
}
2019-11-07 01:20:52 +00:00
}
// validateFileSync to check existence of the test file
func validateFileSync ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2021-10-11 01:46:44 +00:00
// docs(skip): Skips on `none` driver since SSH is not supported
2019-11-07 01:20:52 +00:00
if NoneDriver ( ) {
t . Skipf ( "skipping: ssh unsupported by none" )
}
2020-02-12 22:26:38 +00:00
2021-10-11 01:46:44 +00:00
// docs: Test files have been synced into minikube in the previous step `setupFileSync`
2020-02-12 22:26:38 +00:00
vp := vmSyncTestPath ( )
t . Logf ( "Checking for existence of %s within VM" , vp )
2021-10-11 01:46:44 +00:00
// docs: Check the existence of the test file
2020-04-02 17:37:23 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , fmt . Sprintf ( "sudo cat %s" , vp ) ) )
2019-11-07 01:20:52 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
2019-11-07 01:20:52 +00:00
}
2020-02-12 22:26:38 +00:00
got := rr . Stdout . String ( )
t . Logf ( "file sync test content: %s" , got )
2019-11-07 01:20:52 +00:00
2020-08-04 18:57:10 +00:00
syncFile := filepath . Join ( * testdataDir , "sync.test" )
2021-09-28 10:58:01 +00:00
expected , err := os . ReadFile ( syncFile )
2019-11-07 01:20:52 +00:00
if err != nil {
2020-08-04 18:57:10 +00:00
t . Errorf ( "failed to read test file 'testdata/sync.test' : %v" , err )
2019-11-07 01:20:52 +00:00
}
2021-10-11 01:46:44 +00:00
// docs: Make sure the file is correctly synced
2020-02-12 22:26:38 +00:00
if diff := cmp . Diff ( string ( expected ) , got ) ; diff != "" {
2019-11-07 01:20:52 +00:00
t . Errorf ( "/etc/sync.test content mismatch (-want +got):\n%s" , diff )
}
}
2021-07-22 01:01:39 +00:00
// validateCertSync checks to make sure a custom cert has been copied into the minikube guest and installed correctly
2020-03-04 22:48:40 +00:00
func validateCertSync ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2020-03-04 22:48:40 +00:00
if NoneDriver ( ) {
t . Skipf ( "skipping: ssh unsupported by none" )
}
2020-08-04 18:57:10 +00:00
testPem := filepath . Join ( * testdataDir , "minikube_test.pem" )
2021-09-28 10:58:01 +00:00
want , err := os . ReadFile ( testPem )
2020-03-04 22:48:40 +00:00
if err != nil {
t . Errorf ( "test file not found: %v" , err )
}
2021-10-11 01:46:44 +00:00
// docs: Check both the installed & reference certs and make sure they are symlinked
2020-03-04 22:48:40 +00:00
paths := [ ] string {
path . Join ( "/etc/ssl/certs" , testCert ( ) ) ,
path . Join ( "/usr/share/ca-certificates" , testCert ( ) ) ,
// hashed path generated by: 'openssl x509 -hash -noout -in testCert()'
"/etc/ssl/certs/51391683.0" ,
}
for _ , vp := range paths {
t . Logf ( "Checking for existence of %s within VM" , vp )
2020-04-02 17:37:23 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , fmt . Sprintf ( "sudo cat %s" , vp ) ) )
2020-03-04 22:48:40 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to check existence of %q inside minikube. args %q: %v" , vp , rr . Command ( ) , err )
2020-03-04 22:48:40 +00:00
}
// Strip carriage returned by ssh
2021-04-19 22:16:31 +00:00
got := strings . ReplaceAll ( rr . Stdout . String ( ) , "\r" , "" )
2020-03-04 22:48:40 +00:00
if diff := cmp . Diff ( string ( want ) , got ) ; diff != "" {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed verify pem file. minikube_test.pem -> %s mismatch (-want +got):\n%s" , vp , diff )
2020-03-04 22:48:40 +00:00
}
}
2021-07-22 01:01:39 +00:00
testPem2 := filepath . Join ( * testdataDir , "minikube_test2.pem" )
2021-09-28 10:58:01 +00:00
want , err = os . ReadFile ( testPem2 )
2021-07-22 01:01:39 +00:00
if err != nil {
t . Errorf ( "test file not found: %v" , err )
}
// Check both the installed & reference certs (they should be symlinked)
paths = [ ] string {
path . Join ( "/etc/ssl/certs" , testFileCert ( ) ) ,
path . Join ( "/usr/share/ca-certificates" , testFileCert ( ) ) ,
// hashed path generated by: 'openssl x509 -hash -noout -in testCert()'
"/etc/ssl/certs/3ec20f2e.0" ,
}
for _ , vp := range paths {
t . Logf ( "Checking for existence of %s within VM" , vp )
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , fmt . Sprintf ( "sudo cat %s" , vp ) ) )
if err != nil {
t . Errorf ( "failed to check existence of %q inside minikube. args %q: %v" , vp , rr . Command ( ) , err )
}
// Strip carriage returned by ssh
got := strings . ReplaceAll ( rr . Stdout . String ( ) , "\r" , "" )
if diff := cmp . Diff ( string ( want ) , got ) ; diff != "" {
t . Errorf ( "failed verify pem file. minikube_test2.pem -> %s mismatch (-want +got):\n%s" , vp , diff )
}
}
2020-03-04 22:48:40 +00:00
}
2021-10-11 01:46:44 +00:00
// validateNotActiveRuntimeDisabled asserts that for a given runtime, the other runtimes are disabled, for example for `containerd` runtime, `docker` and `crio` needs to be not running
2021-05-27 01:19:53 +00:00
func validateNotActiveRuntimeDisabled ( ctx context . Context , t * testing . T , profile string ) {
2021-05-27 19:22:46 +00:00
if NoneDriver ( ) {
t . Skip ( "skipping on none driver, minikube does not control the runtime of user on the none driver." )
}
2021-05-27 00:58:52 +00:00
disableMap := map [ string ] [ ] string {
2021-05-27 01:36:01 +00:00
"docker" : { "crio" } ,
"containerd" : { "docker" , "crio" } ,
"crio" : { "docker" , "containerd" } ,
2021-05-27 00:58:52 +00:00
}
expectDisable := disableMap [ ContainerRuntime ( ) ]
for _ , cr := range expectDisable {
2021-10-11 01:46:44 +00:00
// docs: For each container runtime, run `minikube ssh sudo systemctl is-active ...` and make sure the other container runtimes are not running
2021-05-27 00:58:52 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , fmt . Sprintf ( "sudo systemctl is-active %s" , cr ) ) )
2021-05-27 19:22:46 +00:00
got := rr . Stdout . String ( )
if err != nil && ! strings . Contains ( got , "inactive" ) {
2021-05-27 00:58:52 +00:00
t . Logf ( "output of %s: %v" , rr . Output ( ) , err )
}
if ! strings . Contains ( got , "inactive" ) {
t . Errorf ( "For runtime %q: expected %q to be inactive but got %q " , ContainerRuntime ( ) , cr , got )
}
}
}
2019-12-16 15:58:45 +00:00
// validateUpdateContextCmd asserts basic "update-context" command functionality
func validateUpdateContextCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2020-08-16 05:03:41 +00:00
tests := [ ] struct {
name string
kubeconfig [ ] byte
want [ ] byte
} {
{
name : "no changes" ,
kubeconfig : nil ,
want : [ ] byte ( "No changes" ) ,
} ,
{
name : "no minikube cluster" ,
kubeconfig : [ ] byte ( `
apiVersion : v1
clusters :
- cluster :
certificate - authority : / home / la - croix / apiserver . crt
server : 192.168 .1 .1 : 8080
name : la - croix
contexts :
- context :
cluster : la - croix
user : la - croix
name : la - croix
current - context : la - croix
kind : Config
preferences : { }
users :
- name : la - croix
user :
client - certificate : / home / la - croix / apiserver . crt
client - key : / home / la - croix / apiserver . key
` ) ,
want : [ ] byte ( "context has been updated" ) ,
} ,
{
name : "no clusters" ,
kubeconfig : [ ] byte ( `
apiVersion : v1
clusters :
contexts :
kind : Config
preferences : { }
users :
` ) ,
want : [ ] byte ( "context has been updated" ) ,
} ,
2019-12-16 15:58:45 +00:00
}
2020-08-16 05:03:41 +00:00
for _ , tc := range tests {
tc := tc
2020-08-22 17:18:15 +00:00
if ctx . Err ( ) == context . DeadlineExceeded {
t . Fatalf ( "Unable to run more tests (deadline exceeded)" )
}
2020-08-16 05:03:41 +00:00
t . Run ( tc . name , func ( t * testing . T ) {
t . Parallel ( )
c := exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "update-context" , "--alsologtostderr" , "-v=2" )
if tc . kubeconfig != nil {
2021-09-28 10:58:01 +00:00
tf , err := os . CreateTemp ( "" , "kubeconfig" )
2020-08-16 05:03:41 +00:00
if err != nil {
t . Fatal ( err )
}
2021-09-28 10:58:01 +00:00
if err := os . WriteFile ( tf . Name ( ) , tc . kubeconfig , 0644 ) ; err != nil {
2020-08-16 05:03:41 +00:00
t . Fatal ( err )
}
t . Cleanup ( func ( ) {
os . Remove ( tf . Name ( ) )
} )
c . Env = append ( os . Environ ( ) , fmt . Sprintf ( "KUBECONFIG=%s" , tf . Name ( ) ) )
}
2021-10-11 01:46:44 +00:00
// docs: Run `minikube update-context`
2020-08-16 05:03:41 +00:00
rr , err := Run ( t , c )
if err != nil {
t . Errorf ( "failed to run minikube update-context: args %q: %v" , rr . Command ( ) , err )
}
2021-10-11 01:46:44 +00:00
// docs: Make sure the context has been correctly updated by checking the command output
2020-08-16 05:03:41 +00:00
if ! bytes . Contains ( rr . Stdout . Bytes ( ) , tc . want ) {
t . Errorf ( "update-context: got=%q, want=*%q*" , rr . Stdout . Bytes ( ) , tc . want )
}
} )
2019-12-16 15:58:45 +00:00
}
}
2021-06-30 16:16:25 +00:00
// startProxyWithCustomCerts mimics starts a proxy with custom certs by using mitmproxy and installing its certs
func startProxyWithCustomCerts ( ctx context . Context , t * testing . T ) error {
2021-06-22 21:57:53 +00:00
// Download the mitmproxy bundle for mitmdump
_ , err := Run ( t , exec . CommandContext ( ctx , "curl" , "-LO" , "https://snapshots.mitmproxy.org/6.0.2/mitmproxy-6.0.2-linux.tar.gz" ) )
2021-06-08 20:27:33 +00:00
if err != nil {
2021-06-24 20:47:03 +00:00
return errors . Wrap ( err , "download mitmproxy tar" )
2021-06-08 20:27:33 +00:00
}
2021-06-24 17:05:47 +00:00
defer func ( ) {
err := os . Remove ( "mitmproxy-6.0.2-linux.tar.gz" )
if err != nil {
2021-06-24 20:47:03 +00:00
t . Logf ( "remove tarball: %v" , err )
2021-06-24 17:05:47 +00:00
}
} ( )
2021-06-08 20:27:33 +00:00
2022-04-02 02:18:20 +00:00
mitmDir := t . TempDir ( )
2021-06-22 23:58:05 +00:00
_ , err = Run ( t , exec . CommandContext ( ctx , "tar" , "xzf" , "mitmproxy-6.0.2-linux.tar.gz" , "-C" , mitmDir ) )
2021-06-08 20:27:33 +00:00
if err != nil {
2021-06-24 20:47:03 +00:00
return errors . Wrap ( err , "untar mitmproxy tar" )
2021-06-08 20:27:33 +00:00
}
2021-06-22 21:57:53 +00:00
// Start mitmdump in the background, this will create the needed certs
// and provide the necessary proxy at 127.0.0.1:8080
2021-06-24 00:41:52 +00:00
mitmRR , err := Start ( t , exec . CommandContext ( ctx , path . Join ( mitmDir , "mitmdump" ) , "--set" , fmt . Sprintf ( "confdir=%s" , mitmDir ) ) )
2021-06-10 21:34:24 +00:00
if err != nil {
2021-06-24 20:47:03 +00:00
return errors . Wrap ( err , "starting mitmproxy" )
2021-06-10 21:34:24 +00:00
}
2021-06-24 17:05:47 +00:00
// Store it for cleanup later
mitm = mitmRR
2021-06-08 20:27:33 +00:00
2021-06-10 17:40:53 +00:00
// Add a symlink from the cert to the correct directory
2021-06-23 23:02:57 +00:00
certFile := path . Join ( mitmDir , "mitmproxy-ca-cert.pem" )
2021-06-24 00:41:52 +00:00
// wait 15 seconds for the certs to show up
_ , err = os . Stat ( certFile )
tries := 1
for os . IsNotExist ( err ) {
time . Sleep ( 1 * time . Second )
tries ++
if tries > 15 {
break
}
_ , err = os . Stat ( certFile )
}
if os . IsNotExist ( err ) {
2021-06-24 20:47:03 +00:00
return errors . Wrap ( err , "cert files never showed up" )
2021-06-24 00:41:52 +00:00
}
2021-06-10 17:40:53 +00:00
destCertPath := path . Join ( "/etc/ssl/certs" , "mitmproxy-ca-cert.pem" )
2021-06-24 00:41:52 +00:00
symLinkCmd := fmt . Sprintf ( "ln -fs %s %s" , certFile , destCertPath )
2021-06-10 17:40:53 +00:00
if _ , err := Run ( t , exec . CommandContext ( ctx , "sudo" , "/bin/bash" , "-c" , symLinkCmd ) ) ; err != nil {
2021-06-24 20:47:03 +00:00
return errors . Wrap ( err , "cert symlink" )
2021-06-10 17:40:53 +00:00
}
// Add a symlink of the form {hash}.0
rr , err := Run ( t , exec . CommandContext ( ctx , "openssl" , "x509" , "-hash" , "-noout" , "-in" , certFile ) )
if err != nil {
2021-06-24 20:47:03 +00:00
return errors . Wrap ( err , "cert hashing" )
2021-06-10 17:40:53 +00:00
}
stringHash := strings . TrimSpace ( rr . Stdout . String ( ) )
hashLink := path . Join ( "/etc/ssl/certs" , fmt . Sprintf ( "%s.0" , stringHash ) )
hashCmd := fmt . Sprintf ( "test -L %s || ln -fs %s %s" , hashLink , destCertPath , hashLink )
if _ , err := Run ( t , exec . CommandContext ( ctx , "sudo" , "/bin/bash" , "-c" , hashCmd ) ) ; err != nil {
2021-06-24 20:48:51 +00:00
return errors . Wrap ( err , "cert hash symlink" )
2021-06-24 17:49:47 +00:00
}
2021-06-24 20:47:03 +00:00
return nil
2021-06-08 20:27:33 +00:00
}
2019-09-11 16:59:38 +00:00
// startHTTPProxy runs a local http proxy and sets the env vars for it.
func startHTTPProxy ( t * testing . T ) ( * http . Server , error ) {
port , err := freeport . GetFreePort ( )
if err != nil {
return nil , errors . Wrap ( err , "Failed to get an open port" )
}
addr := fmt . Sprintf ( "localhost:%d" , port )
proxy := goproxy . NewProxyHttpServer ( )
srv := & http . Server { Addr : addr , Handler : proxy }
go func ( s * http . Server , t * testing . T ) {
if err := s . ListenAndServe ( ) ; err != http . ErrServerClosed {
t . Errorf ( "Failed to start http server for proxy mock" )
}
} ( srv , t )
return srv , nil
2016-12-05 22:49:52 +00:00
}
2021-06-24 22:41:04 +00:00
func startMinikubeWithProxy ( ctx context . Context , t * testing . T , profile string , proxyEnv string , addr string ) {
// Use more memory so that we may reliably fit MySQL and nginx
memoryFlag := "--memory=4000"
// to avoid failure for mysq/pv on virtualbox on darwin on free github actions,
2022-01-06 17:56:54 +00:00
if detect . GithubActionRunner ( ) && VirtualboxDriver ( ) {
2021-06-24 22:41:04 +00:00
memoryFlag = "--memory=6000"
}
// passing --api-server-port so later verify it didn't change in soft start.
startArgs := append ( [ ] string { "start" , "-p" , profile , memoryFlag , fmt . Sprintf ( "--apiserver-port=%d" , apiPortTest ) , "--wait=all" } , StartArgs ( ) ... )
c := exec . CommandContext ( ctx , Target ( ) , startArgs ... )
env := os . Environ ( )
env = append ( env , fmt . Sprintf ( "%s=%s" , proxyEnv , addr ) )
env = append ( env , "NO_PROXY=" )
c . Env = env
rr , err := Run ( t , c )
if err != nil {
t . Errorf ( "failed minikube start. args %q: %v" , rr . Command ( ) , err )
}
want := "Found network options:"
if ! strings . Contains ( rr . Stdout . String ( ) , want ) {
t . Errorf ( "start stdout=%s, want: *%s*" , rr . Stdout . String ( ) , want )
}
want = "You appear to be using a proxy"
if ! strings . Contains ( rr . Stderr . String ( ) , want ) {
t . Errorf ( "start stderr=%s, want: *%s*" , rr . Stderr . String ( ) , want )
}
}
2021-06-30 21:04:50 +00:00
// validateVersionCmd asserts `minikube version` command works fine for both --short and --components
func validateVersionCmd ( ctx context . Context , t * testing . T , profile string ) {
2021-10-11 01:46:44 +00:00
// docs: Run `minikube version --short` and make sure the returned version is a valid semver
2021-06-30 21:04:50 +00:00
t . Run ( "short" , func ( t * testing . T ) {
MaybeParallel ( t )
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "version" , "--short" ) )
if err != nil {
t . Errorf ( "failed to get version --short: %v" , err )
}
_ , err = semver . Make ( strings . TrimSpace ( strings . Trim ( rr . Stdout . String ( ) , "v" ) ) )
if err != nil {
t . Errorf ( "failed to get a valid semver for minikube version --short:%s %v" , rr . Output ( ) , err )
}
} )
2021-10-11 01:46:44 +00:00
// docs: Run `minikube version --components` and make sure the component versions are returned
2021-06-30 21:04:50 +00:00
t . Run ( "components" , func ( t * testing . T ) {
MaybeParallel ( t )
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "version" , "-o=json" , "--components" ) )
if err != nil {
t . Errorf ( "error version: %v" , err )
}
got := rr . Stdout . String ( )
2021-09-08 22:21:52 +00:00
for _ , c := range [ ] string { "buildctl" , "commit" , "containerd" , "crictl" , "crio" , "ctr" , "docker" , "minikubeVersion" , "podman" , "run" , "crun" } {
2021-07-01 19:19:24 +00:00
if ! strings . Contains ( got , c ) {
t . Errorf ( "expected to see %q in the minikube version --components but got:\n%s" , c , got )
}
2021-06-30 21:04:50 +00:00
}
} )
}