github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/multicluster/examples/sock-shop/sock_shop_example_utils.go (about)

     1  // Copyright (c) 2021, 2022, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package sock_shop
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  
    10  	"github.com/verrazzano/verrazzano/pkg/k8s/resource"
    11  
    12  	oamcore "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
    13  	clustersv1alpha1 "github.com/verrazzano/verrazzano/application-operator/apis/clusters/v1alpha1"
    14  	"github.com/verrazzano/verrazzano/pkg/k8sutil"
    15  	"github.com/verrazzano/verrazzano/tests/e2e/pkg"
    16  	"k8s.io/apimachinery/pkg/api/errors"
    17  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    18  	"k8s.io/apimachinery/pkg/runtime/schema"
    19  	"k8s.io/client-go/dynamic"
    20  )
    21  
    22  const (
    23  	multiclusterNamespace = "verrazzano-mc"
    24  	appConfigName         = "sockshop-appconf"
    25  )
    26  
    27  var (
    28  	expectedCompsSockShop = []string{
    29  		"carts-component",
    30  		"catalog-component",
    31  		"orders-component",
    32  		"payment-component",
    33  		"shipping-component",
    34  		"users-component"}
    35  	expectedPodsSockShop = []string{
    36  		"carts-coh",
    37  		"catalog-coh",
    38  		"orders-coh",
    39  		"payment-coh",
    40  		"shipping-coh",
    41  		"users-coh"}
    42  )
    43  
    44  // DeploySockShopProject deploys the sock-shop example's VerrazzanoProject to the cluster with the given kubeConfigPath
    45  func DeploySockShopProject(kubeconfigPath string, sourceDir string) error {
    46  	file, err := pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/verrazzano-project.yaml", sourceDir))
    47  	if err != nil {
    48  		return err
    49  	}
    50  	if err := resource.CreateOrUpdateResourceFromFileInCluster(file, kubeconfigPath); err != nil {
    51  		return fmt.Errorf("failed to create %s project resource: %v", sourceDir, err)
    52  	}
    53  	return nil
    54  }
    55  
    56  // DeploySockShopApp deploys the sock-shop example application to the cluster with the given kubeConfigPath
    57  func DeploySockShopApp(kubeconfigPath string, sourceDir string) error {
    58  	file, err := pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/sock-shop-comp.yaml", sourceDir))
    59  	if err != nil {
    60  		return err
    61  	}
    62  	if err := resource.CreateOrUpdateResourceFromFileInCluster(file, kubeconfigPath); err != nil {
    63  		return fmt.Errorf("failed to create multi-cluster %s component resources: %v", sourceDir, err)
    64  	}
    65  	file, err = pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/sock-shop-app.yaml", sourceDir))
    66  	if err != nil {
    67  		return err
    68  	}
    69  	if err := resource.CreateOrUpdateResourceFromFileInCluster(file, kubeconfigPath); err != nil {
    70  		return fmt.Errorf("failed to create multi-cluster %s application resource: %v", sourceDir, err)
    71  	}
    72  	return nil
    73  }
    74  
    75  // VerifyMCResources verifies that the MC resources are present or absent depending on whether this is an admin
    76  // cluster and whether the resources are placed in the given cluster
    77  func VerifyMCResources(kubeconfigPath string, isAdminCluster bool, placedInThisCluster bool, namespace string) bool {
    78  	// call both appConfExists and componentExists and store the results, to avoid short-circuiting
    79  	// since we should check both in all cases
    80  	mcAppConfExists := appConfExists(kubeconfigPath, namespace)
    81  
    82  	compExists := true
    83  	// check each sock-shop component in expectedCompsSockShop
    84  	for _, comp := range expectedCompsSockShop {
    85  		compExists = componentExists(kubeconfigPath, namespace, comp) && compExists
    86  	}
    87  
    88  	if isAdminCluster || placedInThisCluster {
    89  		// always expect MC resources on admin cluster - otherwise expect them only if placed here
    90  		return mcAppConfExists && compExists
    91  	} else {
    92  		// don't expect either
    93  		return !mcAppConfExists && !compExists
    94  	}
    95  }
    96  
    97  // VerifySockShopInCluster verifies that the sock-shop app resources are either present or absent
    98  // depending on whether the app is placed in this cluster
    99  func VerifySockShopInCluster(kubeconfigPath string, isAdminCluster bool, placedInThisCluster bool, projectName string, namespace string) (bool, error) {
   100  	projectExists := projectExists(kubeconfigPath, projectName)
   101  	podsRunning, err := sockShopPodsRunning(kubeconfigPath, namespace)
   102  	if err != nil {
   103  		return false, err
   104  	}
   105  
   106  	if placedInThisCluster {
   107  		return projectExists && podsRunning, nil
   108  	} else {
   109  		if isAdminCluster {
   110  			return projectExists && !podsRunning, nil
   111  		} else {
   112  			return !podsRunning && !projectExists, nil
   113  		}
   114  	}
   115  }
   116  
   117  // VerifySockShopDeleteOnAdminCluster verifies that the sock shop app resources have been deleted from the admin
   118  // cluster after the application has been deleted
   119  func VerifySockShopDeleteOnAdminCluster(kubeconfigPath string, placedInCluster bool, namespace string, projectName string) bool {
   120  	mcResDeleted := VerifyMCResourcesDeleted(kubeconfigPath, namespace, projectName)
   121  	if !placedInCluster {
   122  		return mcResDeleted
   123  	}
   124  	appDeleted, _ := VerifyAppDeleted(kubeconfigPath, namespace)
   125  
   126  	return mcResDeleted && appDeleted
   127  }
   128  
   129  // VerifySockShopDeleteOnManagedCluster verifies that the sock shop app resources have been deleted from the managed
   130  // cluster after the application has been deleted
   131  func VerifySockShopDeleteOnManagedCluster(kubeconfigPath string, namespace string, projectName string) bool {
   132  	mcResDeleted := VerifyMCResourcesDeleted(kubeconfigPath, namespace, projectName)
   133  	appDeleted, _ := VerifyAppDeleted(kubeconfigPath, namespace)
   134  
   135  	return mcResDeleted && appDeleted
   136  }
   137  
   138  // VerifyAppDeleted verifies that the workload and pods are deleted on the specified cluster
   139  func VerifyAppDeleted(kubeconfigPath string, namespace string) (bool, error) {
   140  	podsRunning, _ := sockShopPodsRunning(kubeconfigPath, namespace)
   141  
   142  	return !podsRunning, nil
   143  }
   144  
   145  // VerifyMCResourcesDeleted verifies that any resources created by the deployment are deleted on the specified cluster
   146  func VerifyMCResourcesDeleted(kubeconfigPath string, namespace string, projectName string) bool {
   147  	appConfExists := appConfExists(kubeconfigPath, namespace)
   148  	projExists := projectExists(kubeconfigPath, projectName)
   149  
   150  	compExists := true
   151  	// check each sock-shop component in expectedCompsSockShop
   152  	for _, comp := range expectedCompsSockShop {
   153  		compExists = componentExists(kubeconfigPath, namespace, comp) && compExists
   154  	}
   155  
   156  	return !appConfExists && !compExists && !projExists
   157  }
   158  
   159  // SockShopNamespaceExists SockShopExists - returns true if the sock-shop namespace exists in the given cluster
   160  func SockShopNamespaceExists(kubeconfigPath string, namespace string) bool {
   161  	_, err := pkg.GetNamespaceInCluster(namespace, kubeconfigPath)
   162  	return err == nil
   163  }
   164  
   165  // projectExists Check if sockshop project exists
   166  func projectExists(kubeconfigPath string, projectName string) bool {
   167  	gvr := schema.GroupVersionResource{
   168  		Group:    clustersv1alpha1.SchemeGroupVersion.Group,
   169  		Version:  clustersv1alpha1.SchemeGroupVersion.Version,
   170  		Resource: "verrazzanoprojects",
   171  	}
   172  	return resourceExists(gvr, multiclusterNamespace, projectName, kubeconfigPath)
   173  }
   174  
   175  // appConfExists Check if app config exists
   176  func appConfExists(kubeconfigPath string, namespace string) bool {
   177  	gvr := schema.GroupVersionResource{
   178  		Group:    clustersv1alpha1.SchemeGroupVersion.Group,
   179  		Version:  clustersv1alpha1.SchemeGroupVersion.Version,
   180  		Resource: "multiclusterapplicationconfigurations",
   181  	}
   182  	return resourceExists(gvr, namespace, appConfigName, kubeconfigPath)
   183  }
   184  
   185  // componentExists Check if individual component exists
   186  func componentExists(kubeconfigPath string, namespace string, component string) bool {
   187  	gvr := schema.GroupVersionResource{
   188  		Group:    oamcore.Group,
   189  		Version:  oamcore.Version,
   190  		Resource: "components",
   191  	}
   192  	return resourceExists(gvr, namespace, component, kubeconfigPath)
   193  }
   194  
   195  // resourceExists Check if given resource exists
   196  func resourceExists(gvr schema.GroupVersionResource, ns string, name string, kubeconfigPath string) bool {
   197  	config, err := k8sutil.GetKubeConfigGivenPath(kubeconfigPath)
   198  	if err != nil {
   199  		pkg.Log(pkg.Error, fmt.Sprintf("Could not get kube config: %v\n", err))
   200  		return false
   201  	}
   202  	client, err := dynamic.NewForConfig(config)
   203  	if err != nil {
   204  		pkg.Log(pkg.Error, fmt.Sprintf("Could not create dynamic client: %v\n", err))
   205  		return false
   206  	}
   207  
   208  	u, err := client.Resource(gvr).Namespace(ns).Get(context.TODO(), name, v1.GetOptions{})
   209  
   210  	if err != nil {
   211  		if errors.IsNotFound(err) {
   212  			return false
   213  		}
   214  		pkg.Log(pkg.Error, fmt.Sprintf("Could not retrieve resource %s: %v\n", gvr.String(), err))
   215  		return false
   216  	}
   217  	return u != nil
   218  }
   219  
   220  // sockShopPodsRunning Check if expected pods are running on a given cluster
   221  func sockShopPodsRunning(kubeconfigPath string, namespace string) (bool, error) {
   222  	result, err := pkg.PodsRunningInCluster(namespace, expectedPodsSockShop, kubeconfigPath)
   223  	if err != nil {
   224  		pkg.Log(pkg.Error, fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", namespace, err))
   225  		return false, err
   226  	}
   227  	return result, nil
   228  }