github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/verify-infra/restapi/rancher_url_test.go (about) 1 // Copyright (c) 2021, 2023, 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 restapi_test 5 6 import ( 7 "context" 8 "fmt" 9 "reflect" 10 "strings" 11 "time" 12 13 . "github.com/onsi/ginkgo/v2" 14 . "github.com/onsi/gomega" 15 "github.com/verrazzano/verrazzano/pkg/k8sutil" 16 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/common" 17 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/rancher" 18 "github.com/verrazzano/verrazzano/tests/e2e/pkg" 19 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework/metrics" 20 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 "k8s.io/client-go/dynamic" 22 ) 23 24 const ( 25 waitTimeout = 5 * time.Minute 26 pollingInterval = 5 * time.Second 27 ) 28 29 var _ = t.Describe("rancher", Label("f:infra-lcm", 30 "f:ui.console"), func() { 31 32 t.Context("test to", func() { 33 t.It("Verify rancher access and configuration", func() { 34 if !pkg.IsManagedClusterProfile() { 35 kubeconfigPath, err := k8sutil.GetKubeConfigLocation() 36 if err != nil { 37 t.Logs.Error(fmt.Sprintf("Error getting kubeconfig: %v", err)) 38 t.Fail(err.Error()) 39 } 40 41 start := time.Now() 42 err = pkg.VerifyRancherAccess(t.Logs) 43 if err != nil { 44 t.Logs.Error(fmt.Sprintf("Error verifying access to Rancher: %v", err)) 45 t.Fail(err.Error()) 46 } 47 48 metrics.Emit(t.Metrics.With("rancher_access_elapsed_time", time.Since(start).Milliseconds())) 49 50 k8sClient, err := pkg.GetDynamicClientInCluster(kubeconfigPath) 51 if err != nil { 52 t.Logs.Error(fmt.Sprintf("Error getting K8S client: %v", err)) 53 t.Fail(err.Error()) 54 } 55 56 start = time.Now() 57 t.Logs.Info("Verify local cluster status") 58 Eventually(func() (bool, error) { 59 clusterData, err := k8sClient.Resource(pkg.GvkToGvr(rancher.GVKCluster)).Get(context.Background(), rancher.ClusterLocal, v1.GetOptions{}) 60 if err != nil { 61 t.Logs.Error(fmt.Sprintf("Error getting local Cluster CR: %v", err)) 62 return false, err 63 } 64 status := clusterData.UnstructuredContent()["status"].(map[string]interface{}) 65 conditions := status["conditions"].([]interface{}) 66 for _, condition := range conditions { 67 conditionStage := condition.(map[string]interface{}) 68 if conditionStage["status"].(string) == "True" && conditionStage["type"].(string) == "Ready" { 69 return true, nil 70 } 71 } 72 return false, fmt.Errorf("Cluster still not in active state") 73 }, waitTimeout, pollingInterval).Should(Equal(true), "rancher local cluster not in active state") 74 metrics.Emit(t.Metrics.With("get_cluster_state_elapsed_time", time.Since(start).Milliseconds())) 75 76 minVer14, err := pkg.IsVerrazzanoMinVersion("1.4.0", kubeconfigPath) 77 Expect(err).ToNot(HaveOccurred()) 78 79 start = time.Now() 80 t.Logs.Info("Verify Local AuthConfig") 81 Eventually(func() (bool, error) { 82 localAuthConfigData, err := k8sClient.Resource(pkg.GvkToGvr(common.GVKAuthConfig)).Get(context.Background(), rancher.AuthConfigLocal, v1.GetOptions{}) 83 if err != nil { 84 t.Logs.Error(fmt.Sprintf("error getting local authConfig: %v", err)) 85 return false, err 86 } 87 88 authConfigAttributes := localAuthConfigData.UnstructuredContent() 89 return authConfigAttributes[rancher.AuthConfigAttributeEnabled].(bool), nil 90 }, waitTimeout, pollingInterval).Should(BeTrue(), "failed verifying local authconfig") 91 metrics.Emit(t.Metrics.With("get_local_authconfig_state_elapsed_time", time.Since(start).Milliseconds())) 92 93 if minVer14 { 94 start = time.Now() 95 t.Logs.Info("Verify OKE driver status") 96 Eventually(func() (bool, error) { 97 okeDriverData, err := k8sClient.Resource(pkg.GvkToGvr(rancher.GVKKontainerDriver)).Get(context.Background(), rancher.KontainerDriverOKE, v1.GetOptions{}) 98 if err != nil { 99 t.Logs.Error(fmt.Sprintf("Error getting OKE Driver CR: %v", err)) 100 return false, err 101 } 102 return okeDriverData.UnstructuredContent()["spec"].(map[string]interface{})["active"].(bool), nil 103 }, waitTimeout, pollingInterval).Should(Equal(true), "rancher OKE driver not activated") 104 metrics.Emit(t.Metrics.With("get_oke_driver_state_elapsed_time", time.Since(start).Milliseconds())) 105 106 start = time.Now() 107 err = pkg.VerifyRancherKeycloakAuthConfig(t.Logs) 108 if err != nil { 109 t.Logs.Error(fmt.Sprintf("Error verifying Rancher/Keycloak integration: %v", err)) 110 t.Fail(err.Error()) 111 } 112 113 metrics.Emit(t.Metrics.With("get_kc_authconfig_state_elapsed_time", time.Since(start).Milliseconds())) 114 // Verify Rancher auth settings 115 minVer170, err := pkg.IsVerrazzanoMinVersion("1.7.0", kubeconfigPath) 116 Expect(err).ToNot(HaveOccurred()) 117 if minVer170 { 118 verifySettingValue(rancher.SettingAuthResyncCron, rancher.SettingAuthResyncCronValue, k8sClient) 119 verifySettingValue(rancher.SettingAuthMaxAge, rancher.SettingAuthMaxAgeValue, k8sClient) 120 verifySettingValue(rancher.SettingAuthTTL, rancher.SettingAuthTTLValue, k8sClient) 121 verifySettingValue(rancher.SettingKubeDefaultTokenTTL, rancher.SettingKubeDefaultTokenTTLValue, k8sClient) 122 } 123 124 start = time.Now() 125 t.Logs.Info("Verify Verrazzano rancher user") 126 var rancherUsername string 127 Eventually(func() (bool, error) { 128 userList, err := k8sClient.Resource(pkg.GvkToGvr(rancher.GVKUser)).List(context.Background(), v1.ListOptions{}) 129 if err != nil { 130 t.Logs.Error(fmt.Sprintf("error getting rancher verrazzano user: %v", err)) 131 return false, err 132 } 133 for _, userData := range userList.Items { 134 username, ok := userData.UnstructuredContent()[rancher.UserAttributeUserName].(string) 135 if !ok || username != rancher.UsernameVerrazzano { 136 continue 137 } 138 userPrincipals, ok := userData.UnstructuredContent()[rancher.UserAttributePrincipalIDs].([]interface{}) 139 if ok { 140 switch reflect.TypeOf(userPrincipals).Kind() { 141 case reflect.Slice: 142 listOfPrincipleIDs := reflect.ValueOf(userPrincipals) 143 for i := 0; i < listOfPrincipleIDs.Len(); i++ { 144 principleID := listOfPrincipleIDs.Index(i).Interface().(string) 145 if strings.Contains(principleID, rancher.UserPrincipalKeycloakPrefix) { 146 rancherUsername = userData.GetName() 147 return true, nil 148 } 149 } 150 } 151 } 152 } 153 return false, fmt.Errorf("Verrazzano rancher user is not mapped in keycloak") 154 }, waitTimeout, pollingInterval).Should(Equal(true), "verrazzano rancher user not correctly configured") 155 metrics.Emit(t.Metrics.With("get_vz_rancher_user_elapsed_time", time.Since(start).Milliseconds())) 156 157 start = time.Now() 158 t.Logs.Info("Verify Verrazzano rancher user admin GlobalRoleBinding") 159 Eventually(func() (bool, error) { 160 grbData, err := k8sClient.Resource(pkg.GvkToGvr(rancher.GVKGlobalRoleBinding)).Get(context.Background(), rancher.GlobalRoleBindingVerrazzanoPrefix+rancherUsername, v1.GetOptions{}) 161 if err != nil { 162 t.Logs.Error(fmt.Sprintf("error getting rancher verrazzano user global role binding for rancher user %s : %v", rancherUsername, err)) 163 return false, err 164 } 165 166 grbAttributes := grbData.UnstructuredContent() 167 if grbAttributes[rancher.GlobalRoleBindingAttributeUserName].(string) != rancherUsername { 168 return false, fmt.Errorf("verrazzano rancher user global role binding user is invalid") 169 } 170 171 if grbAttributes[rancher.GlobalRoleBindingAttributeRoleName].(string) != rancher.AdminRoleName { 172 return false, fmt.Errorf("verrazzano rancher user global role binding role is invalid") 173 } 174 175 return true, nil 176 }, waitTimeout, pollingInterval).Should(Equal(true), "verrazzano rancher user global role binding does not exist") 177 metrics.Emit(t.Metrics.With("get_vz_rancher_user_grb_elapsed_time", time.Since(start).Milliseconds())) 178 179 start = time.Now() 180 t.Logs.Info("Verify ClusterRoleTemplateBindings are created for Keycloak groups") 181 Eventually(func() (bool, error) { 182 for _, grp := range rancher.GroupRolePairs { 183 name := fmt.Sprintf("crtb-%s-%s", grp[rancher.ClusterRoleKey], grp[rancher.GroupKey]) 184 crtpData, err := k8sClient.Resource(pkg.GvkToGvr(rancher.GVKClusterRoleTemplateBinding)).Namespace(rancher.ClusterLocal).Get(context.Background(), name, v1.GetOptions{}) 185 if err != nil { 186 return false, fmt.Errorf("error getting ClusterRoleTemplateBinding %s: %v", name, err) 187 } 188 189 crtpAttributes := crtpData.UnstructuredContent() 190 if crtpAttributes[rancher.ClusterRoleTemplateBindingAttributeGroupPrincipalName].(string) != rancher.GroupPrincipalKeycloakPrefix+grp[rancher.GroupKey] { 191 return false, fmt.Errorf("ClusterRoleTemplateBinding %s attribute %s is invalid, expected %s, got %s", name, rancher.ClusterRoleTemplateBindingAttributeGroupPrincipalName, crtpAttributes[rancher.ClusterRoleTemplateBindingAttributeGroupPrincipalName].(string), rancher.GroupPrincipalKeycloakPrefix+grp[rancher.GroupKey]) 192 } 193 194 if crtpAttributes[rancher.ClusterRoleTemplateBindingAttributeRoleTemplateName].(string) != grp[rancher.ClusterRoleKey] { 195 return false, fmt.Errorf("ClusterRoleTemplateBinding %s attribute %s is invalid, expected %s, got %s", name, rancher.ClusterRoleTemplateBindingAttributeRoleTemplateName, crtpAttributes[rancher.ClusterRoleTemplateBindingAttributeRoleTemplateName].(string), grp[rancher.ClusterRoleKey]) 196 } 197 } 198 199 return true, nil 200 }, waitTimeout, pollingInterval).Should(Equal(true), "ClusterRoleTemplateBinding not found or incorrect") 201 metrics.Emit(t.Metrics.With("get_crtb_elapsed_time", time.Since(start).Milliseconds())) 202 203 start = time.Now() 204 t.Logs.Info("Verify RoleTemplate are created for Keycloak groups ClusterRoleBindings") 205 Eventually(func() (bool, error) { 206 _, err := k8sClient.Resource(pkg.GvkToGvr(rancher.GVKRoleTemplate)).Get(context.Background(), rancher.VerrazzanoAdminRoleName, v1.GetOptions{}) 207 if err != nil { 208 return false, fmt.Errorf("error getting RoleTemplate %s: %v", rancher.VerrazzanoAdminRoleName, err) 209 } 210 211 _, err = k8sClient.Resource(pkg.GvkToGvr(rancher.GVKRoleTemplate)).Get(context.Background(), rancher.VerrazzanoMonitorRoleName, v1.GetOptions{}) 212 if err != nil { 213 return false, fmt.Errorf("error getting RoleTemplate %s: %v", rancher.VerrazzanoMonitorRoleName, err) 214 } 215 216 return true, nil 217 }, waitTimeout, pollingInterval).Should(Equal(true), "RoleTemplate not found") 218 metrics.Emit(t.Metrics.With("get_roletemplate_elapsed_time", time.Since(start).Milliseconds())) 219 verifySettingValue(rancher.SettingUIPL, rancher.SettingUIPLValueVerrazzano, k8sClient) 220 // VZ-11418 221 //verifyUILogoSetting(rancher.SettingUILogoLight, rancher.SettingUILogoLightFile, k8sClient) 222 //verifyUILogoSetting(rancher.SettingUILogoDark, rancher.SettingUILogoDarkFile, k8sClient) 223 224 } 225 226 minVer15, err := pkg.IsVerrazzanoMinVersion("1.5.0", kubeconfigPath) 227 Expect(err).ToNot(HaveOccurred()) 228 if minVer15 { 229 verifySettingValue(rancher.SettingUIPrimaryColor, rancher.SettingUIPrimaryColorValue, k8sClient) 230 verifySettingValue(rancher.SettingUILinkColor, rancher.SettingUILinkColorValue, k8sClient) 231 verifySettingValue(rancher.SettingUIBrand, rancher.SettingUIBrandValue, k8sClient) 232 } 233 } 234 }) 235 }) 236 }) 237 238 var _ = t.AfterEach(func() {}) 239 240 // verifyUILogoSetting verifies the value of ui logo related rancher setting 241 // GIVEN a Verrazzano installation with ui settings (ui-logo-dark and ui-logo-light) populated 242 // AND corresponding actual logo files present in specified path in a running rancher pod 243 // 244 // WHEN value of the base64 encoded logo file is extracted from the setting CR specified by settingName 245 // AND compared with base64 encoded value of corresponding actual logo file present in running rancher pod 246 // THEN both the values are expected to be equal, otherwise the test scenario is deemed to have failed. 247 /*func verifyUILogoSetting(settingName string, logoFilename string, dynamicClient dynamic.Interface) { 248 start := time.Now() 249 t.Logs.Infof("Verify %s setting", settingName) 250 Eventually(func() (bool, error) { 251 clusterData, err := dynamicClient.Resource(pkg.GvkToGvr(common.GVKSetting)).Get(context.Background(), settingName, v1.GetOptions{}) 252 if err != nil { 253 t.Logs.Error(fmt.Sprintf("Error getting %s setting: %v", settingName, err)) 254 return false, err 255 } 256 257 value := clusterData.UnstructuredContent()["value"].(string) 258 logoSVG := strings.Split(value, rancher.SettingUILogoValueprefix)[1] 259 // Strip out any extra carriage returns 260 logoSVG = strings.ReplaceAll(logoSVG, "\r\r", "\r") 261 cfg, err := k8sutil.GetKubeConfig() 262 if err != nil { 263 t.Logs.Error(fmt.Sprintf("Error getting client config to verify value of %s setting: %v", settingName, err)) 264 return false, err 265 } 266 267 c, err := client.New(cfg, client.Options{}) 268 if err != nil { 269 t.Logs.Error(fmt.Sprintf("Error getting client to verify value of %s setting: %v", settingName, err)) 270 return false, err 271 } 272 273 pod, err := k8sutil.GetRunningPodForLabel(c, "app=rancher", "cattle-system") 274 if err != nil { 275 t.Logs.Error(fmt.Sprintf("Error getting running rancher pod to verify value of %s setting: %v", settingName, err)) 276 return false, err 277 } 278 279 k8sClient, err := kubernetes.NewForConfig(cfg) 280 if err != nil { 281 t.Logs.Error(fmt.Sprintf("Error getting kube client to verify value of %s setting: %v", settingName, err)) 282 return false, err 283 } 284 285 logoCommand := []string{"/bin/sh", "-c", fmt.Sprintf("cat %s/%s | base64", rancher.SettingUILogoFolder, logoFilename)} 286 var stdout, stderr string 287 stdout, _, err = k8sutil.ExecPod(k8sClient, cfg, pod, "rancher", logoCommand) 288 if err != nil || strings.Contains(stdout, "No such file or directory") { 289 // Try pre-Rancher 2.7.5 location 290 logoCommand = []string{"/bin/sh", "-c", fmt.Sprintf("cat %s/%s | base64", rancher.SettingUILogoFolderBeforeRancher275, logoFilename)} 291 stdout, stderr, err = k8sutil.ExecPod(k8sClient, cfg, pod, "rancher", logoCommand) 292 if err != nil { 293 t.Logs.Error(fmt.Sprintf("Error executing command in rancher pod to verify value of %s setting: %v, stderr: %v", settingName, err, stderr)) 294 return false, err 295 } 296 break 297 } 298 299 // Strip out any extra carriage returns 300 stdout = strings.ReplaceAll(stdout, "\r\r", "\r") 301 if stdout != logoSVG { 302 t.Logs.Errorf("Setting %s unstructured %v", logoFilename, clusterData.UnstructuredContent()) 303 t.Logs.Errorf("Got %s for Rancher UI logo path, expected %s", stdout, logoSVG) 304 return false, nil 305 } 306 return true, nil 307 }, waitTimeout, pollingInterval).Should(Equal(true)) 308 metrics.Emit(t.Metrics.With("get_ui_setting_elapsed_time", time.Since(start).Milliseconds())) 309 310 } 311 */ 312 // verifySettingValue verifies the value of a rancher setting 313 // GIVEN a Verrazzano installation with setting specified by settingName populated 314 // 315 // WHEN value field of the setting CR specified by settingName is extracted 316 // AND compared with input expectedValue 317 // THEN both the values are expected to be equal, otherwise the test scenario is deemed to have failed. 318 func verifySettingValue(settingName string, expectedValue string, k8sClient dynamic.Interface) { 319 start := time.Now() 320 t.Logs.Infof("Verify %s setting", settingName) 321 Eventually(func() (bool, error) { 322 clusterData, err := k8sClient.Resource(pkg.GvkToGvr(common.GVKSetting)).Get(context.Background(), settingName, v1.GetOptions{}) 323 if err != nil { 324 t.Logs.Errorf("Error getting %s setting: %v", settingName, err.Error()) 325 return false, err 326 } 327 value := clusterData.UnstructuredContent()["value"].(string) 328 return expectedValue == value, nil 329 }, waitTimeout, pollingInterval).Should(Equal(true), fmt.Sprintf("rancher %s setting not updated", settingName)) 330 metrics.Emit(t.Metrics.With(fmt.Sprintf("get_%s_setting_elapsed_time", strings.ReplaceAll(settingName, "-", "")), time.Since(start).Milliseconds())) 331 }