github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/multicluster/verify-rancher/rancher_test.go (about) 1 // Copyright (c) 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 rancher_test 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 "os" 11 "regexp" 12 "time" 13 14 . "github.com/onsi/ginkgo/v2" 15 . "github.com/onsi/gomega" 16 "github.com/verrazzano/verrazzano/cluster-operator/apis/clusters/v1alpha1" 17 "github.com/verrazzano/verrazzano/cluster-operator/clientset/versioned" 18 "github.com/verrazzano/verrazzano/pkg/constants" 19 "github.com/verrazzano/verrazzano/tests/e2e/pkg" 20 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework" 21 corev1 "k8s.io/api/core/v1" 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 "k8s.io/client-go/kubernetes" 24 ) 25 26 const ( 27 waitTimeout = 5 * time.Minute 28 pollingInterval = 10 * time.Second 29 cattleSystemNamespace = "cattle-system" 30 searchTimeWindow = "1h" 31 ) 32 33 const ( 34 agentSecName = "verrazzano-cluster-agent" 35 regSecName = "verrazzano-cluster-registration" 36 ) 37 38 var t = framework.NewTestFramework("rancher_test") 39 40 var beforeSuite = t.BeforeSuiteFunc(func() {}) 41 var _ = BeforeSuite(beforeSuite) 42 var _ = t.AfterEach(func() {}) 43 44 var afterSuite = t.AfterSuiteFunc(func() {}) 45 var _ = AfterSuite(afterSuite) 46 47 var _ = t.Describe("Multi Cluster Rancher Validation", Label("f:platform-lcm.install"), func() { 48 t.It("Rancher log records do not contain any websocket bad handshake messages", func() { 49 // GIVEN existing system logs 50 // WHEN the Elasticsearch index for the cattle-system namespace is retrieved 51 // THEN it has a limited number of bad socket messages 52 adminKubeconfig := os.Getenv("ADMIN_KUBECONFIG") 53 indexName, err := pkg.GetOpenSearchSystemIndexWithKC(cattleSystemNamespace, adminKubeconfig) 54 Expect(err).ShouldNot(HaveOccurred()) 55 Eventually(func() bool { 56 return pkg.LogIndexFound(indexName) 57 }, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find Elasticsearch index cattle-system") 58 59 // the presence of bad socket messages does not necessarily indicate that anything is wrong with Rancher 60 // from a user's perspective, so just log the number of bad socket messages for informational purposes 61 getNumBadSocketMessages() 62 }) 63 64 t.Context("When the VMC is updated to the status of the managed cluster", func() { 65 var adminClient *versioned.Clientset 66 var managedClient *kubernetes.Clientset 67 BeforeEach(func() { 68 adminKubeconfig := os.Getenv("ADMIN_KUBECONFIG") 69 Expect(adminKubeconfig).To(Not(BeEmpty())) 70 managedKubeconfig := os.Getenv("MANAGED_KUBECONFIG") 71 Expect(managedKubeconfig).To(Not(BeEmpty())) 72 73 var err error 74 75 adminClient, err = pkg.GetClusterOperatorClientset(adminKubeconfig) 76 Expect(err).ShouldNot(HaveOccurred()) 77 managedClient, err = pkg.GetKubernetesClientsetForCluster(managedKubeconfig) 78 Expect(err).ShouldNot(HaveOccurred()) 79 }) 80 81 t.It("the VMC status is updated that objects have been pushed to the managed cluster", func() { 82 // GIVEN the VMC has been registered 83 // WHEN the VMC is retrieved 84 // THEN the VMC should have a status condition of Type: Manifest Pushed and Status: True 85 Eventually(func() error { 86 pkg.Log(pkg.Info, "Waiting for all VMC to have status condition ManifestPushed = True") 87 vmcList, err := adminClient.ClustersV1alpha1().VerrazzanoManagedClusters(constants.VerrazzanoMultiClusterNamespace).List(context.TODO(), metav1.ListOptions{}) 88 if err != nil { 89 return err 90 } 91 92 for _, vmc := range vmcList.Items { 93 statusPushedFound := false 94 for _, condition := range vmc.Status.Conditions { 95 if condition.Type == v1alpha1.ConditionManifestPushed && condition.Status == corev1.ConditionFalse { 96 return fmt.Errorf("failed to find successful condition for ManifestPushed, VMC %s/%s has condition: %s = %s", 97 vmc.Name, vmc.Namespace, condition.Type, condition.Status) 98 } 99 if condition.Type == v1alpha1.ConditionManifestPushed && condition.Status == corev1.ConditionTrue { 100 statusPushedFound = true 101 } 102 } 103 if !statusPushedFound { 104 return fmt.Errorf("failed to find expected condition, VMC %s/%s had no condition of type %s", 105 vmc.Name, vmc.Namespace, v1alpha1.ConditionManifestPushed) 106 } 107 } 108 return nil 109 }).WithPolling(pollingInterval).WithTimeout(waitTimeout).Should(BeNil()) 110 }) 111 112 t.It("the managed cluster should contain the pushed secrets", func() { 113 // GIVEN the VMC has a status of ManifestPushed = True 114 // WHEN we search for secrets on a managed cluster 115 // THEN we should see that the agent and registration secrets exist in the verrazzano-system namespace 116 Eventually(func() error { 117 adminSec, err := managedClient.CoreV1().Secrets(constants.VerrazzanoSystemNamespace).Get(context.TODO(), agentSecName, metav1.GetOptions{}) 118 if err != nil { 119 return err 120 } 121 if adminSec == nil { 122 return fmt.Errorf("get admin secret %s returned nil on the managed cluster", agentSecName) 123 } 124 125 managedSec, err := managedClient.CoreV1().Secrets(constants.VerrazzanoSystemNamespace).Get(context.TODO(), regSecName, metav1.GetOptions{}) 126 if err != nil { 127 return err 128 } 129 if managedSec == nil { 130 return fmt.Errorf("get registration secret %s returned nil on the managed cluster", regSecName) 131 } 132 return nil 133 }).WithPolling(pollingInterval).WithTimeout(waitTimeout).Should(BeNil()) 134 }) 135 }) 136 }) 137 138 func getNumBadSocketMessages() int { 139 badSocket := regexp.MustCompile(`websocket: bad handshake`) 140 numMessages := 0 141 index, err := pkg.GetOpenSearchSystemIndex(cattleSystemNamespace) 142 if err != nil { 143 pkg.Log(pkg.Error, fmt.Sprintf("Failed to get OpenSearch index: %v", err)) 144 return -1 145 } 146 147 template := 148 `{ 149 "size": 1000, 150 "sort": [{"@timestamp": {"order": "desc"}}], 151 "query": { 152 "bool": { 153 "filter" : [ 154 {"match_phrase": {"%s": "%s"}}, 155 {"range": {"@timestamp": {"gte": "now-%s"}}} 156 ] 157 } 158 } 159 }` 160 query := fmt.Sprintf(template, "kubernetes.labels.app.keyword", "rancher", searchTimeWindow) 161 resp, err := pkg.PostOpensearch(fmt.Sprintf("%s/_search", index), query) 162 if err != nil { 163 pkg.Log(pkg.Error, fmt.Sprintf("Failed to query Elasticsearch: %v", err)) 164 return -1 165 } 166 if resp.StatusCode != 200 { 167 pkg.Log(pkg.Error, fmt.Sprintf("Failed to query Elasticsearch: status=%d: body=%s", resp.StatusCode, string(resp.Body))) 168 return -1 169 } 170 var result map[string]interface{} 171 json.Unmarshal(resp.Body, &result) 172 173 hits := pkg.Jq(result, "hits", "hits") 174 if hits == nil { 175 pkg.Log(pkg.Info, "Expected to find hits in log record query results") 176 return -1 177 } 178 pkg.Log(pkg.Info, fmt.Sprintf("Found %d records", len(hits.([]interface{})))) 179 if len(hits.([]interface{})) == 0 { 180 pkg.Log(pkg.Info, "Expected log record query results to contain at least one hit") 181 return -1 182 } 183 for _, h := range hits.([]interface{}) { 184 hit := h.(map[string]interface{}) 185 src := hit["_source"].(map[string]interface{}) 186 log := src["log"].(string) 187 if badSocket.MatchString(log) { 188 numMessages++ 189 } 190 } 191 192 pkg.Log(pkg.Info, fmt.Sprintf("Found %d bad socket messages over the last hour", numMessages)) 193 return numMessages 194 }