github.com/solo-io/service-mesh-hub@v0.9.2/test/e2e/env.go (about)

     1  package e2e
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"strconv"
     9  	"strings"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/solo-io/skv2/codegen/util"
    14  
    15  	"k8s.io/client-go/rest"
    16  
    17  	"github.com/solo-io/service-mesh-hub/test/kubectl"
    18  
    19  	. "github.com/onsi/ginkgo"
    20  	. "github.com/onsi/gomega"
    21  	istionetworkingv1alpha3 "github.com/solo-io/external-apis/pkg/api/istio/networking.istio.io/v1alpha3"
    22  	kubernetes_core "github.com/solo-io/external-apis/pkg/api/k8s/core/v1"
    23  	discoveryv1alpha2 "github.com/solo-io/service-mesh-hub/pkg/api/discovery.smh.solo.io/v1alpha2"
    24  	networkingv1alpha2 "github.com/solo-io/service-mesh-hub/pkg/api/networking.smh.solo.io/v1alpha2"
    25  	corev1 "k8s.io/api/core/v1"
    26  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/client-go/kubernetes"
    28  	"k8s.io/client-go/tools/clientcmd"
    29  )
    30  
    31  const (
    32  	mgmtContext   = "kind-mgmt-cluster"
    33  	remoteContext = "kind-remote-cluster"
    34  )
    35  
    36  type Env struct {
    37  	Management KubeContext
    38  	Remote     KubeContext
    39  }
    40  
    41  func (e Env) DumpState() {
    42  	dumpState()
    43  }
    44  
    45  func newEnv(mgmt, remote string) Env {
    46  	return Env{
    47  		Management: NewKubeContext(mgmt),
    48  		Remote:     NewKubeContext(remote),
    49  	}
    50  }
    51  
    52  type SingleClusterEnv struct {
    53  	Management KubeContext
    54  }
    55  
    56  func (s SingleClusterEnv) DumpState() {
    57  	dumpState()
    58  }
    59  
    60  func newSingleClusterEnv(mgmt string) SingleClusterEnv {
    61  	return SingleClusterEnv{
    62  		Management: NewKubeContext(mgmt),
    63  	}
    64  }
    65  
    66  type KubeContext struct {
    67  	Context               string
    68  	Config                *rest.Config
    69  	Clientset             *kubernetes.Clientset
    70  	TrafficPolicyClient   networkingv1alpha2.TrafficPolicyClient
    71  	MeshClient            discoveryv1alpha2.MeshClient
    72  	SecretClient          kubernetes_core.SecretClient
    73  	VirtualMeshClient     networkingv1alpha2.VirtualMeshClient
    74  	DestinationRuleClient istionetworkingv1alpha3.DestinationRuleClient
    75  	VirtualServiceClient  istionetworkingv1alpha3.VirtualServiceClient
    76  }
    77  
    78  // If kubecontext is empty string, use current context.
    79  func NewKubeContext(kubecontext string) KubeContext {
    80  	cfg, err := clientcmd.NewDefaultClientConfigLoadingRules().Load()
    81  	Expect(err).NotTo(HaveOccurred())
    82  
    83  	config := clientcmd.NewNonInteractiveClientConfig(*cfg, kubecontext, &clientcmd.ConfigOverrides{}, nil)
    84  	restcfg, err := config.ClientConfig()
    85  	Expect(err).NotTo(HaveOccurred())
    86  
    87  	clientset, err := kubernetes.NewForConfig(restcfg)
    88  	Expect(err).NotTo(HaveOccurred())
    89  
    90  	kubeCoreClientset, err := kubernetes_core.NewClientsetFromConfig(restcfg)
    91  	Expect(err).NotTo(HaveOccurred())
    92  
    93  	networkingClientset, err := networkingv1alpha2.NewClientsetFromConfig(restcfg)
    94  	Expect(err).NotTo(HaveOccurred())
    95  
    96  	discoveryClientset, err := discoveryv1alpha2.NewClientsetFromConfig(restcfg)
    97  	Expect(err).NotTo(HaveOccurred())
    98  
    99  	istioNetworkingClientset, err := istionetworkingv1alpha3.NewClientsetFromConfig(restcfg)
   100  	Expect(err).NotTo(HaveOccurred())
   101  
   102  	return KubeContext{
   103  		Context:               kubecontext,
   104  		Config:                restcfg,
   105  		Clientset:             clientset,
   106  		TrafficPolicyClient:   networkingClientset.TrafficPolicies(),
   107  		VirtualMeshClient:     networkingClientset.VirtualMeshes(),
   108  		MeshClient:            discoveryClientset.Meshes(),
   109  		SecretClient:          kubeCoreClientset.Secrets(),
   110  		DestinationRuleClient: istioNetworkingClientset.DestinationRules(),
   111  		VirtualServiceClient:  istioNetworkingClientset.VirtualServices(),
   112  	}
   113  }
   114  
   115  func (k *KubeContext) Curl(ctx context.Context, ns, fromDeployment, fromContainer, url string) string {
   116  	return kubectl.Curl(ctx, k.Context, ns, fromDeployment, fromContainer, url)
   117  }
   118  
   119  func (k *KubeContext) WaitForRollout(ctx context.Context, ns, deployment string) {
   120  	kubectl.WaitForRollout(ctx, k.Context, ns, deployment)
   121  }
   122  
   123  func (k *KubeContext) DeployBookInfo(ctx context.Context, ns string) {
   124  	kubectl.DeployBookInfo(ctx, k.Context, ns)
   125  }
   126  
   127  func (k *KubeContext) CreateNamespace(ctx context.Context, ns string) {
   128  	kubectl.CreateNamespace(ctx, k.Context, ns)
   129  }
   130  
   131  func (k *KubeContext) DeleteNamespace(ctx context.Context, ns string) {
   132  	kubectl.DeleteNamespace(ctx, k.Context, ns)
   133  }
   134  
   135  func (k *KubeContext) LabelNamespace(ctx context.Context, ns, label string) {
   136  	kubectl.LabelNamespace(ctx, k.Context, ns, label)
   137  }
   138  
   139  func (k *KubeContext) SetDeploymentEnvVars(
   140  	ctx context.Context,
   141  	ns string,
   142  	deploymentName string,
   143  	containerName string,
   144  	envVars map[string]string) {
   145  	kubectl.SetDeploymentEnvVars(ctx, k.Context, ns, deploymentName, containerName, envVars)
   146  }
   147  
   148  // Modify the deployment's container entrypoint command to "sleep 20h" to disable the application.
   149  func (k *KubeContext) DisableContainer(
   150  	ctx context.Context,
   151  	ns string,
   152  	deploymentName string,
   153  	containerName string,
   154  ) {
   155  	kubectl.DisableContainer(ctx, k.Context, ns, deploymentName, containerName)
   156  }
   157  
   158  // Remove the sleep command to re-enable the application container.
   159  func (k *KubeContext) EnableContainer(
   160  	ctx context.Context,
   161  	ns string,
   162  	deploymentName string,
   163  ) {
   164  	kubectl.EnableContainer(ctx, k.Context, ns, deploymentName)
   165  }
   166  
   167  type Pod struct {
   168  	corev1.Pod
   169  	Cluster *KubeContext
   170  }
   171  
   172  func (p *Pod) Curl(ctx context.Context, args ...string) string {
   173  	return kubectl.CurlWithEphemeralPod(ctx, p.Cluster.Context, p.Namespace, p.Name, args...)
   174  }
   175  
   176  func (k *KubeContext) GetPod(ctx context.Context, ns, app string) *Pod {
   177  	pl, err := k.Clientset.CoreV1().Pods(ns).List(ctx, v1.ListOptions{LabelSelector: "app=" + app})
   178  	Expect(err).NotTo(HaveOccurred())
   179  	Expect(pl.Items).NotTo(BeEmpty())
   180  
   181  	return &Pod{
   182  		Pod:     pl.Items[0],
   183  		Cluster: k,
   184  	}
   185  }
   186  
   187  var env Env
   188  var envOnce sync.Once
   189  
   190  func StartEnvOnce(ctx context.Context) Env {
   191  	envOnce.Do(func() {
   192  		env = StartEnv(ctx)
   193  	})
   194  
   195  	return env
   196  }
   197  
   198  func GetEnv() Env {
   199  	return env
   200  }
   201  
   202  func ClearEnv(ctx context.Context) error {
   203  	if useExisting := os.Getenv("USE_EXISTING"); useExisting == "1" {
   204  		// dont clear existing env
   205  		return nil
   206  	}
   207  	cmd := exec.CommandContext(ctx, "./ci/setup-kind.sh", "cleanup", strconv.Itoa(GinkgoParallelNode()))
   208  	cmd.Stdout = GinkgoWriter
   209  	cmd.Stderr = GinkgoWriter
   210  	return cmd.Run()
   211  }
   212  
   213  func StartEnv(ctx context.Context) Env {
   214  
   215  	if useExisting := os.Getenv("USE_EXISTING"); useExisting == "1" {
   216  		mgmt := "kind-mgmt-cluster"
   217  		remote := "kind-remote-cluster"
   218  		if fields := strings.Split(useExisting, ","); len(fields) == 2 {
   219  			mgmt = fields[0]
   220  			remote = fields[1]
   221  		}
   222  		return newEnv(mgmt, remote)
   223  	}
   224  
   225  	// change to repo root dir
   226  	err := os.Chdir(filepath.Join(util.MustGetThisDir(), "..", ".."))
   227  	Expect(err).NotTo(HaveOccurred())
   228  
   229  	// get absolute path to setup script so this function can be called from any working directory)
   230  	cmd := exec.CommandContext(ctx, "./ci/setup-kind.sh", strconv.Itoa(GinkgoParallelNode()))
   231  	cmd.Stdout = GinkgoWriter
   232  	cmd.Stderr = GinkgoWriter
   233  
   234  	err = cmd.Run()
   235  	if err != nil {
   236  		dumpState()
   237  	}
   238  	Expect(err).NotTo(HaveOccurred())
   239  
   240  	return newEnv(mgmtContext, remoteContext)
   241  }
   242  
   243  var (
   244  	singleClusterEnv     SingleClusterEnv
   245  	singleClusterEnvOnce sync.Once
   246  )
   247  
   248  func StartSingleClusterEnvOnce(ctx context.Context) SingleClusterEnv {
   249  	singleClusterEnvOnce.Do(func() {
   250  		singleClusterEnv = StartSingleClusterEnv(ctx)
   251  	})
   252  
   253  	return singleClusterEnv
   254  }
   255  
   256  func GetSingleClusterEnv() SingleClusterEnv {
   257  	return singleClusterEnv
   258  }
   259  
   260  func ClearSingleClusterEnv(ctx context.Context) error {
   261  	if useExisting := os.Getenv("USE_EXISTING"); useExisting == "1" {
   262  		// dont clear existing env
   263  		return nil
   264  	}
   265  	cmd := exec.CommandContext(ctx, "./ci/setup-kind.sh", "cleanup", strconv.Itoa(GinkgoParallelNode()))
   266  	cmd.Stdout = GinkgoWriter
   267  	cmd.Stderr = GinkgoWriter
   268  	return cmd.Run()
   269  }
   270  
   271  func StartSingleClusterEnv(ctx context.Context) SingleClusterEnv {
   272  
   273  	if useExisting := os.Getenv("USE_EXISTING"); useExisting == "1" {
   274  		return newSingleClusterEnv(mgmtContext)
   275  	}
   276  
   277  	// TODO: don't hardcode osm installation here
   278  	cmd := exec.CommandContext(ctx, "./ci/setup-kind.sh", "osm")
   279  	cmd.Stdout = GinkgoWriter
   280  	cmd.Stderr = GinkgoWriter
   281  
   282  	err := cmd.Run()
   283  	if err != nil {
   284  		dumpState()
   285  	}
   286  	Expect(err).NotTo(HaveOccurred())
   287  
   288  	return newSingleClusterEnv(mgmtContext)
   289  }
   290  
   291  func dumpState() {
   292  	timeoutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
   293  	defer cancel()
   294  	dbgCmd := exec.CommandContext(timeoutCtx, "./ci/print-kind-info.sh", strconv.Itoa(GinkgoParallelNode()))
   295  	dbgCmd.Dir = "../.."
   296  	dbgCmd.Stdout = GinkgoWriter
   297  	dbgCmd.Stderr = GinkgoWriter
   298  	_ = dbgCmd.Run()
   299  }