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  }