github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/registry/registry_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 registry
     5  
     6  import (
     7  	"fmt"
     8  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
     9  	"github.com/verrazzano/verrazzano/pkg/nginxutil"
    10  	"os"
    11  	"strings"
    12  	"time"
    13  
    14  	. "github.com/onsi/ginkgo/v2"
    15  	. "github.com/onsi/gomega"
    16  	"github.com/verrazzano/verrazzano/platform-operator/constants"
    17  	"github.com/verrazzano/verrazzano/tests/e2e/pkg"
    18  	"github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework"
    19  	corev1 "k8s.io/api/core/v1"
    20  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  )
    22  
    23  const (
    24  	waitTimeout     = 2 * time.Minute
    25  	pollingInterval = 10 * time.Second
    26  
    27  	extOSPod                   = "opensearch-cluster-master-0"
    28  	helmOperationPodNamePrefix = "helm-operation"
    29  	shellImage                 = "shell:"
    30  )
    31  
    32  var registry = os.Getenv("REGISTRY")
    33  
    34  // Map that contains the images present in the BOM with the associated registry URL
    35  var imageRegistryMap = make(map[string]string)
    36  
    37  var ingressNGINXNamespace string
    38  
    39  var t = framework.NewTestFramework("registry")
    40  var beforeSuite = t.BeforeSuiteFunc(func() {
    41  	var err error
    42  	ingressNGINXNamespace, err = nginxutil.DetermineNamespaceForIngressNGINX(vzlog.DefaultLogger())
    43  	if err != nil {
    44  		Fail(err.Error())
    45  	}
    46  })
    47  var _ = BeforeSuite(beforeSuite)
    48  var afterSuite = t.AfterSuiteFunc(func() {})
    49  var _ = AfterSuite(afterSuite)
    50  var _ = t.AfterEach(func() {})
    51  
    52  var _ = t.Describe("Image Registry Verification", Label("f:platform-lcm.private-registry"),
    53  	func() {
    54  		t.It("All the pods in the cluster have the expected registry URLs",
    55  			func() {
    56  				// List of namespaces from which all the pods are queried to confirm the images are loaded from the target registry/repo
    57  				var listOfNamespaces = []string{
    58  					"cattle-global-data",
    59  					"cattle-global-data-nt",
    60  					"cattle-system",
    61  					"cert-manager",
    62  					"default",
    63  					"fleet-default",
    64  					"fleet-local",
    65  					"fleet-system",
    66  					ingressNGINXNamespace,
    67  					"istio-system",
    68  					"keycloak",
    69  					"local",
    70  					"monitoring",
    71  					"verrazzano-install",
    72  					"verrazzano-mc",
    73  					"argocd",
    74  					constants.VerrazzanoSystemNamespace,
    75  					constants.VerrazzanoMonitoringNamespace,
    76  				}
    77  				foundHelmOperationPod := false
    78  				shellImageHasCorrectPrefix := false
    79  				var pod corev1.Pod
    80  				for i, ns := range listOfNamespaces {
    81  					var pods *corev1.PodList
    82  					Eventually(func() (*corev1.PodList, error) {
    83  						var err error
    84  						pods, err = pkg.ListPods(ns, metav1.ListOptions{})
    85  						return pods, err
    86  					}, waitTimeout, pollingInterval).ShouldNot(BeNil(), fmt.Sprintf("Error listing pods in the namespace %s", ns))
    87  
    88  					for j := range pods.Items {
    89  						pod = pods.Items[j]
    90  						// Skip private registry validation in case of external OpenSearch
    91  						if pod.Name == extOSPod {
    92  							continue
    93  						}
    94  						if strings.HasPrefix(pod.Name, helmOperationPodNamePrefix) {
    95  							foundHelmOperationPod = true
    96  						}
    97  						podLabels := pod.GetLabels()
    98  						_, ok := podLabels["job-name"]
    99  						if pod.Status.Phase != corev1.PodRunning && ok {
   100  							continue
   101  						}
   102  						pkg.Log(pkg.Info, fmt.Sprintf("%d. Validating the registry url prefix for pod: %s in namespace: %s", i, pod.Name, ns))
   103  						for k := range pod.Spec.Containers {
   104  							image := pod.Spec.Containers[k].Image
   105  							registryURL, err := getRegistryURL(image)
   106  							Expect(err).To(BeNil(), fmt.Sprintf("Failed to get the expected registry url for image %s: %v", image, err))
   107  							hasCorrectRegistryPrefix := strings.HasPrefix(image, registryURL)
   108  
   109  							// When checking the Rancher Helm Operation pod Shell image, there may be old pods left over so we only check to see
   110  							// if at least one of the Shell images has the correct registry prefix
   111  							if strings.Contains(image, shellImage) {
   112  								if hasCorrectRegistryPrefix {
   113  									shellImageHasCorrectPrefix = true
   114  								}
   115  								continue
   116  							}
   117  							Expect(hasCorrectRegistryPrefix).To(BeTrue(),
   118  								fmt.Sprintf("FAIL: The image for the pod %s in containers, doesn't start with expected registry URL prefix %s, image name %s", pod.Name, registryURL, image))
   119  						}
   120  						for k := range pod.Spec.InitContainers {
   121  							image := pod.Spec.InitContainers[k].Image
   122  							registryURL, err := getRegistryURL(image)
   123  							Expect(err).To(BeNil(), fmt.Sprintf("Failed to get the expected registry url for init container image %s: %v", image, err))
   124  							Expect(strings.HasPrefix(image, registryURL)).To(BeTrue(),
   125  								fmt.Sprintf("FAIL: The image for the pod %s in initContainers, doesn't start with expected registry URL prefix %s, image name %s", pod.Name, registryURL, image))
   126  						}
   127  					}
   128  				}
   129  
   130  				// If we found at least one Rancher Helm Operation pod, then make sure at least one of the Shell images has the correct prefix
   131  				if foundHelmOperationPod {
   132  					Expect(shellImageHasCorrectPrefix).To(BeTrue(), "FAIL: Found at least one Rancher Helm Operation pod but none of the shell images has the expected registry prefix")
   133  				}
   134  			})
   135  	})
   136  
   137  // getRegistryURL returns the private registry url if the private registry env is set
   138  // If private registry is not set, the registry url is determined based on what is specified in the BOM
   139  // for a given image
   140  func getRegistryURL(containerImage string) (string, error) {
   141  	// For private registry, determine the registry url from the corresponding env variables
   142  	if len(registry) > 0 {
   143  		return pkg.GetImagePrefix(), nil
   144  	}
   145  	// Populate image registry map if not already done
   146  	if len(imageRegistryMap) == 0 {
   147  		err := populateImageRegistryMap()
   148  		if err != nil {
   149  			return "", err
   150  		}
   151  	}
   152  	imageName := getImageName(containerImage)
   153  	// Due to the Rancher images changing from vz/rancher/shell to vz/rancher-shell, this logic handles looking up both
   154  	// the old and new shell image names in the BOM. If neither are found, then this function returns an error.
   155  	if imageRegistryMap[imageName] == "" && imageName == "shell" {
   156  		imageName = "rancher-shell"
   157  	}
   158  	// If the image is not defined in the bom, return an error
   159  	if imageRegistryMap[imageName] == "" {
   160  		return "", fmt.Errorf("the image %s is not specified in the BOM from platform operator", imageName)
   161  	}
   162  	registryURLFromBom := imageRegistryMap[imageName]
   163  	// If the registry of the image is docker.io and the container image does not have the registry prefix,
   164  	// remove docker.io from the constructed registry url. This is mainly to address the case where some of the
   165  	// images such as rancher-webhook does not have "docker.io" prefix in the image in the pod output.
   166  	if strings.HasPrefix(registryURLFromBom, "docker.io") && !strings.HasPrefix(containerImage, "docker.io") {
   167  		return strings.TrimPrefix(registryURLFromBom, "docker.io/"), nil
   168  	}
   169  	return registryURLFromBom, nil
   170  }
   171  
   172  // Populate image registry map from BOM
   173  func populateImageRegistryMap() error {
   174  	// Get the BOM from installed Platform Operator
   175  	bomDoc, err := pkg.GetBOMDoc()
   176  	if err != nil {
   177  		return err
   178  	}
   179  	globalRegistry := bomDoc.Registry
   180  	for _, component := range bomDoc.Components {
   181  		for _, subComponent := range component.SubComponents {
   182  			registry := globalRegistry
   183  			if len(subComponent.Registry) > 0 {
   184  				registry = subComponent.Registry
   185  			}
   186  			repository := subComponent.Repository
   187  			for _, image := range subComponent.Images {
   188  				if len(image.Registry) > 0 {
   189  					registry = image.Registry
   190  				}
   191  				if len(image.Repository) > 0 {
   192  					repository = image.Repository
   193  				}
   194  				imageRegistryMap[image.ImageName] = registry + "/" + repository
   195  			}
   196  		}
   197  	}
   198  	return nil
   199  }
   200  
   201  // Get the name of the image from the image URL
   202  func getImageName(imageURL string) string {
   203  	imageWithoutVer := strings.Split(imageURL, ":")[0]
   204  	imageParts := strings.Split(imageWithoutVer, "/")
   205  	return imageParts[len(imageParts)-1]
   206  }