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 }