2021-09-13 18:58:43 +00:00
//go:build integration
2019-09-11 17:16:16 +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 (
2020-10-08 20:25:19 +00:00
"bytes"
2019-09-11 17:16:16 +00:00
"context"
2020-10-08 20:25:19 +00:00
"encoding/json"
2022-12-05 16:34:40 +00:00
"errors"
2019-09-11 17:16:16 +00:00
"fmt"
"net/http"
"net/url"
2020-10-08 20:25:19 +00:00
"os"
2019-09-11 17:16:16 +00:00
"os/exec"
"path/filepath"
2020-10-08 20:25:19 +00:00
"reflect"
2022-06-21 20:39:50 +00:00
"regexp"
2019-09-11 17:16:16 +00:00
"strings"
2024-04-08 14:47:51 +00:00
"sync"
2019-09-11 17:16:16 +00:00
"testing"
"time"
2021-10-28 02:50:06 +00:00
"github.com/blang/semver/v4"
2021-03-15 18:39:06 +00:00
retryablehttp "github.com/hashicorp/go-retryablehttp"
2023-01-14 12:13:56 +00:00
core "k8s.io/api/core/v1"
2019-09-11 17:16:16 +00:00
"k8s.io/minikube/pkg/kapi"
2022-12-27 04:27:48 +00:00
"k8s.io/minikube/pkg/minikube/constants"
2021-03-09 23:11:54 +00:00
"k8s.io/minikube/pkg/minikube/detect"
2019-09-11 17:16:16 +00:00
"k8s.io/minikube/pkg/util/retry"
)
2021-04-16 20:42:41 +00:00
// TestAddons tests addons that require no special environment in parallel
2019-09-11 17:16:16 +00:00
func TestAddons ( t * testing . T ) {
profile := UniqueProfileName ( "addons" )
2020-02-21 00:19:59 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , Minutes ( 40 ) )
2020-05-08 20:12:30 +00:00
defer Cleanup ( t , profile , cancel )
2019-09-11 17:16:16 +00:00
2023-09-29 20:07:25 +00:00
t . Run ( "PreSetup" , func ( t * testing . T ) {
2023-09-29 20:03:13 +00:00
tests := [ ] struct {
name string
validator validateFunc
} {
{ "EnablingAddonOnNonExistingCluster" , validateEnablingAddonOnNonExistingCluster } ,
{ "DisablingAddonOnNonExistingCluster" , validateDisablingAddonOnNonExistingCluster } ,
}
for _ , tc := range tests {
tc := tc
if ctx . Err ( ) == context . DeadlineExceeded {
t . Fatalf ( "Unable to run more tests (deadline exceeded)" )
}
t . Run ( tc . name , func ( t * testing . T ) {
MaybeParallel ( t )
tc . validator ( ctx , t , profile )
} )
}
} )
2021-08-13 22:26:39 +00:00
setupSucceeded := t . Run ( "Setup" , func ( t * testing . T ) {
2021-10-22 00:04:20 +00:00
// Set an env var to point to our dummy credentials file
2021-10-25 19:49:49 +00:00
// don't use t.Setenv because we sometimes manually unset the env var later manually
err := os . Setenv ( "GOOGLE_APPLICATION_CREDENTIALS" , filepath . Join ( * testdataDir , "gcp-creds.json" ) )
t . Cleanup ( func ( ) {
os . Unsetenv ( "GOOGLE_APPLICATION_CREDENTIALS" )
} )
if err != nil {
t . Fatalf ( "Failed setting GOOGLE_APPLICATION_CREDENTIALS env var: %v" , err )
}
err = os . Setenv ( "GOOGLE_CLOUD_PROJECT" , "this_is_fake" )
t . Cleanup ( func ( ) {
os . Unsetenv ( "GOOGLE_CLOUD_PROJECT" )
} )
if err != nil {
t . Fatalf ( "Failed setting GOOGLE_CLOUD_PROJECT env var: %v" , err )
}
2019-09-11 17:16:16 +00:00
2022-12-07 23:05:31 +00:00
// MOCK_GOOGLE_TOKEN forces the gcp-auth webhook to use a mock token instead of trying to get a valid one from the credentials.
2022-12-27 04:27:48 +00:00
os . Setenv ( "MOCK_GOOGLE_TOKEN" , "true" )
2022-12-28 00:51:45 +00:00
// for some reason, (Docker_Cloud_Shell) sets 'MINIKUBE_FORCE_SYSTEMD=true' while having cgroupfs set in docker (and probably os itself), which might make it unstable and occasionally fail:
2022-12-27 04:27:48 +00:00
// - I1226 15:05:24.834294 11286 out.go:177] - MINIKUBE_FORCE_SYSTEMD=true
// - I1226 15:05:25.070037 11286 info.go:266] docker info: {... CgroupDriver:cgroupfs ...}
// ref: https://storage.googleapis.com/minikube-builds/logs/15463/27154/Docker_Cloud_Shell.html
// so we override that here to let minikube auto-detect appropriate cgroup driver
os . Setenv ( constants . MinikubeForceSystemdEnv , "" )
2022-12-07 23:05:31 +00:00
2024-10-11 20:36:06 +00:00
args := append ( [ ] string { "start" , "-p" , profile , "--wait=true" , "--memory=4000" , "--alsologtostderr" , "--addons=registry" , "--addons=metrics-server" , "--addons=volumesnapshots" , "--addons=csi-hostpath-driver" , "--addons=gcp-auth" , "--addons=cloud-spanner" , "--addons=inspektor-gadget" , "--addons=nvidia-device-plugin" , "--addons=yakd" , "--addons=volcano" , "--addons=amd-gpu-device-plugin" } , StartArgs ( ) ... )
2024-10-01 17:43:23 +00:00
if ! NoneDriver ( ) {
args = append ( args , "--addons=ingress" , "--addons=ingress-dns" , "--addons=storage-provisioner-rancher" )
2021-08-12 16:34:29 +00:00
}
2021-03-09 22:32:02 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , args ... ) )
2021-08-10 19:57:10 +00:00
if err != nil {
2021-08-12 16:34:29 +00:00
t . Fatalf ( "%s failed: %v" , rr . Command ( ) , err )
2021-03-24 23:18:28 +00:00
}
2019-09-11 17:16:16 +00:00
2021-08-12 16:34:29 +00:00
} )
2021-03-09 22:32:02 +00:00
2021-08-13 22:26:39 +00:00
if ! setupSucceeded {
2021-08-12 20:49:08 +00:00
t . Fatalf ( "Failed setup for addon tests" )
2021-03-09 22:32:02 +00:00
}
2024-10-11 20:36:06 +00:00
type TestCase = struct {
name string
validator validateFunc
}
2024-07-17 22:32:50 +00:00
// Run tests in serial to avoid collision
t . Run ( "serial" , func ( t * testing . T ) {
2024-10-11 20:36:06 +00:00
tests := [ ] TestCase {
2024-04-08 14:47:51 +00:00
{ "Volcano" , validateVolcanoAddon } ,
2024-07-17 22:32:50 +00:00
{ "GCPAuth" , validateGCPAuthAddon } ,
2019-09-11 17:16:16 +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 17:16:16 +00:00
t . Run ( tc . name , func ( t * testing . T ) {
tc . validator ( ctx , t , profile )
} )
}
} )
2019-10-17 21:48:41 +00:00
2024-07-17 22:32:50 +00:00
// Parallelized tests
t . Run ( "parallel" , func ( t * testing . T ) {
2024-10-11 20:36:06 +00:00
tests := [ ] TestCase {
2024-07-17 22:32:50 +00:00
{ "Registry" , validateRegistryAddon } ,
{ "Ingress" , validateIngressAddon } ,
{ "InspektorGadget" , validateInspektorGadgetAddon } ,
{ "MetricsServer" , validateMetricsServerAddon } ,
{ "Olm" , validateOlmAddon } ,
{ "CSI" , validateCSIDriverAndSnapshots } ,
{ "Headlamp" , validateHeadlampAddon } ,
{ "CloudSpanner" , validateCloudSpannerAddon } ,
{ "LocalPath" , validateLocalPathAddon } ,
{ "NvidiaDevicePlugin" , validateNvidiaDevicePlugin } ,
{ "Yakd" , validateYakdAddon } ,
2024-10-11 20:36:06 +00:00
{ "AmdGpuDevicePlugin" , validateAmdGpuDevicePlugin } ,
2021-09-15 19:25:22 +00:00
}
2024-10-11 20:36:06 +00:00
2021-09-15 19:25:22 +00:00
for _ , tc := range tests {
tc := tc
if ctx . Err ( ) == context . DeadlineExceeded {
t . Fatalf ( "Unable to run more tests (deadline exceeded)" )
}
t . Run ( tc . name , func ( t * testing . T ) {
2024-07-17 22:32:50 +00:00
MaybeParallel ( t )
2021-09-15 19:25:22 +00:00
tc . validator ( ctx , t , profile )
} )
}
} )
2021-08-12 16:34:29 +00:00
t . Run ( "StoppedEnableDisable" , func ( t * testing . T ) {
// Assert that disable/enable works offline
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "stop" , "-p" , profile ) )
if err != nil {
t . Errorf ( "failed to stop minikube. args %q : %v" , rr . Command ( ) , err )
}
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "addons" , "enable" , "dashboard" , "-p" , profile ) )
if err != nil {
t . Errorf ( "failed to enable dashboard addon: args %q : %v" , rr . Command ( ) , err )
}
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "addons" , "disable" , "dashboard" , "-p" , profile ) )
if err != nil {
t . Errorf ( "failed to disable dashboard addon: args %q : %v" , rr . Command ( ) , err )
}
2023-03-23 22:15:30 +00:00
// Disable a non-enabled addon
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "addons" , "disable" , "gvisor" , "-p" , profile ) )
if err != nil {
t . Errorf ( "failed to disable non-enabled addon: args %q : %v" , rr . Command ( ) , err )
}
2021-08-12 16:34:29 +00:00
} )
2019-09-11 17:16:16 +00:00
}
2021-04-16 20:42:41 +00:00
// validateIngressAddon tests the ingress addon by deploying a default nginx pod
2019-09-11 17:16:16 +00:00
func validateIngressAddon ( ctx context . Context , t * testing . T , profile string ) {
2021-08-01 11:23:39 +00:00
if NoneDriver ( ) {
2021-09-15 00:41:26 +00:00
t . Skipf ( "skipping: ingress not supported" )
2019-09-11 17:16:16 +00:00
}
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "ingress" , profile )
defer disableAddon ( t , "ingress-dns" , profile )
defer PostMortemLogs ( t , profile )
2019-09-11 17:16:16 +00:00
client , err := kapi . Client ( profile )
if err != nil {
2020-05-07 21:12:10 +00:00
t . Fatalf ( "failed to get Kubernetes client: %v" , client )
2019-09-11 17:16:16 +00:00
}
2021-08-22 02:58:34 +00:00
// avoid timeouts like:
// Error from server (InternalError): Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io": Post "https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking/v1/ingresses?timeout=10s": dial tcp 10.107.218.58:443: i/o timeout
// Error from server (InternalError): Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io": Post "https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking/v1/ingresses?timeout=10s": context deadline exceeded
if _ , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "wait" , "--for=condition=ready" , "--namespace=ingress-nginx" , "pod" , "--selector=app.kubernetes.io/component=controller" , "--timeout=90s" ) ) ; err != nil {
2021-09-15 00:41:26 +00:00
t . Fatalf ( "failed waiting for ingress-nginx-controller : %v" , err )
2019-09-11 17:16:16 +00:00
}
2021-10-28 02:50:06 +00:00
// use nginx ingress yaml that corresponds to k8s version
// default: k8s >= v1.19, ingress api v1
ingressYaml := "nginx-ingress-v1.yaml"
ingressDNSYaml := "ingress-dns-example-v1.yaml"
v , err := client . ServerVersion ( )
2023-03-26 00:13:11 +00:00
if err == nil {
// for pre-release k8s version, remove any "+" suffix in minor version to be semver-compliant and not panic
// ref: https://github.com/kubernetes/minikube/pull/16145#issuecomment-1483283260
minor := strings . TrimSuffix ( v . Minor , "+" )
if semver . MustParseRange ( "<1.19.0" ) ( semver . MustParse ( fmt . Sprintf ( "%s.%s.0" , v . Major , minor ) ) ) {
// legacy: k8s < v1.19 & ingress api v1beta1
ingressYaml = "nginx-ingress-v1beta1.yaml"
ingressDNSYaml = "ingress-dns-example-v1beta1.yaml"
}
} else {
2021-10-28 02:50:06 +00:00
t . Log ( "failed to get k8s version, assuming v1.19+ => ingress api v1" )
}
2021-08-10 21:24:43 +00:00
// create networking.k8s.io/v1 ingress
createv1Ingress := func ( ) error {
2021-08-22 02:58:34 +00:00
// apply networking.k8s.io/v1 ingress
2021-10-28 02:50:06 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "replace" , "--force" , "-f" , filepath . Join ( * testdataDir , ingressYaml ) ) )
2020-05-05 19:36:03 +00:00
if err != nil {
return err
}
if rr . Stderr . String ( ) != "" {
2020-10-30 17:34:19 +00:00
t . Logf ( "%v: unexpected stderr: %s (may be temporary)" , rr . Command ( ) , rr . Stderr )
2020-05-05 19:36:03 +00:00
}
return nil
2019-09-11 17:16:16 +00:00
}
2021-08-10 21:24:43 +00:00
if err := retry . Expo ( createv1Ingress , 1 * time . Second , Seconds ( 90 ) ) ; err != nil {
2020-05-05 19:36:03 +00:00
t . Errorf ( "failed to create ingress: %v" , err )
}
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "replace" , "--force" , "-f" , filepath . Join ( * testdataDir , "nginx-pod-svc.yaml" ) ) )
2019-09-11 17:16:16 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to kubectl replace nginx-pod-svc. args %q. %v" , rr . Command ( ) , err )
2019-09-11 17:16:16 +00:00
}
2021-09-15 00:41:26 +00:00
if _ , err := PodWait ( ctx , t , profile , "default" , "run=nginx" , Minutes ( 8 ) ) ; err != nil {
2020-03-26 02:58:38 +00:00
t . Fatalf ( "failed waiting for ngnix pod: %v" , err )
2019-09-11 17:16:16 +00:00
}
2020-02-21 00:40:18 +00:00
if err := kapi . WaitForService ( client , "default" , "nginx" , true , time . Millisecond * 500 , Minutes ( 10 ) ) ; err != nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "failed waiting for nginx service to be up: %v" , err )
2019-09-11 17:16:16 +00:00
}
want := "Welcome to nginx!"
2020-05-04 22:31:49 +00:00
addr := "http://127.0.0.1/"
2021-04-24 20:40:24 +00:00
// check if the ingress can route nginx app with networking.k8s.io/v1 ingress
checkv1Ingress := func ( ) error {
2021-09-15 00:41:26 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , fmt . Sprintf ( "curl -s %s -H 'Host: nginx.example.com'" , addr ) ) )
if err != nil {
return err
2021-04-24 20:40:24 +00:00
}
2021-09-15 00:41:26 +00:00
2021-04-24 20:40:24 +00:00
stderr := rr . Stderr . String ( )
if rr . Stderr . String ( ) != "" {
t . Logf ( "debug: unexpected stderr for %v:\n%s" , rr . Command ( ) , stderr )
}
stdout := rr . Stdout . String ( )
if ! strings . Contains ( stdout , want ) {
return fmt . Errorf ( "%v stdout = %q, want %q" , rr . Command ( ) , stdout , want )
}
return nil
}
if err := retry . Expo ( checkv1Ingress , 500 * time . Millisecond , Seconds ( 90 ) ) ; err != nil {
2020-05-04 22:31:49 +00:00
t . Errorf ( "failed to get expected response from %s within minikube: %v" , addr , err )
2019-09-11 17:16:16 +00:00
}
2021-09-21 20:42:13 +00:00
if NeedsPortForward ( ) {
t . Skip ( "skipping ingress DNS test for any combination that needs port forwarding" )
}
2021-09-15 00:41:26 +00:00
// check the ingress-dns addon here as well
2021-10-28 02:50:06 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "replace" , "--force" , "-f" , filepath . Join ( * testdataDir , ingressDNSYaml ) ) )
2021-09-15 00:41:26 +00:00
if err != nil {
t . Errorf ( "failed to kubectl replace ingress-dns-example. args %q. %v" , rr . Command ( ) , err )
}
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ip" ) )
if err != nil {
t . Errorf ( "failed to retrieve minikube ip. args %q : %v" , rr . Command ( ) , err )
}
ip := strings . TrimSuffix ( rr . Stdout . String ( ) , "\n" )
rr , err = Run ( t , exec . CommandContext ( ctx , "nslookup" , "hello-john.test" , ip ) )
if err != nil {
t . Errorf ( "failed to nslookup hello-john.test host. args %q : %v" , rr . Command ( ) , err )
}
// nslookup should include info about the hello-john.test host, including minikube's ip
if ! strings . Contains ( rr . Stdout . String ( ) , ip ) {
t . Errorf ( "unexpected output from nslookup. stdout: %v\nstderr: %v" , rr . Stdout . String ( ) , rr . Stderr . String ( ) )
}
2019-09-11 17:16:16 +00:00
}
2021-04-16 20:42:41 +00:00
// validateRegistryAddon tests the registry addon
2019-09-11 17:16:16 +00:00
func validateRegistryAddon ( ctx context . Context , t * testing . T , profile string ) {
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "registry" , profile )
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2019-09-11 17:16:16 +00:00
client , err := kapi . Client ( profile )
if err != nil {
2020-05-07 21:12:10 +00:00
t . Fatalf ( "failed to get Kubernetes client for %s : %v" , profile , err )
2019-09-11 17:16:16 +00:00
}
start := time . Now ( )
2024-07-16 23:02:49 +00:00
if err := kapi . WaitForDeploymentToStabilize ( client , "kube-system" , "registry" , Minutes ( 6 ) ) ; err != nil {
t . Errorf ( "failed waiting for registry deployment to stabilize: %v" , err )
2019-09-11 17:16:16 +00:00
}
t . Logf ( "registry stabilized in %s" , time . Since ( start ) )
2020-02-21 00:40:18 +00:00
if _ , err := PodWait ( ctx , t , profile , "kube-system" , "actual-registry=true" , Minutes ( 6 ) ) ; err != nil {
2020-03-26 02:58:38 +00:00
t . Fatalf ( "failed waiting for pod actual-registry: %v" , err )
2019-09-11 17:16:16 +00:00
}
2020-02-21 00:40:18 +00:00
if _ , err := PodWait ( ctx , t , profile , "kube-system" , "registry-proxy=true" , Minutes ( 10 ) ) ; err != nil {
2020-03-26 02:58:38 +00:00
t . Fatalf ( "failed waiting for pod registry-proxy: %v" , err )
2019-09-11 17:16:16 +00:00
}
// Test from inside the cluster (no curl available on busybox)
2019-10-04 15:25:49 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "delete" , "po" , "-l" , "run=registry-test" , "--now" ) )
2019-09-11 17:16:16 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Logf ( "pre-cleanup %s failed: %v (not a problem)" , rr . Command ( ) , err )
2019-09-11 17:16:16 +00:00
}
2021-12-21 19:58:24 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "run" , "--rm" , "registry-test" , "--restart=Never" , "--image=gcr.io/k8s-minikube/busybox" , "-it" , "--" , "sh" , "-c" , "wget --spider -S http://registry.kube-system.svc.cluster.local" ) )
2019-09-11 17:16:16 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to hit registry.kube-system.svc.cluster.local. args %q failed: %v" , rr . Command ( ) , err )
2019-09-11 17:16:16 +00:00
}
want := "HTTP/1.1 200"
if ! strings . Contains ( rr . Stdout . String ( ) , want ) {
2020-03-26 02:58:38 +00:00
t . Errorf ( "expected curl response be %q, but got *%s*" , want , rr . Stdout . String ( ) )
2019-09-11 17:16:16 +00:00
}
2020-04-01 20:01:12 +00:00
if NeedsPortForward ( ) {
t . Skipf ( "Unable to complete rest of the test due to connectivity assumptions" )
}
2019-09-11 17:16:16 +00:00
// Test from outside the cluster
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ip" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed run minikube ip. args %q : %v" , rr . Command ( ) , err )
2019-09-11 17:16:16 +00:00
}
if rr . Stderr . String ( ) != "" {
2020-03-26 05:21:19 +00:00
t . Errorf ( "expected stderr to be -empty- but got: *%q* . args %q" , rr . Stderr , rr . Command ( ) )
2019-09-11 17:16:16 +00:00
}
endpoint := fmt . Sprintf ( "http://%s:%d" , strings . TrimSpace ( rr . Stdout . String ( ) ) , 5000 )
u , err := url . Parse ( endpoint )
if err != nil {
t . Fatalf ( "failed to parse %q: %v" , endpoint , err )
}
checkExternalAccess := func ( ) error {
resp , err := retryablehttp . Get ( u . String ( ) )
if err != nil {
return err
}
if resp . StatusCode != http . StatusOK {
return fmt . Errorf ( "%s = status code %d, want %d" , u , resp . StatusCode , http . StatusOK )
}
return nil
}
2020-03-26 02:58:38 +00:00
if err := retry . Expo ( checkExternalAccess , 500 * time . Millisecond , Seconds ( 150 ) ) ; err != nil {
t . Errorf ( "failed to check external access to %s: %v" , u . String ( ) , err . Error ( ) )
2019-09-11 17:16:16 +00:00
}
}
2019-11-16 16:01:48 +00:00
2021-04-16 20:42:41 +00:00
// validateMetricsServerAddon tests the metrics server addon by making sure "kubectl top pods" returns a sensible result
2019-11-16 16:01:48 +00:00
func validateMetricsServerAddon ( ctx context . Context , t * testing . T , profile string ) {
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "metrics-server" , profile )
2020-05-08 20:12:30 +00:00
defer PostMortemLogs ( t , profile )
2019-11-16 16:01:48 +00:00
client , err := kapi . Client ( profile )
if err != nil {
2020-05-07 21:12:10 +00:00
t . Fatalf ( "failed to get Kubernetes client for %s: %v" , profile , err )
2019-11-16 16:01:48 +00:00
}
start := time . Now ( )
2020-02-21 00:40:18 +00:00
if err := kapi . WaitForDeploymentToStabilize ( client , "kube-system" , "metrics-server" , Minutes ( 6 ) ) ; err != nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "failed waiting for metrics-server deployment to stabilize: %v" , err )
2019-11-16 16:01:48 +00:00
}
t . Logf ( "metrics-server stabilized in %s" , time . Since ( start ) )
2020-02-21 00:40:18 +00:00
if _ , err := PodWait ( ctx , t , profile , "kube-system" , "k8s-app=metrics-server" , Minutes ( 6 ) ) ; err != nil {
2020-03-26 02:58:38 +00:00
t . Fatalf ( "failed waiting for k8s-app=metrics-server pod: %v" , err )
2019-11-16 16:01:48 +00:00
}
want := "CPU(cores)"
checkMetricsServer := func ( ) error {
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "top" , "pods" , "-n" , "kube-system" ) )
if err != nil {
return err
}
if rr . Stderr . String ( ) != "" {
2020-03-26 05:21:19 +00:00
t . Logf ( "%v: unexpected stderr: %s" , rr . Command ( ) , rr . Stderr )
2019-11-16 16:01:48 +00:00
}
if ! strings . Contains ( rr . Stdout . String ( ) , want ) {
2020-03-26 05:21:19 +00:00
return fmt . Errorf ( "%v stdout = %q, want %q" , rr . Command ( ) , rr . Stdout , want )
2019-11-16 16:01:48 +00:00
}
return nil
}
2020-03-24 13:37:16 +00:00
if err := retry . Expo ( checkMetricsServer , time . Second * 3 , Minutes ( 6 ) ) ; err != nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "failed checking metric server: %v" , err . Error ( ) )
2019-11-16 16:01:48 +00:00
}
}
2020-03-21 09:27:57 +00:00
2021-04-16 20:42:41 +00:00
// validateOlmAddon tests the OLM addon
2020-05-20 19:51:31 +00:00
func validateOlmAddon ( ctx context . Context , t * testing . T , profile string ) {
2022-03-30 17:53:11 +00:00
t . Skip ( "Skipping OLM addon test until https://github.com/operator-framework/operator-lifecycle-manager/issues/2534 is resolved" )
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "olm" , profile )
2021-12-23 20:57:02 +00:00
defer PostMortemLogs ( t , profile )
2020-05-20 19:51:31 +00:00
start := time . Now ( )
2021-08-24 01:30:39 +00:00
if _ , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "wait" , "--for=condition=ready" , "--namespace=olm" , "pod" , "--selector=app=catalog-operator" , "--timeout=90s" ) ) ; err != nil {
2021-12-21 19:19:35 +00:00
t . Fatalf ( "failed waiting for pod catalog-operator: %v" , err )
2020-05-20 19:51:31 +00:00
}
t . Logf ( "catalog-operator stabilized in %s" , time . Since ( start ) )
2021-08-24 01:30:39 +00:00
if _ , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "wait" , "--for=condition=ready" , "--namespace=olm" , "pod" , "--selector=app=olm-operator" , "--timeout=90s" ) ) ; err != nil {
2021-12-21 19:19:35 +00:00
t . Fatalf ( "failed waiting for pod olm-operator: %v" , err )
2020-05-20 19:51:31 +00:00
}
t . Logf ( "olm-operator stabilized in %s" , time . Since ( start ) )
2021-08-24 01:30:39 +00:00
if _ , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "wait" , "--for=condition=ready" , "--namespace=olm" , "pod" , "--selector=app=packageserver" , "--timeout=90s" ) ) ; err != nil {
2021-12-21 19:19:35 +00:00
t . Fatalf ( "failed waiting for pod olm-operator: %v" , err )
2020-05-20 19:51:31 +00:00
}
t . Logf ( "packageserver stabilized in %s" , time . Since ( start ) )
2021-08-24 01:30:39 +00:00
if _ , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "wait" , "--for=condition=ready" , "--namespace=olm" , "pod" , "--selector=olm.catalogSource=operatorhubio-catalog" , "--timeout=90s" ) ) ; err != nil {
2021-12-21 19:19:35 +00:00
t . Fatalf ( "failed waiting for pod operatorhubio-catalog: %v" , err )
2020-05-20 19:51:31 +00:00
}
2021-08-24 01:30:39 +00:00
t . Logf ( "operatorhubio-catalog stabilized in %s" , time . Since ( start ) )
2020-05-20 19:51:31 +00:00
// Install one sample Operator such as etcd
2021-05-07 21:52:13 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "-f" , filepath . Join ( * testdataDir , "etcd.yaml" ) ) )
2020-05-20 19:51:31 +00:00
if err != nil {
t . Logf ( "etcd operator installation with %s failed: %v" , rr . Command ( ) , err )
}
want := "Succeeded"
checkOperatorInstalled := func ( ) error {
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "csv" , "-n" , "my-etcd" ) )
if err != nil {
return err
}
if rr . Stderr . String ( ) != "" {
t . Logf ( "%v: unexpected stderr: %s" , rr . Command ( ) , rr . Stderr )
}
if ! strings . Contains ( rr . Stdout . String ( ) , want ) {
return fmt . Errorf ( "%v stdout = %q, want %q" , rr . Command ( ) , rr . Stdout , want )
}
return nil
}
// Operator installation takes a while
2021-05-07 21:52:13 +00:00
if err := retry . Expo ( checkOperatorInstalled , time . Second * 3 , Minutes ( 10 ) ) ; err != nil {
2020-05-20 19:51:31 +00:00
t . Errorf ( "failed checking operator installed: %v" , err . Error ( ) )
}
}
2020-08-10 15:24:23 +00:00
2021-04-16 20:42:41 +00:00
// validateCSIDriverAndSnapshots tests the csi hostpath driver by creating a persistent volume, snapshotting it and restoring it.
2020-08-10 15:24:23 +00:00
func validateCSIDriverAndSnapshots ( ctx context . Context , t * testing . T , profile string ) {
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "csi-hostpath-driver" , profile )
defer disableAddon ( t , "volumesnapshots" , profile )
2020-08-10 15:24:23 +00:00
defer PostMortemLogs ( t , profile )
client , err := kapi . Client ( profile )
if err != nil {
t . Fatalf ( "failed to get Kubernetes client for %s: %v" , profile , err )
}
start := time . Now ( )
if err := kapi . WaitForPods ( client , "kube-system" , "kubernetes.io/minikube-addons=csi-hostpath-driver" , Minutes ( 6 ) ) ; err != nil {
t . Errorf ( "failed waiting for csi-hostpath-driver pods to stabilize: %v" , err )
}
t . Logf ( "csi-hostpath-driver pods stabilized in %s" , time . Since ( start ) )
// create sample PVC
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "-f" , filepath . Join ( * testdataDir , "csi-hostpath-driver" , "pvc.yaml" ) ) )
if err != nil {
t . Logf ( "creating sample PVC with %s failed: %v" , rr . Command ( ) , err )
}
if err := PVCWait ( ctx , t , profile , "default" , "hpvc" , Minutes ( 6 ) ) ; err != nil {
t . Fatalf ( "failed waiting for PVC hpvc: %v" , err )
}
// create sample pod with the PVC
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "-f" , filepath . Join ( * testdataDir , "csi-hostpath-driver" , "pv-pod.yaml" ) ) )
if err != nil {
t . Logf ( "creating pod with %s failed: %v" , rr . Command ( ) , err )
}
if _ , err := PodWait ( ctx , t , profile , "default" , "app=task-pv-pod" , Minutes ( 6 ) ) ; err != nil {
t . Fatalf ( "failed waiting for pod task-pv-pod: %v" , err )
}
// create volume snapshot
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "-f" , filepath . Join ( * testdataDir , "csi-hostpath-driver" , "snapshot.yaml" ) ) )
if err != nil {
t . Logf ( "creating pod with %s failed: %v" , rr . Command ( ) , err )
}
if err := VolumeSnapshotWait ( ctx , t , profile , "default" , "new-snapshot-demo" , Minutes ( 6 ) ) ; err != nil {
t . Fatalf ( "failed waiting for volume snapshot new-snapshot-demo: %v" , err )
}
// delete pod
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "delete" , "pod" , "task-pv-pod" ) )
if err != nil {
t . Logf ( "deleting pod with %s failed: %v" , rr . Command ( ) , err )
}
// delete pvc
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "delete" , "pvc" , "hpvc" ) )
if err != nil {
t . Logf ( "deleting pod with %s failed: %v" , rr . Command ( ) , err )
}
// restore pv from snapshot
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "-f" , filepath . Join ( * testdataDir , "csi-hostpath-driver" , "pvc-restore.yaml" ) ) )
if err != nil {
t . Logf ( "creating pvc with %s failed: %v" , rr . Command ( ) , err )
}
if err = PVCWait ( ctx , t , profile , "default" , "hpvc-restore" , Minutes ( 6 ) ) ; err != nil {
t . Fatalf ( "failed waiting for PVC hpvc-restore: %v" , err )
}
// create pod from restored snapshot
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "-f" , filepath . Join ( * testdataDir , "csi-hostpath-driver" , "pv-pod-restore.yaml" ) ) )
if err != nil {
t . Logf ( "creating pod with %s failed: %v" , rr . Command ( ) , err )
}
if _ , err := PodWait ( ctx , t , profile , "default" , "app=task-pv-pod-restore" , Minutes ( 6 ) ) ; err != nil {
t . Fatalf ( "failed waiting for pod task-pv-pod-restore: %v" , err )
}
// CLEANUP
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "delete" , "pod" , "task-pv-pod-restore" ) )
if err != nil {
t . Logf ( "cleanup with %s failed: %v" , rr . Command ( ) , err )
}
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "delete" , "pvc" , "hpvc-restore" ) )
if err != nil {
t . Logf ( "cleanup with %s failed: %v" , rr . Command ( ) , err )
}
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "delete" , "volumesnapshot" , "new-snapshot-demo" ) )
if err != nil {
t . Logf ( "cleanup with %s failed: %v" , rr . Command ( ) , err )
}
}
2020-10-08 20:25:19 +00:00
2022-11-30 23:50:32 +00:00
// validateGCPAuthNamespaces validates that newly created namespaces contain the gcp-auth secret.
func validateGCPAuthNamespaces ( ctx context . Context , t * testing . T , profile string ) {
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "ns" , "new-namespace" ) )
if err != nil {
t . Fatalf ( "%s failed: %v" , rr . Command ( ) , err )
}
2022-12-07 23:05:31 +00:00
logsAsError := func ( ) error {
2022-12-05 16:34:40 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "logs" , "-l" , "app=gcp-auth" , "-n" , "gcp-auth" ) )
if err != nil {
return err
}
return errors . New ( rr . Output ( ) )
}
2022-12-01 22:42:38 +00:00
getSecret := func ( ) error {
_ , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "secret" , "gcp-auth" , "-n" , "new-namespace" ) )
if err != nil {
2022-12-07 23:05:31 +00:00
err = fmt . Errorf ( "%w: gcp-auth container logs: %v" , err , logsAsError ( ) )
2022-12-01 22:42:38 +00:00
}
2022-12-05 16:34:40 +00:00
return err
2022-12-01 22:42:38 +00:00
}
2022-12-05 16:34:40 +00:00
if err := retry . Expo ( getSecret , Seconds ( 2 ) , Minutes ( 1 ) ) ; err != nil {
2022-12-01 22:42:38 +00:00
t . Errorf ( "failed to get secret: %v" , err )
2022-11-30 23:50:32 +00:00
}
}
2021-04-16 20:42:41 +00:00
// validateGCPAuthAddon tests the GCP Auth addon with either phony or real credentials and makes sure the files are mounted into pods correctly
2020-10-08 20:25:19 +00:00
func validateGCPAuthAddon ( ctx context . Context , t * testing . T , profile string ) {
2024-10-01 17:43:23 +00:00
defer func ( ) {
disableGCPAuth := func ( ) error {
disableAddon ( t , "gcp-auth" , profile )
return nil
}
if err := retry . Expo ( disableGCPAuth , Minutes ( 2 ) , Minutes ( 10 ) , 5 ) ; err != nil {
t . Errorf ( "failed to disable GCP auth addon: %v" , err )
}
} ( )
2020-10-08 20:25:19 +00:00
defer PostMortemLogs ( t , profile )
2022-12-01 22:24:41 +00:00
t . Run ( "Namespaces" , func ( t * testing . T ) {
validateGCPAuthNamespaces ( ctx , t , profile )
} )
2022-11-30 23:50:32 +00:00
2024-10-02 17:29:30 +00:00
t . Run ( "PullSecret" , func ( t * testing . T ) {
// schedule a pod to check environment variables
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "-f" , filepath . Join ( * testdataDir , "busybox.yaml" ) ) )
if err != nil {
t . Fatalf ( "%s failed: %v" , rr . Command ( ) , err )
}
2022-06-21 20:39:50 +00:00
2024-10-02 17:29:30 +00:00
serviceAccountName := "gcp-auth-test"
// create a dummy service account so we know the pull secret got added
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "sa" , serviceAccountName ) )
2021-03-24 23:52:02 +00:00
if err != nil {
2024-10-02 17:29:30 +00:00
t . Fatalf ( "%s failed: %v" , rr . Command ( ) , err )
2021-03-24 23:52:02 +00:00
}
2020-10-08 20:25:19 +00:00
2024-10-02 17:29:30 +00:00
// 8 minutes, because 4 is not enough for images to pull in all cases.
names , err := PodWait ( ctx , t , profile , "default" , "integration-test=busybox" , Minutes ( 8 ) )
2021-03-24 23:52:02 +00:00
if err != nil {
2024-10-02 17:29:30 +00:00
t . Fatalf ( "wait: %v" , err )
2021-03-24 23:52:02 +00:00
}
2024-10-02 17:29:30 +00:00
// Use this pod to confirm that the env vars are set correctly
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "exec" , names [ 0 ] , "--" , "/bin/sh" , "-c" , "printenv GOOGLE_APPLICATION_CREDENTIALS" ) )
if err != nil {
t . Fatalf ( "printenv creds: %v" , err )
2021-03-24 23:52:02 +00:00
}
2020-10-08 20:25:19 +00:00
2024-10-02 17:29:30 +00:00
got := strings . TrimSpace ( rr . Stdout . String ( ) )
expected := "/google-app-creds.json"
if got != expected {
t . Errorf ( "'printenv GOOGLE_APPLICATION_CREDENTIALS' returned %s, expected %s" , got , expected )
2021-03-24 23:52:02 +00:00
}
2020-10-08 20:25:19 +00:00
2024-10-02 17:29:30 +00:00
// Now check the service account and make sure the "gcp-auth" image pull secret is present
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "describe" , "sa" , serviceAccountName ) )
if err != nil {
t . Fatalf ( "%s failed: %v" , rr . Command ( ) , err )
}
2020-10-08 20:25:19 +00:00
2024-10-02 17:29:30 +00:00
expectedPullSecret := "gcp-auth"
re := regexp . MustCompile ( ` .*Image pull secrets:.* ` )
secrets := re . FindString ( rr . Stdout . String ( ) )
if ! strings . Contains ( secrets , expectedPullSecret ) {
t . Errorf ( "Unexpected image pull secrets. expected %s, got %s" , expectedPullSecret , secrets )
}
2021-10-26 20:47:55 +00:00
2024-10-02 17:29:30 +00:00
if ! detect . IsOnGCE ( ) || detect . IsCloudShell ( ) {
// Make sure the file contents are correct
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "exec" , names [ 0 ] , "--" , "/bin/sh" , "-c" , "cat /google-app-creds.json" ) )
if err != nil {
t . Fatalf ( "cat creds: %v" , err )
}
2020-10-08 20:25:19 +00:00
2024-10-02 17:29:30 +00:00
var gotJSON map [ string ] string
err = json . Unmarshal ( bytes . TrimSpace ( rr . Stdout . Bytes ( ) ) , & gotJSON )
if err != nil {
t . Fatalf ( "unmarshal json: %v" , err )
}
expectedJSON := map [ string ] string {
"client_id" : "haha" ,
"client_secret" : "nice_try" ,
"quota_project_id" : "this_is_fake" ,
"refresh_token" : "maybe_next_time" ,
"type" : "authorized_user" ,
}
2023-01-04 21:02:48 +00:00
2024-10-02 17:29:30 +00:00
if ! reflect . DeepEqual ( gotJSON , expectedJSON ) {
t . Fatalf ( "unexpected creds file: got %v, expected %v" , gotJSON , expectedJSON )
}
2021-10-22 00:04:20 +00:00
}
2024-10-02 17:29:30 +00:00
// Check the GOOGLE_CLOUD_PROJECT env var as well
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "exec" , names [ 0 ] , "--" , "/bin/sh" , "-c" , "printenv GOOGLE_CLOUD_PROJECT" ) )
2021-03-24 23:18:28 +00:00
if err != nil {
t . Fatalf ( "print env project: %v" , err )
}
2024-10-02 17:29:30 +00:00
got = strings . TrimSpace ( rr . Stdout . String ( ) )
expected = "this_is_fake"
2021-08-03 18:48:20 +00:00
2024-10-02 17:29:30 +00:00
if got != expected {
t . Errorf ( "'printenv GOOGLE_CLOUD_PROJECT' returned %s, expected %s" , got , expected )
2021-08-03 18:48:20 +00:00
}
2024-10-02 17:29:30 +00:00
// If we're on GCE, we have proper credentials and can test the registry secrets with an artifact registry image
if detect . IsOnGCE ( ) && ! detect . IsCloudShell ( ) && ! VMDriver ( ) {
t . Skip ( "skipping GCPAuth addon test until 'Permission \"artifactregistry.repositories.downloadArtifacts\" denied on resource \"projects/k8s-minikube/locations/us/repositories/test-artifacts\" (or it may not exist)' issue is resolved" )
// "Setting the environment variable MOCK_GOOGLE_TOKEN to true will prevent using the google application credentials to fetch the token used for the image pull secret. Instead the token will be mocked."
// ref: https://github.com/GoogleContainerTools/gcp-auth-webhook#gcp-auth-webhook
os . Unsetenv ( "MOCK_GOOGLE_TOKEN" )
// re-set MOCK_GOOGLE_TOKEN once we're done
defer os . Setenv ( "MOCK_GOOGLE_TOKEN" , "true" )
os . Unsetenv ( "GOOGLE_APPLICATION_CREDENTIALS" )
os . Unsetenv ( "GOOGLE_CLOUD_PROJECT" )
args := [ ] string { "-p" , profile , "addons" , "enable" , "gcp-auth" }
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , args ... ) )
if err != nil {
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
} else if ! strings . Contains ( rr . Output ( ) , "It seems that you are running in GCE" ) {
t . Errorf ( "Unexpected error message: %v" , rr . Output ( ) )
}
_ , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "apply" , "-f" , filepath . Join ( * testdataDir , "private-image.yaml" ) ) )
if err != nil {
t . Fatalf ( "print env project: %v" , err )
}
// Make sure the pod is up and running, which means we successfully pulled the private image down
// 8 minutes, because 4 is not enough for images to pull in all cases.
_ , err = PodWait ( ctx , t , profile , "default" , "integration-test=private-image" , Minutes ( 8 ) )
if err != nil {
t . Fatalf ( "wait for private image: %v" , err )
}
// Try it with a European mirror as well
_ , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "apply" , "-f" , filepath . Join ( * testdataDir , "private-image-eu.yaml" ) ) )
if err != nil {
t . Fatalf ( "print env project: %v" , err )
}
_ , err = PodWait ( ctx , t , profile , "default" , "integration-test=private-image-eu" , Minutes ( 8 ) )
if err != nil {
t . Fatalf ( "wait for private image: %v" , err )
}
2021-03-24 23:18:28 +00:00
}
2024-10-02 17:29:30 +00:00
} )
2020-10-08 20:25:19 +00:00
}
2022-06-06 07:17:55 +00:00
func validateHeadlampAddon ( ctx context . Context , t * testing . T , profile string ) {
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "headlamp" , profile )
2022-06-06 07:17:55 +00:00
defer PostMortemLogs ( t , profile )
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "addons" , "enable" , "headlamp" , "-p" , profile , "--alsologtostderr" , "-v=1" ) )
if err != nil {
t . Fatalf ( "failed to enable headlamp addon: args: %q: %v" , rr . Command ( ) , err )
}
if _ , err := PodWait ( ctx , t , profile , "headlamp" , "app.kubernetes.io/name=headlamp" , Minutes ( 8 ) ) ; err != nil {
t . Fatalf ( "failed waiting for headlamp pod: %v" , err )
}
}
2022-10-26 17:27:47 +00:00
2023-02-16 17:11:43 +00:00
// validateInspektorGadgetAddon tests the inspektor-gadget addon by ensuring the pod has come up and addon disables
func validateInspektorGadgetAddon ( ctx context . Context , t * testing . T , profile string ) {
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "inspektor-gadget" , profile )
2023-02-16 17:11:43 +00:00
defer PostMortemLogs ( t , profile )
if _ , err := PodWait ( ctx , t , profile , "gadget" , "k8s-app=gadget" , Minutes ( 8 ) ) ; err != nil {
t . Fatalf ( "failed waiting for inspektor-gadget pod: %v" , err )
}
}
2022-10-26 17:27:47 +00:00
// validateCloudSpannerAddon tests the cloud-spanner addon by ensuring the deployment and pod come up and addon disables
func validateCloudSpannerAddon ( ctx context . Context , t * testing . T , profile string ) {
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "cloud-spanner" , profile )
2022-10-26 17:27:47 +00:00
defer PostMortemLogs ( t , profile )
client , err := kapi . Client ( profile )
if err != nil {
t . Fatalf ( "failed to get Kubernetes client for %s: %v" , profile , err )
}
if err := kapi . WaitForDeploymentToStabilize ( client , "default" , "cloud-spanner-emulator" , Minutes ( 6 ) ) ; err != nil {
t . Errorf ( "failed waiting for cloud-spanner-emulator deployment to stabilize: %v" , err )
}
if _ , err := PodWait ( ctx , t , profile , "default" , "app=cloud-spanner-emulator" , Minutes ( 6 ) ) ; err != nil {
t . Errorf ( "failed waiting for app=cloud-spanner-emulator pod: %v" , err )
}
}
2023-01-14 12:13:56 +00:00
2024-04-08 14:47:51 +00:00
// validateVolcanoAddon tests the Volcano addon, makes sure the Volcano is installed into cluster.
func validateVolcanoAddon ( ctx context . Context , t * testing . T , profile string ) {
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "volcano" , profile )
2024-04-08 14:47:51 +00:00
defer PostMortemLogs ( t , profile )
2024-04-20 15:52:03 +00:00
if ContainerRuntime ( ) == "crio" {
t . Skipf ( "skipping: crio not supported" )
}
2024-04-08 14:47:51 +00:00
volcanoNamespace := "volcano-system"
client , err := kapi . Client ( profile )
if err != nil {
t . Fatalf ( "failed to get Kubernetes client for %s: %v" , profile , err )
}
// Wait for the volcano component installation to complete
start := time . Now ( )
var wg sync . WaitGroup
wg . Add ( 3 )
go func ( ) {
if err := kapi . WaitForDeploymentToStabilize ( client , volcanoNamespace , "volcano-scheduler" , Minutes ( 6 ) ) ; err != nil {
t . Errorf ( "failed waiting for volcano-scheduler deployment to stabilize: %v" , err )
} else {
t . Logf ( "volcano-scheduler stabilized in %s" , time . Since ( start ) )
}
wg . Done ( )
} ( )
go func ( ) {
if err := kapi . WaitForDeploymentToStabilize ( client , volcanoNamespace , "volcano-admission" , Minutes ( 6 ) ) ; err != nil {
t . Errorf ( "failed waiting for volcano-admission deployment to stabilize: %v" , err )
} else {
t . Logf ( "volcano-admission stabilized in %s" , time . Since ( start ) )
}
wg . Done ( )
} ( )
go func ( ) {
2024-06-16 16:33:21 +00:00
if err := kapi . WaitForDeploymentToStabilize ( client , volcanoNamespace , "volcano-controllers" , Minutes ( 6 ) ) ; err != nil {
2024-04-08 14:47:51 +00:00
t . Errorf ( "failed waiting for volcano-controller deployment to stabilize: %v" , err )
} else {
t . Logf ( "volcano-controller stabilized in %s" , time . Since ( start ) )
}
wg . Done ( )
} ( )
wg . Wait ( )
if _ , err := PodWait ( ctx , t , profile , volcanoNamespace , "app=volcano-scheduler" , Minutes ( 6 ) ) ; err != nil {
t . Fatalf ( "failed waiting for app=volcano-scheduler pod: %v" , err )
}
if _ , err := PodWait ( ctx , t , profile , volcanoNamespace , "app=volcano-admission" , Minutes ( 6 ) ) ; err != nil {
t . Fatalf ( "failed waiting for app=volcano-admission pod: %v" , err )
}
if _ , err := PodWait ( ctx , t , profile , volcanoNamespace , "app=volcano-controller" , Minutes ( 6 ) ) ; err != nil {
t . Fatalf ( "failed waiting for app=volcano-controller pod: %v" , err )
}
// When the volcano deployment is complete, delete the volcano-admission-init job, it will affect the tests
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "delete" , "-n" , volcanoNamespace , "job" , "volcano-admission-init" ) )
if err != nil {
t . Logf ( "vcjob creation with %s failed: %v" , rr . Command ( ) , err )
}
// Create a vcjob
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "-f" , filepath . Join ( * testdataDir , "vcjob.yaml" ) ) )
if err != nil {
t . Logf ( "vcjob creation with %s failed: %v" , rr . Command ( ) , err )
}
want := "test-job"
checkVolcano := func ( ) error {
// check the vcjob
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "vcjob" , "-n" , "my-volcano" ) )
if err != nil {
return err
}
if rr . Stderr . String ( ) != "" {
t . Logf ( "%v: unexpected stderr: %s" , rr . Command ( ) , rr . Stderr )
}
if ! strings . Contains ( rr . Stdout . String ( ) , want ) {
return fmt . Errorf ( "%v stdout = %q, want %q" , rr . Command ( ) , rr . Stdout , want )
}
return nil
}
if err := retry . Expo ( checkVolcano , time . Second * 3 , Minutes ( 2 ) ) ; err != nil {
t . Errorf ( "failed checking volcano: %v" , err . Error ( ) )
}
// also ensure the job is actually running
if _ , err := PodWait ( ctx , t , profile , "my-volcano" , "volcano.sh/job-name=test-job" , Minutes ( 3 ) ) ; err != nil {
t . Fatalf ( "failed waiting for test-local-path pod: %v" , err )
}
}
2023-01-14 12:13:56 +00:00
// validateLocalPathAddon tests the functionality of the storage-provisioner-rancher addon
func validateLocalPathAddon ( ctx context . Context , t * testing . T , profile string ) {
if NoneDriver ( ) {
t . Skipf ( "skip local-path test on none driver" )
}
2024-10-01 17:43:23 +00:00
defer disableAddon ( t , "storage-provisioner-rancher" , profile )
2024-10-09 18:26:27 +00:00
defer PostMortemLogs ( t , profile )
2023-01-14 12:13:56 +00:00
// Create a test PVC
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "apply" , "-f" , filepath . Join ( * testdataDir , "storage-provisioner-rancher" , "pvc.yaml" ) ) )
if err != nil {
t . Fatalf ( "kubectl apply pvc.yaml failed: args %q: %v" , rr . Command ( ) , err )
}
// Deploy a simple pod with PVC
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "apply" , "-f" , filepath . Join ( * testdataDir , "storage-provisioner-rancher" , "pod.yaml" ) ) )
if err != nil {
t . Fatalf ( "kubectl apply pod.yaml failed: args %q: %v" , rr . Command ( ) , err )
}
if err := PVCWait ( ctx , t , profile , "default" , "test-pvc" , Minutes ( 5 ) ) ; err != nil {
t . Fatalf ( "failed waiting for PVC test-pvc: %v" , err )
}
if _ , err := PodWait ( ctx , t , profile , "default" , "run=test-local-path" , Minutes ( 3 ) ) ; err != nil {
t . Fatalf ( "failed waiting for test-local-path pod: %v" , err )
}
// Get info about PVC
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "pvc" , "test-pvc" , "-o=json" ) )
if err != nil {
t . Fatalf ( "kubectl get pvc with %s failed: %v" , rr . Command ( ) , err )
}
pvc := core . PersistentVolumeClaim { }
if err := json . NewDecoder ( bytes . NewReader ( rr . Stdout . Bytes ( ) ) ) . Decode ( & pvc ) ; err != nil {
t . Fatalf ( "failed decoding json to pvc: %v" , err )
}
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , fmt . Sprintf ( "cat /opt/local-path-provisioner/%s_default_test-pvc/file1" , pvc . Spec . VolumeName ) ) )
if err != nil {
t . Fatalf ( "ssh error: %v" , err )
}
got := rr . Stdout . String ( )
want := "local-path-provisioner"
if ! strings . Contains ( got , want ) {
t . Fatalf ( "%v stdout = %q, want %q" , rr . Command ( ) , got , want )
}
// Cleanup
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "delete" , "pod" , "test-local-path" ) )
if err != nil {
t . Logf ( "cleanup with %s failed: %v" , rr . Command ( ) , err )
}
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "delete" , "pvc" , "test-pvc" ) )
if err != nil {
t . Logf ( "cleanup with %s failed: %v" , rr . Command ( ) , err )
}
}
2023-09-29 20:03:13 +00:00
// validateEnablingAddonOnNonExistingCluster tests enabling an addon on a non-existing cluster
func validateEnablingAddonOnNonExistingCluster ( ctx context . Context , t * testing . T , profile string ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "addons" , "enable" , "dashboard" , "-p" , profile ) )
if err == nil {
t . Fatalf ( "enabling addon succeeded when it shouldn't have: %s" , rr . Output ( ) )
}
2023-10-03 16:29:07 +00:00
if ! strings . Contains ( rr . Output ( ) , "To start a cluster, run" ) {
2023-09-29 20:03:13 +00:00
t . Fatalf ( "unexpected error was returned: %v" , err )
}
}
// validateDisablingAddonOnNonExistingCluster tests disabling an addon on a non-existing cluster
func validateDisablingAddonOnNonExistingCluster ( ctx context . Context , t * testing . T , profile string ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "addons" , "disable" , "dashboard" , "-p" , profile ) )
if err == nil {
t . Fatalf ( "disabling addon succeeded when it shouldn't have: %s" , rr . Output ( ) )
}
2023-10-03 16:29:07 +00:00
if ! strings . Contains ( rr . Output ( ) , "To start a cluster, run" ) {
2023-09-29 20:03:13 +00:00
t . Fatalf ( "unexpected error was returned: %v" , err )
}
}
2023-09-25 22:16:15 +00:00
// validateNvidiaDevicePlugin tests the nvidia-device-plugin addon by ensuring the pod comes up and the addon disables
func validateNvidiaDevicePlugin ( ctx context . Context , t * testing . T , profile string ) {
2024-10-09 18:26:27 +00:00
defer disableAddon ( t , "nvidia-device-plugin" , profile )
2023-09-25 22:16:15 +00:00
defer PostMortemLogs ( t , profile )
2023-09-26 21:52:47 +00:00
if _ , err := PodWait ( ctx , t , profile , "kube-system" , "name=nvidia-device-plugin-ds" , Minutes ( 6 ) ) ; err != nil {
2023-09-25 22:16:15 +00:00
t . Fatalf ( "failed waiting for nvidia-device-plugin-ds pod: %v" , err )
}
}
2023-12-12 18:30:09 +00:00
2024-10-11 20:36:06 +00:00
// validateAmdGpuDevicePlugin tests the amd-gpu-device-plugin addon by ensuring the pod comes up and the addon disables
func validateAmdGpuDevicePlugin ( ctx context . Context , t * testing . T , profile string ) {
if ! ( DockerDriver ( ) && amd64Platform ( ) ) {
t . Skipf ( "skip amd gpu test on all but docker driver and amd64 platform" )
}
defer disableAddon ( t , "amd-gpu-device-plugin" , profile )
defer PostMortemLogs ( t , profile )
if _ , err := PodWait ( ctx , t , profile , "kube-system" , "name=amd-gpu-device-plugin" , Minutes ( 6 ) ) ; err != nil {
t . Fatalf ( "failed waiting for amd-gpu-device-plugin pod: %v" , err )
}
}
2023-12-12 18:30:09 +00:00
func validateYakdAddon ( ctx context . Context , t * testing . T , profile string ) {
2024-10-09 18:26:27 +00:00
defer disableAddon ( t , "yakd" , profile )
2023-12-12 18:30:09 +00:00
defer PostMortemLogs ( t , profile )
if _ , err := PodWait ( ctx , t , profile , "yakd-dashboard" , "app.kubernetes.io/name=yakd-dashboard" , Minutes ( 2 ) ) ; err != nil {
t . Fatalf ( "failed waiting for YAKD - Kubernetes Dashboard pod: %v" , err )
}
}
2024-10-01 17:43:23 +00:00
func disableAddon ( t * testing . T , addon , profile string ) {
rr , err := Run ( t , exec . Command ( Target ( ) , "-p" , profile , "addons" , "disable" , addon , "--alsologtostderr" , "-v=1" ) )
if err != nil {
t . Errorf ( "failed to disable %s addon: args %q: %v" , addon , rr . Command ( ) , err )
}
}