github.com/verrazzano/verrazzano@v1.7.0/pkg/bom/bom_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 bom
     5  
     6  import (
     7  	"fmt"
     8  	"github.com/stretchr/testify/assert"
     9  	"testing"
    10  )
    11  
    12  const (
    13  	ingressControllerComponent = "ingress-controller"
    14  	ingressControllerImageName = "nginx-ingress-controller"
    15  )
    16  
    17  // testSubComponent contains the override Key values for a subcomponent.
    18  type testSubComponent struct {
    19  	// kvs is the map of helm Key to expected helm Value.  These values are used in helm overrides
    20  	// for the subcomponent chart
    21  	kvs map[string]string
    22  }
    23  
    24  // testSubcomponetHelmKeyValues are the Key:values pairs that will be passed to helm as overrides.
    25  // The map Key is the subcomponent name.
    26  // This list of subcomponents is in the verrazzano-bom.json file and it must stay in sync with that file
    27  // Keep this map in the same order as that JSON for review purposes.
    28  var testSubcomponetHelmKeyValues = map[string]*testSubComponent{
    29  	"verrazzano-platform-operator": {
    30  		kvs: map[string]string{
    31  			"image": "ghcr.io/verrazzano/VERRAZZANO_PLATFORM_OPERATOR_IMAGE:VERRAZZANO_PLATFORM_OPERATOR_TAG",
    32  		},
    33  	},
    34  	"cert-manager": {
    35  		kvs: map[string]string{
    36  			"image.repository": "ghcr.io/verrazzano/cert-manager-controller",
    37  			"image.tag":        "0.13.1-20201016205232-4c8f3fe38",
    38  			"extraArgs[0]=--acme-http01-solver-image": "ghcr.io/verrazzano/cert-manager-acmesolver:0.13.1-20201016205234-4c8f3fe38",
    39  			"webhook.image.repository":                "ghcr.io/verrazzano/cert-manager-webhook",
    40  			"webhook.image.tag":                       "1.2.0-20210602163405-aac6bdf62",
    41  			"cainjector.image.repository":             "ghcr.io/verrazzano/cert-manager-cainjector",
    42  			"cainjector.image.tag":                    "1.2.0-20210602163405-aac6bdf62",
    43  		},
    44  	},
    45  	ingressControllerComponent: {
    46  		kvs: map[string]string{
    47  			"controller.image.repository":     "ghcr.io/verrazzano/nginx-ingress-controller",
    48  			"controller.image.tag":            "0.46.0-20210510134749-abc2d2088",
    49  			"defaultBackend.image.repository": "ghcr.io/verrazzano/nginx-ingress-default-backend",
    50  			"defaultBackend.image.tag":        "0.46.0-20210510134749-abc2d2088",
    51  		},
    52  	},
    53  	"external-dns": {
    54  		kvs: map[string]string{
    55  			"image.repository": "verrazzano/external-dns",
    56  			"image.registry":   "ghcr.io",
    57  			"image.tag":        "v0.7.1-20201016205338-516bc8b2",
    58  		},
    59  	},
    60  	"istiocoredns": {
    61  		kvs: map[string]string{
    62  			"istiocoredns.coreDNSImage":       "ghcr.io/verrazzano/coredns",
    63  			"istiocoredns.coreDNSTag":         "1.6.2",
    64  			"istiocoredns.coreDNSPluginImage": "ghcr.io/verrazzano/istio-coredns-plugin:0.2-20201016204812-23723dcb",
    65  		},
    66  	},
    67  	"istiod": {
    68  		kvs: map[string]string{
    69  			"pilot.image":        "ghcr.io/verrazzano/pilot:1.7.3",
    70  			"global.proxy.image": "proxyv2",
    71  			"global.tag":         "1.7.3",
    72  		},
    73  	},
    74  	"istio-ingress": {
    75  		kvs: map[string]string{
    76  			"global.proxy.image": "proxyv2",
    77  			"global.tag":         "1.7.3",
    78  		},
    79  	},
    80  	"istio-egress": {
    81  		kvs: map[string]string{
    82  			"global.proxy.image": "proxyv2",
    83  			"global.tag":         "1.7.3",
    84  		},
    85  	},
    86  	"rancher": {
    87  		kvs: map[string]string{
    88  			"rancherImage":    "ghcr.io/verrazzano/rancher",
    89  			"rancherImageTag": "v2.5.7-20210407205410-1c7b39d0c",
    90  		},
    91  	},
    92  	// NOTE additional-rancher images are not used by the local rancher helm chart used by verrazzano
    93  	// so ignore those entries
    94  
    95  	"verrazzano": {
    96  		kvs: map[string]string{
    97  			"monitoringOperator.imageName":       "ghcr.io/verrazzano/verrazzano-monitoring-operator",
    98  			"monitoringOperator.imageVersion":    "0.15.0-20210521020822-9b87485",
    99  			"monitoringOperator.istioProxyImage": "ghcr.io/verrazzano/proxyv2:1.7.3",
   100  			"monitoringOperator.grafanaImage":    "ghcr.io/verrazzano/grafana:v6.4.4",
   101  			"monitoringOperator.prometheusImage": "ghcr.io/verrazzano/prometheus:v2.13.1",
   102  			"monitoringOperator.osImage":         "ghcr.io/verrazzano/opensearch:2.3.0-20230123213036-bd387046f04",
   103  			"monitoringOperator.osdImage":        "ghcr.io/verrazzano/opensearch-dashboards:2.3.0-20230124171546-f9e6353395",
   104  			"monitoringOperator.oidcProxyImage":  "ghcr.io/verrazzano/nginx-ingress-controller:0.46.0-20210510134749-abc2d2088",
   105  			"api.imageName":                      "ghcr.io/verrazzano/nginx-ingress-controller",
   106  			"api.imageVersion":                   "0.46.0-20210510134749-abc2d2088",
   107  		},
   108  	},
   109  	"monitoring-init-images": {
   110  		kvs: map[string]string{
   111  			"monitoringOperator.osInitImage": "ghcr.io/oracle/oraclelinux:7.8",
   112  		},
   113  	},
   114  	"oam-kubernetes-runtime": {
   115  		kvs: map[string]string{
   116  			"image.repository": "ghcr.io/verrazzano/oam-kubernetes-runtime",
   117  			"image.tag":        "v0.3.0-20210222205541-9e8d4fb",
   118  		},
   119  	},
   120  	"verrazzano-application-operator": {
   121  		kvs: map[string]string{
   122  			"image":        "ghcr.io/verrazzano/VERRAZZANO_APPLICATION_OPERATOR_IMAGE:VERRAZZANO_APPLICATION_OPERATOR_TAG",
   123  			"fluentdImage": "ghcr.io/verrazzano/fluentd-kubernetes-daemonset:v1.12.3-20210517195222-f345ec2",
   124  		},
   125  	},
   126  	"weblogic-operator": {
   127  		kvs: map[string]string{
   128  			"image":                           "ghcr.io/oracle/weblogic-kubernetes-operator:3.2.2",
   129  			"weblogicMonitoringExporterImage": "ghcr.io/oracle/weblogic-monitoring-exporter:2.0.7",
   130  		},
   131  	},
   132  	"coherence-operator": {
   133  		kvs: map[string]string{
   134  			"image": "ghcr.io/oracle/coherence-operator:3.1.3",
   135  		},
   136  	},
   137  	"mysql": {
   138  		kvs: map[string]string{
   139  			"image":    "ghcr.io/verrazzano/mysql",
   140  			"imageTag": "8.0.20",
   141  		},
   142  	},
   143  	"oraclelinux": {
   144  		kvs: map[string]string{
   145  			"busybox.image": "ghcr.io/oracle/oraclelinux",
   146  			"busybox.tag":   "7-slim",
   147  		},
   148  	},
   149  	"keycloak": {
   150  		kvs: map[string]string{
   151  			"keycloak.image.repository": "ghcr.io/verrazzano/keycloak",
   152  			"keycloak.image.tag":        "10.0.1-20201016212759-30d98b0",
   153  		},
   154  	},
   155  	"keycloak-oracle-theme": {
   156  		kvs: map[string]string{
   157  			"image": "ghcr.io/verrazzano/keycloak-oracle-theme:0.15.0-20210510085250-01638c7",
   158  		},
   159  	},
   160  	"fluentd": {
   161  		kvs: map[string]string{
   162  			"logging.fluentdImage": "ghcr.io/verrazzano/fluentd-kubernetes-daemonset:v1.14.5-20230810212038-8777b84",
   163  		},
   164  	},
   165  	"verrazzano-console": {
   166  		kvs: map[string]string{
   167  			"imageName": "ghcr.io/verrazzano/console",
   168  			"imageTag":  "v2.0.0-20230912070053-2d1883d",
   169  		},
   170  	},
   171  }
   172  
   173  // This is the real BOM file path needed for unit tests
   174  const realBomFilePath = "testdata/verrazzano-bom.json"
   175  const testBomFilePath = "testdata/test_bom.json"
   176  const testBomSubcomponentOverridesPath = "testdata/test_bom_sc_overrides.json"
   177  const testBomImageOverridesPath = "testdata/test_bom_image_overrides.json"
   178  
   179  // TestFakeBom tests loading a fake bom json into a struct
   180  // GIVEN a json file
   181  // WHEN I call loadBom
   182  // THEN the correct Verrazzano bom is returned
   183  func TestFakeBom(t *testing.T) {
   184  	assert := assert.New(t)
   185  	bom, err := NewBom(testBomFilePath)
   186  	assert.NoError(err, "error calling NewBom")
   187  	assert.Equal("ghcr.io", bom.bomDoc.Registry, "Wrong registry name")
   188  	assert.Len(bom.bomDoc.Components, 16, "incorrect number of Bom components")
   189  
   190  	validateImages(assert, &bom, true)
   191  }
   192  
   193  // TestRealBom tests loading the real bom json into a struct
   194  // GIVEN a json file
   195  // WHEN I call loadBom
   196  // THEN the correct Verrazzano bom is returned
   197  func TestRealBom(t *testing.T) {
   198  	assert := assert.New(t)
   199  	bom, err := NewBom(realBomFilePath)
   200  	assert.NoError(err, "error calling NewBom")
   201  	assert.Equal("ghcr.io", bom.bomDoc.Registry, "Wrong registry name")
   202  	assert.Len(bom.bomDoc.Components, 16, "incorrect number of Bom components")
   203  
   204  	// Ignore the values in the real bom file since some will change every build
   205  	validateImages(assert, &bom, false)
   206  }
   207  
   208  // validateImages validates the images in the subcomponents.
   209  // Optional check the image Value.
   210  func validateImages(assert *assert.Assertions, bom *Bom, checkImageVal bool) {
   211  	// Validate each component
   212  	for _, comp := range bom.bomDoc.Components {
   213  		for _, sub := range comp.SubComponents {
   214  			// Get the expected Key:Value pair overrides for this subcomponent
   215  			expectedSub := testSubcomponetHelmKeyValues[sub.Name]
   216  			if expectedSub == nil {
   217  				fmt.Println("Skipping subcomponent " + sub.Name)
   218  				continue
   219  			}
   220  
   221  			// Get the actual Key Value override list for this subcomponent
   222  			foundKvs, err := bom.BuildImageOverrides(sub.Name)
   223  			assert.NoError(err, "error calling BuildImageOverrides")
   224  			assert.Equal(len(expectedSub.kvs), len(foundKvs), "Incorrect override list len for "+sub.Name)
   225  
   226  			// Loop through the found kv pairs and make sure the actual kvs match the expected
   227  			for _, kv := range foundKvs {
   228  				expectedVal, ok := expectedSub.kvs[kv.Key]
   229  				assert.True(ok, "Found unexpected Key in override list for "+sub.Name)
   230  				if checkImageVal {
   231  					assert.Equal(expectedVal, kv.Value, "Found unexpected Value in override list for "+sub.Name)
   232  				}
   233  			}
   234  		}
   235  	}
   236  }
   237  
   238  // TestBomSubcomponentOverrides the ability to override registry and repo settings at the subcomponent level
   239  // GIVEN a json file where a subcomponent overrides the registry and repository location of its images
   240  // WHEN I load it and check those settings
   241  // THEN the correct overrides are present without affecting the global registry setting
   242  func TestBomSubcomponentOverrides(t *testing.T) {
   243  	assert := assert.New(t)
   244  	bom, err := NewBom(testBomSubcomponentOverridesPath)
   245  	assert.Equal("ghcr.io", bom.GetRegistry(), "Global registry not correct")
   246  	assert.NoError(err)
   247  
   248  	nginxSubcomponent, err := bom.GetSubcomponent(ingressControllerComponent)
   249  	assert.NotNil(t, nginxSubcomponent)
   250  	assert.NoError(err)
   251  
   252  	assert.Equal("ghcr.io", bom.GetRegistry(), "Global registry not correct")
   253  	assert.Equal("myreg.io", bom.ResolveRegistry(nginxSubcomponent, BomImage{}), "NGINX subcomponent registry not correct")
   254  	assert.Equal("myrepoprefix/testnginx", bom.ResolveRepo(nginxSubcomponent, BomImage{}), "NGINX subcomponent repo not correct")
   255  
   256  	vpoSubcomponent, err := bom.GetSubcomponent("verrazzano-platform-operator")
   257  	assert.NotNil(t, vpoSubcomponent)
   258  	assert.NoError(err)
   259  
   260  	assert.Equal("ghcr.io", bom.ResolveRegistry(vpoSubcomponent, BomImage{}), "VPO subcomponent registry not correct")
   261  	assert.Equal("verrazzano", bom.ResolveRepo(vpoSubcomponent, BomImage{}), "VPO subcomponent repo not correct")
   262  }
   263  
   264  // TestBomImageOverrides tests the ability to override the registry settings for a subcomponent
   265  // GIVEN a call to ResolveRegistry and ResolveRepo for a valid subcomponent
   266  // WHEN the image has overrides for the registry and repository
   267  // THEN the correct registry and repository overrides are returned
   268  func TestBomImageOverrides(t *testing.T) {
   269  	bom, err := NewBom(testBomImageOverridesPath)
   270  	assert.NoError(t, err)
   271  	assert.Equal(t, "ghcr.io", bom.GetRegistry())
   272  	sc, err := bom.GetSubcomponent("verrazzano-platform-operator")
   273  	assert.NoError(t, err)
   274  	img := sc.Images[0]
   275  	assert.Equal(t, "testRegistry", bom.ResolveRegistry(sc, img))
   276  	assert.Equal(t, "testRepository", bom.ResolveRepo(sc, img))
   277  }
   278  
   279  // TestBomFindImage tests the FindImage method
   280  // GIVEN a call to FindImage for a valid subcomponent
   281  // WHEN I ask for an image for that subcomponent
   282  // THEN the correct BomImage object is returned if found, or an error if not found
   283  func TestBomFindImage(t *testing.T) {
   284  	bom, err := NewBom(testBomFilePath)
   285  	assert.NoError(t, err)
   286  
   287  	_, err = bom.FindImage(ingressControllerComponent, ingressControllerImageName)
   288  	assert.NoError(t, err)
   289  
   290  	_, err = bom.FindImage(ingressControllerComponent, "foo")
   291  	assert.Error(t, err)
   292  }
   293  
   294  // TestBomComponentVersion tests the ability to fetch component version
   295  func TestBomComponentVersion(t *testing.T) {
   296  	bom, err := NewBom(realBomFilePath)
   297  	assert.NoError(t, err)
   298  	c, err := bom.GetComponent("verrazzano")
   299  	assert.NoError(t, err)
   300  	assert.NotNil(t, c)
   301  	assert.NotNil(t, c.Version)
   302  }
   303  
   304  // TestBomGetComponentVersion tests the GetComponentVersion method
   305  // GIVEN a call to GetComponentVersion for a valid component
   306  // WHEN I ask for the version of that component
   307  // THEN the correct version is returned if found, or an error if not found
   308  func TestBomGetComponentVersion(t *testing.T) {
   309  	bom, err := NewBom(testBomFilePath)
   310  	assert.NoError(t, err)
   311  
   312  	ver, err := bom.GetComponentVersion("cert-manager")
   313  	assert.NoError(t, err)
   314  	assert.Equal(t, ver, "v1.7.1")
   315  
   316  	ver, err = bom.GetComponentVersion("foo")
   317  	assert.Error(t, err)
   318  	assert.Equal(t, ver, "")
   319  }
   320  
   321  // TestGetSubcomponentImages tests the GetSubcomponentImages method
   322  // GIVEN a call to GetSubcomponentImages for a valid subcomponent
   323  // WHEN I ask for the images of that component
   324  // THEN the correct images are returned if found, or an error if not found
   325  func TestGetSubcomponentImages(t *testing.T) {
   326  	bom, err := NewBom(testBomFilePath)
   327  	assert.NoError(t, err)
   328  	subComponentImageforNil := []BomImage([]BomImage(nil))
   329  	subComponentImage := []BomImage([]BomImage{{ImageName: "external-dns", ImageTag: "v0.7.1-20201016205338-516bc8b2", Registry: "", Repository: "", HelmRegistryKey: "image.registry", HelmRepoKey: "", HelmImageKey: "", HelmTagKey: "image.tag", HelmFullImageKey: "image.repository", HelmRegistryAndRepoKey: ""}})
   330  	scImages, err := bom.GetSubcomponentImages("external-dns")
   331  	assert.NoError(t, err)
   332  	assert.Equal(t, scImages, subComponentImage)
   333  
   334  	scImages, err = bom.GetSubcomponentImages("foo")
   335  	assert.Error(t, err)
   336  	assert.Equal(t, scImages, subComponentImageforNil)
   337  }
   338  
   339  // TestBomGetSubcomponentImageCount tests the GetSubcomponentImageCount method
   340  // GIVEN a call to GetSubcomponentImageCount for a valid subcomponent
   341  // WHEN I ask for the number of images of that component
   342  // THEN the correct number is returned if found, or zero if not found
   343  func TestGetSubcomponentImageCount(t *testing.T) {
   344  	bom, err := NewBom(testBomFilePath)
   345  	assert.NoError(t, err)
   346  
   347  	imageNum := bom.GetSubcomponentImageCount("foo")
   348  	assert.Equal(t, imageNum, 0)
   349  
   350  	imageNum = bom.GetSubcomponentImageCount(ingressControllerComponent)
   351  	assert.Equal(t, imageNum, 2)
   352  
   353  }