github.com/verrazzano/verrazzano@v1.7.1/tools/vz/pkg/helpers/vzcapture_test.go (about)

     1  // Copyright (c) 2022, 2024, 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 helpers
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/json"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"path/filepath"
    13  	"regexp"
    14  	"testing"
    15  	"time"
    16  
    17  	certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
    18  	"github.com/crossplane/oam-kubernetes-runtime/apis/core"
    19  	"github.com/stretchr/testify/assert"
    20  	appv1alpha1 "github.com/verrazzano/verrazzano/application-operator/apis/app/v1alpha1"
    21  	appclusterv1alpha1 "github.com/verrazzano/verrazzano/application-operator/apis/clusters/v1alpha1"
    22  	appoamv1alpha1 "github.com/verrazzano/verrazzano/application-operator/apis/oam/v1alpha1"
    23  	clusterv1alpha1 "github.com/verrazzano/verrazzano/cluster-operator/apis/clusters/v1alpha1"
    24  	vzconstants "github.com/verrazzano/verrazzano/pkg/constants"
    25  	"github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1"
    26  	"github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/common"
    27  	"github.com/verrazzano/verrazzano/tools/vz/pkg/constants"
    28  	testhelpers "github.com/verrazzano/verrazzano/tools/vz/test/helpers"
    29  	corev1 "k8s.io/api/core/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    32  	"k8s.io/apimachinery/pkg/runtime"
    33  	"k8s.io/apimachinery/pkg/runtime/schema"
    34  	"k8s.io/cli-runtime/pkg/genericclioptions"
    35  	fakedynamic "k8s.io/client-go/dynamic/fake"
    36  	k8sfake "k8s.io/client-go/kubernetes/fake"
    37  	k8scheme "k8s.io/client-go/kubernetes/scheme"
    38  	"sigs.k8s.io/controller-runtime/pkg/client"
    39  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    40  )
    41  
    42  const dummyIP1 = "0.0.0.0"
    43  const dummyIP2 = "5.6.x.x"
    44  
    45  // TestCreateReportArchive
    46  // GIVEN a directory containing some files
    47  //
    48  //	WHEN I call function CreateReportArchive with a report file
    49  //	THEN expect it to create the report file
    50  func TestCreateReportArchive(t *testing.T) {
    51  	tmpDir, _ := os.MkdirTemp("", "bug-report")
    52  	defer cleanupTempDir(t, tmpDir)
    53  
    54  	captureDir := tmpDir + string(os.PathSeparator) + "test-report"
    55  	if err := os.Mkdir(captureDir, os.ModePerm); err != nil {
    56  		assert.Error(t, err)
    57  	}
    58  
    59  	// Create some files inside bugReport
    60  	_, err := os.Create(captureDir + string(os.PathSeparator) + "f1.txt")
    61  	if err != nil {
    62  		assert.Error(t, err)
    63  	}
    64  
    65  	_, err = os.Create(captureDir + string(os.PathSeparator) + "f2.txt")
    66  	if err != nil {
    67  		assert.Error(t, err)
    68  	}
    69  
    70  	_, err = os.Create(captureDir + string(os.PathSeparator) + "f3.txt")
    71  	if err != nil {
    72  		assert.Error(t, err)
    73  	}
    74  
    75  	bugReportFile, err := os.Create(tmpDir + string(os.PathSeparator) + "bug.tar.gz")
    76  	if err != nil {
    77  		assert.Error(t, err)
    78  	}
    79  	err = CreateReportArchive(captureDir, bugReportFile, true)
    80  	if err != nil {
    81  		assert.Error(t, err)
    82  	}
    83  
    84  	// Check file exists
    85  	assert.FileExists(t, bugReportFile.Name())
    86  }
    87  
    88  // TestRemoveDuplicates
    89  // GIVEN a string slice containing duplicates
    90  //
    91  //	WHEN I call function RemoveDuplicate
    92  //	THEN expect it to remove the duplicate elements
    93  func TestRemoveDuplicates(t *testing.T) {
    94  	testSlice := []string{"abc", "def", "abc"}
    95  	result := RemoveDuplicate(testSlice)
    96  	assert.True(t, true, len(result) == 2)
    97  }
    98  
    99  // TestGroupVersionResource
   100  //
   101  //	WHEN I call functions to get the config schemes
   102  //	THEN expect it to return the expected resource
   103  func TestGroupVersionResource(t *testing.T) {
   104  	assert.True(t, true, GetAppConfigScheme().Resource == constants.OAMAppConfigurations)
   105  	assert.True(t, true, GetComponentConfigScheme().Resource == constants.OAMComponents)
   106  	assert.True(t, true, GetMetricsTraitConfigScheme().Resource == constants.OAMMetricsTraits)
   107  	assert.True(t, true, GetIngressTraitConfigScheme().Resource == constants.OAMIngressTraits)
   108  	assert.True(t, true, GetMCComponentScheme().Resource == constants.OAMMCCompConfigurations)
   109  	assert.True(t, true, GetMCAppConfigScheme().Resource == constants.OAMMCAppConfigurations)
   110  	assert.True(t, true, GetVzProjectsConfigScheme().Resource == constants.OAMProjects)
   111  	assert.True(t, true, GetManagedClusterConfigScheme().Resource == constants.OAMManagedClusters)
   112  }
   113  
   114  // TestCaptureK8SResources
   115  //
   116  //	WHEN I call functions to capture k8s resource
   117  //	THEN expect it to not throw any error
   118  func TestCaptureK8SResources(t *testing.T) {
   119  	schemeForClient := k8scheme.Scheme
   120  	err := certmanagerv1.AddToScheme(schemeForClient)
   121  	assert.NoError(t, err)
   122  	k8sClient := k8sfake.NewSimpleClientset()
   123  	scheme := k8scheme.Scheme
   124  	AddCapiToScheme(scheme)
   125  	dynamicClient := fakedynamic.NewSimpleDynamicClient(scheme)
   126  	client := fake.NewClientBuilder().WithScheme(schemeForClient).Build()
   127  	captureDir, err := os.MkdirTemp("", "testcapture")
   128  	defer cleanupTempDir(t, captureDir)
   129  	assert.NoError(t, err)
   130  	buf := new(bytes.Buffer)
   131  	errBuf := new(bytes.Buffer)
   132  	tempFile, err := os.CreateTemp("", "testfile")
   133  	defer cleanupFile(t, tempFile)
   134  	assert.NoError(t, err)
   135  	SetMultiWriterOut(buf, tempFile)
   136  	SetMultiWriterErr(errBuf, tempFile)
   137  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   138  	err = CaptureK8SResources(client, k8sClient, dynamicClient, constants.VerrazzanoInstall, captureDir, rc)
   139  	assert.NoError(t, err)
   140  	isError = false
   141  }
   142  
   143  // TestCaptureMultiClusterOAMResources tests the functionality to capture the multi cluster related resources
   144  //
   145  //	WHEN I call functions to capture Verrazzano OAM resources in a multi cluster environment
   146  //	THEN expect it to not throw any error
   147  func TestCaptureMultiClusterOAMResources(t *testing.T) {
   148  	scheme := k8scheme.Scheme
   149  	_ = v1beta1.AddToScheme(scheme)
   150  	_ = clusterv1alpha1.AddToScheme(scheme)
   151  	_ = appclusterv1alpha1.AddToScheme(scheme)
   152  
   153  	dynamicClient := fakedynamic.NewSimpleDynamicClient(scheme)
   154  	captureDir, err := os.MkdirTemp("", "testcapture")
   155  	defer cleanupTempDir(t, captureDir)
   156  	assert.NoError(t, err)
   157  	buf := new(bytes.Buffer)
   158  	errBuf := new(bytes.Buffer)
   159  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   160  	assert.NoError(t, CaptureMultiClusterOAMResources(dynamicClient, []string{constants.VerrazzanoInstall}, captureDir, rc))
   161  }
   162  
   163  // TestCaptureOAMResources tests the functionality to capture the OAM resources in the cluster
   164  //
   165  //	WHEN I call functions to capture Verrazzano OAM resources
   166  //	THEN expect it to not throw any error
   167  func TestCaptureOAMResources(t *testing.T) {
   168  	scheme := k8scheme.Scheme
   169  	_ = v1beta1.AddToScheme(scheme)
   170  	_ = clusterv1alpha1.AddToScheme(scheme)
   171  	_ = appclusterv1alpha1.AddToScheme(scheme)
   172  	_ = appv1alpha1.AddToScheme(scheme)
   173  	_ = appoamv1alpha1.AddToScheme(scheme)
   174  	_ = core.AddToScheme(scheme)
   175  
   176  	dynamicClient := fakedynamic.NewSimpleDynamicClient(scheme)
   177  	captureDir, err := os.MkdirTemp("", "testcapture")
   178  	defer cleanupTempDir(t, captureDir)
   179  	assert.NoError(t, err)
   180  	buf := new(bytes.Buffer)
   181  	errBuf := new(bytes.Buffer)
   182  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   183  	assert.NoError(t, CaptureOAMResources(dynamicClient, []string{constants.VerrazzanoInstall}, captureDir, rc))
   184  }
   185  
   186  // TestCapturePodLog tests the functionality to capture the logs of a given pod.
   187  func TestCapturePodLog(t *testing.T) {
   188  	k8sClient := k8sfake.NewSimpleClientset()
   189  	captureDir, err := os.MkdirTemp("", "testcapture")
   190  	defer cleanupTempDir(t, captureDir)
   191  	assert.NoError(t, err)
   192  	buf := new(bytes.Buffer)
   193  	errBuf := new(bytes.Buffer)
   194  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   195  	err = CapturePodLog(k8sClient, corev1.Pod{}, constants.VerrazzanoInstall, captureDir, rc, 0, false)
   196  	assert.NoError(t, err)
   197  
   198  	//  GIVENT and empty k8s cluster,
   199  	//	WHEN I call functions to capture VPO pod logs,
   200  	//	THEN expect it to not throw any error.
   201  	err = CapturePodLog(k8sClient, corev1.Pod{ObjectMeta: metav1.ObjectMeta{
   202  		Name:      constants.VerrazzanoPlatformOperator,
   203  		Namespace: constants.VerrazzanoInstall,
   204  	}}, constants.VerrazzanoInstall, captureDir, rc, 0, false)
   205  	assert.NoError(t, err)
   206  
   207  	//  GIVENT a k8s cluster with a VPO pod,
   208  	//	WHEN I call functions to capture VPO pod logs,
   209  	//	THEN expect it to not throw any error.
   210  	k8sClient = k8sfake.NewSimpleClientset(&corev1.Pod{ObjectMeta: metav1.ObjectMeta{
   211  		Name:      constants.VerrazzanoPlatformOperator,
   212  		Namespace: constants.VerrazzanoInstall,
   213  	}, Spec: corev1.PodSpec{
   214  		Containers: []corev1.Container{
   215  			{
   216  				Name:  "testcontainer",
   217  				Image: "dummimage:notag",
   218  			},
   219  		},
   220  	}})
   221  	err = CapturePodLog(k8sClient, corev1.Pod{ObjectMeta: metav1.ObjectMeta{
   222  		Name:      constants.VerrazzanoPlatformOperator,
   223  		Namespace: constants.VerrazzanoInstall,
   224  	}, Spec: corev1.PodSpec{
   225  		Containers: []corev1.Container{
   226  			{
   227  				Name:  "testcontainer",
   228  				Image: "dummimage:notag",
   229  			},
   230  		},
   231  	}}, constants.VerrazzanoInstall, captureDir, rc, 300, false)
   232  	assert.NoError(t, err)
   233  }
   234  
   235  // TestGetPodList tests the functionality to return the list of pods with the given label
   236  func TestGetPodList(t *testing.T) {
   237  	//  GIVEN a k8s cluster with no VPO pods,
   238  	//	WHEN I call functions to get the list of pods in the k8s cluster,
   239  	//	THEN expect it to be an empty list.
   240  	pods, err := GetPodList(fake.NewClientBuilder().Build(), "app", constants.VerrazzanoPlatformOperator, constants.VerrazzanoInstall)
   241  	assert.NoError(t, err)
   242  	assert.Empty(t, pods)
   243  
   244  	//  GIVEN a k8s cluster with a VPO pod,
   245  	//	WHEN I call functions to get the list of pods in the k8s cluster,
   246  	//	THEN expect it to be an empty list.
   247  	pods, err = GetPodList(fake.NewClientBuilder().WithObjects(&corev1.Pod{
   248  		ObjectMeta: metav1.ObjectMeta{
   249  			Name:      constants.VerrazzanoPlatformOperator,
   250  			Namespace: constants.VerrazzanoInstall,
   251  			Labels:    map[string]string{"app": constants.VerrazzanoPlatformOperator},
   252  		},
   253  	}).Build(), "app", constants.VerrazzanoPlatformOperator, constants.VerrazzanoInstall)
   254  	assert.NoError(t, err)
   255  	assert.NotEmpty(t, pods)
   256  }
   257  
   258  // TestCaptureVZResource tests the functionality to capture the Verrazzano resource.
   259  func TestCaptureVZResource(t *testing.T) {
   260  	captureDir, err := os.MkdirTemp("", "testcapture")
   261  	defer cleanupTempDir(t, captureDir)
   262  	assert.NoError(t, err)
   263  	buf := new(bytes.Buffer)
   264  	errBuf := new(bytes.Buffer)
   265  
   266  	//  GIVEN a k8s cluster with a user provided Verrazzano CR,
   267  	//	WHEN I call functions to capture the Verrazzano CR,
   268  	//	THEN expect the file to contain the JSON output of the Verrazzano CR.
   269  	vz := &v1beta1.Verrazzano{
   270  		ObjectMeta: metav1.ObjectMeta{
   271  			Namespace: "default",
   272  			Name:      "myverrazzano",
   273  		},
   274  		Spec: v1beta1.VerrazzanoSpec{
   275  			Profile: v1beta1.Dev,
   276  		},
   277  	}
   278  	tempFile, err := os.CreateTemp("", "testfile")
   279  	defer cleanupFile(t, tempFile)
   280  	assert.NoError(t, err)
   281  	SetMultiWriterOut(buf, tempFile)
   282  	SetMultiWriterErr(errBuf, tempFile)
   283  	SetVerboseOutput(true)
   284  	SetIsLiveCluster()
   285  	err = CaptureVZResource(captureDir, vz)
   286  	assert.NoError(t, err)
   287  	assert.NotNil(t, GetMultiWriterOut())
   288  	assert.NotNil(t, GetMultiWriterErr())
   289  	assert.True(t, GetIsLiveCluster())
   290  }
   291  
   292  // TestCaptureVerrazzanoProjects tests the CaptureVerrazzanoProjects function
   293  // GIVEN a dynamic client possibly containing VerrazzanoProject resources
   294  // WHEN I call CaptureVerrazzanoProjects
   295  // THEN expect it to detect the VerrazzanoProjects and appropriately create a JSON file
   296  func TestCaptureVerrazzanoProjects(t *testing.T) {
   297  	scheme := k8scheme.Scheme
   298  	_ = appclusterv1alpha1.AddToScheme(scheme)
   299  	vzProject := appclusterv1alpha1.VerrazzanoProject{
   300  		ObjectMeta: metav1.ObjectMeta{
   301  			Namespace: vzconstants.VerrazzanoMultiClusterNamespace,
   302  			Name:      "myvzproject",
   303  		},
   304  	}
   305  	vzProject2 := appclusterv1alpha1.VerrazzanoProject{
   306  		ObjectMeta: metav1.ObjectMeta{
   307  			Namespace: vzconstants.VerrazzanoMultiClusterNamespace,
   308  			Name:      "myvzproject2",
   309  		},
   310  	}
   311  
   312  	tests := []struct {
   313  		name       string
   314  		vzProjects []runtime.Object
   315  	}{
   316  		{
   317  			"No VerrazzanoProjects exists",
   318  			nil,
   319  		},
   320  		{
   321  			"A single existing VerrazzanoProject",
   322  			[]runtime.Object{&vzProject},
   323  		},
   324  		{
   325  			"Two VerrazzanoProjects",
   326  			[]runtime.Object{&vzProject, &vzProject2},
   327  		},
   328  	}
   329  
   330  	for _, tt := range tests {
   331  		t.Run(tt.name, func(t *testing.T) {
   332  			// create dynamic client
   333  			var dynamicClient *fakedynamic.FakeDynamicClient
   334  			if tt.vzProjects == nil {
   335  				dynamicClient = fakedynamic.NewSimpleDynamicClient(scheme)
   336  			} else {
   337  				dynamicClient = fakedynamic.NewSimpleDynamicClient(scheme, tt.vzProjects...)
   338  			}
   339  
   340  			// create capture directory
   341  			captureDir, err := os.MkdirTemp("", "testcapture")
   342  			defer cleanupTempDir(t, captureDir)
   343  			assert.NoError(t, err)
   344  
   345  			// stdout and stderr
   346  			buf := new(bytes.Buffer)
   347  			errBuf := new(bytes.Buffer)
   348  			tempFile, _ := os.CreateTemp("", "testfile")
   349  			defer cleanupFile(t, tempFile)
   350  			SetMultiWriterOut(buf, tempFile)
   351  			SetMultiWriterErr(errBuf, tempFile)
   352  
   353  			// Call the function we want to test
   354  			rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   355  			assert.NoError(t, CaptureVerrazzanoProjects(dynamicClient, captureDir, rc))
   356  
   357  			// Check if the VerrazzanoProject JSON file exists in the cluster snapshot as expected
   358  			expectedFilePath := filepath.Join(captureDir, vzconstants.VerrazzanoMultiClusterNamespace, constants.VzProjectsJSON)
   359  			_, err = os.Stat(expectedFilePath)
   360  			if len(tt.vzProjects) == 0 {
   361  				assert.Error(t, err)
   362  			} else {
   363  				assert.NoError(t, err)
   364  				vzProjectList := &appclusterv1alpha1.VerrazzanoProjectList{}
   365  				bytesToUnmarshall, err := returnBytesFromAFile(expectedFilePath)
   366  				assert.NoError(t, err)
   367  				assert.NoError(t, json.Unmarshal(bytesToUnmarshall, vzProjectList))
   368  				assert.Len(t, vzProjectList.Items, len(tt.vzProjects),
   369  					"the file %s did not have the expected number of VerrazzanoProject resources listed", expectedFilePath)
   370  			}
   371  		})
   372  	}
   373  }
   374  
   375  // TestCaptureVerrazzanoManagedCluster tests the CaptureVerrazzanoManagedCluster function
   376  // GIVEN a dynamic client possibly containing VMC resources
   377  // WHEN I call CaptureVerrazzanoManagedCluster
   378  // THEN expect it to detect the VMCs and appropriately create a JSON file
   379  func TestCaptureVerrazzanoManagedCluster(t *testing.T) {
   380  	scheme := k8scheme.Scheme
   381  	_ = clusterv1alpha1.AddToScheme(scheme)
   382  	vmc := clusterv1alpha1.VerrazzanoManagedCluster{
   383  		ObjectMeta: metav1.ObjectMeta{
   384  			Namespace: vzconstants.VerrazzanoMultiClusterNamespace,
   385  			Name:      "myverrazzanomanagedcluster",
   386  		},
   387  	}
   388  	vmc2 := clusterv1alpha1.VerrazzanoManagedCluster{
   389  		ObjectMeta: metav1.ObjectMeta{
   390  			Namespace: vzconstants.VerrazzanoMultiClusterNamespace,
   391  			Name:      "myverrazzanomanagedcluster2",
   392  		},
   393  	}
   394  
   395  	tests := []struct {
   396  		name string
   397  		vmcs []runtime.Object
   398  	}{
   399  		{
   400  			"No VerrazzanoManagedClusters exists",
   401  			nil,
   402  		},
   403  		{
   404  			"A single existing VerrazzanoManagedCluster",
   405  			[]runtime.Object{&vmc},
   406  		},
   407  		{
   408  			"Two VerrazzanoManagedClusters",
   409  			[]runtime.Object{&vmc, &vmc2},
   410  		},
   411  	}
   412  
   413  	for _, tt := range tests {
   414  		t.Run(tt.name, func(t *testing.T) {
   415  			// create dynamic client
   416  			var dynamicClient *fakedynamic.FakeDynamicClient
   417  			if tt.vmcs == nil {
   418  				dynamicClient = fakedynamic.NewSimpleDynamicClient(scheme)
   419  			} else {
   420  				dynamicClient = fakedynamic.NewSimpleDynamicClient(scheme, tt.vmcs...)
   421  			}
   422  
   423  			// create capture directory
   424  			captureDir, err := os.MkdirTemp("", "testcapture")
   425  			defer cleanupTempDir(t, captureDir)
   426  			assert.NoError(t, err)
   427  
   428  			// stdout and stderr
   429  			buf := new(bytes.Buffer)
   430  			errBuf := new(bytes.Buffer)
   431  			tempFile, _ := os.CreateTemp("", "testfile")
   432  			defer cleanupFile(t, tempFile)
   433  			SetMultiWriterOut(buf, tempFile)
   434  			SetMultiWriterErr(errBuf, tempFile)
   435  
   436  			// Call the function we want to test
   437  			rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   438  			assert.NoError(t, CaptureVerrazzanoManagedCluster(dynamicClient, captureDir, rc))
   439  
   440  			// Check if the VMC JSON file exists in the cluster snapshot as expected
   441  			expectedFilePath := filepath.Join(captureDir, vzconstants.VerrazzanoMultiClusterNamespace, constants.VmcJSON)
   442  			_, err = os.Stat(expectedFilePath)
   443  			if len(tt.vmcs) == 0 {
   444  				assert.Error(t, err)
   445  			} else {
   446  				assert.NoError(t, err)
   447  				vmcList := &clusterv1alpha1.VerrazzanoManagedClusterList{}
   448  				bytesToUnmarshall, err := returnBytesFromAFile(expectedFilePath)
   449  				assert.NoError(t, err)
   450  				assert.NoError(t, json.Unmarshal(bytesToUnmarshall, vmcList))
   451  				assert.Len(t, vmcList.Items, len(tt.vmcs),
   452  					"the file %s did not have the expected number of VerrazzanoManagedCluster resources listed", expectedFilePath)
   453  			}
   454  		})
   455  	}
   456  }
   457  
   458  // TestDoesNamespaceExist tests the functionality to check if a given namespace exists.
   459  func TestDoesNamespaceExist(t *testing.T) {
   460  	buf := new(bytes.Buffer)
   461  	errBuf := new(bytes.Buffer)
   462  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   463  	tempFile, _ := os.CreateTemp("", "testfile")
   464  	defer cleanupFile(t, tempFile)
   465  	SetMultiWriterOut(buf, tempFile)
   466  	SetMultiWriterErr(errBuf, tempFile)
   467  	SetVerboseOutput(true)
   468  
   469  	//  GIVEN a k8s cluster with no namespaces,
   470  	//	WHEN I call functions to check if a namespace with empty string exists,
   471  	//	THEN expect it to return false and no error.
   472  	exists, err := DoesNamespaceExist(k8sfake.NewSimpleClientset(), "", rc)
   473  	assert.NoError(t, err)
   474  	assert.False(t, exists)
   475  
   476  	//  GIVEN a k8s cluster with no namespaces,
   477  	//	WHEN I call functions to check if a namespace verrazzano-install exists,
   478  	//	THEN expect it to return false and an error.
   479  	exists, err = DoesNamespaceExist(k8sfake.NewSimpleClientset(), constants.VerrazzanoInstall, rc)
   480  	assert.Error(t, err)
   481  	assert.False(t, exists)
   482  
   483  	//  GIVEN a k8s cluster with the required verrazzano-install namespace,
   484  	//	WHEN I call functions to check if a namespace verrazzano-install exists,
   485  	//	THEN expect it to return true and no error.
   486  	exists, err = DoesNamespaceExist(k8sfake.NewSimpleClientset(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
   487  		Name: constants.VerrazzanoInstall,
   488  	}}), constants.VerrazzanoInstall, rc)
   489  	assert.NoError(t, err)
   490  	assert.True(t, exists)
   491  }
   492  
   493  // TestGetVZManagedNamespaces tests the functionality to return all namespaces managed by verrazzano
   494  func TestGetVZManagedNamespaces(t *testing.T) {
   495  	namespaces := GetVZManagedNamespaces(k8sfake.NewSimpleClientset())
   496  	assert.Empty(t, namespaces)
   497  
   498  	//  GIVEN a k8s cluster with the required verrazzano-install namespace with label verrazzano-managed=true,
   499  	//	WHEN I call functions to list the namespaces that are managed by Verrazzano,
   500  	//	THEN expect it to return a single namespace verrazzano-install
   501  	namespaces = GetVZManagedNamespaces(k8sfake.NewSimpleClientset(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
   502  		Name:   constants.VerrazzanoInstall,
   503  		Labels: map[string]string{"verrazzano-managed": "true"},
   504  	}}))
   505  	assert.NotEmpty(t, namespaces)
   506  	assert.Equal(t, 1, len(namespaces))
   507  	assert.Equal(t, constants.VerrazzanoInstall, namespaces[0])
   508  }
   509  
   510  // TestIsErrorReported tests the functionality to see if an error had been reported when capturing the k8s resources.
   511  func TestIsErrorReported(t *testing.T) {
   512  	assert.False(t, IsErrorReported())
   513  	LogError("dummy error msg")
   514  	assert.True(t, IsErrorReported())
   515  }
   516  
   517  // TestCreateFile tests the functionality to create a file containing the Verrazzano Resource
   518  func TestCreateFile(t *testing.T) {
   519  	//  GIVEN a k8s cluster with a VPO pod,
   520  	//	WHEN I call functions to create a JSON file for the pod,
   521  	//	THEN expect it to write to the provided resource file, the JSON contents of the pod and no error should be returned.
   522  	captureDir, err := os.MkdirTemp("", "testcapture")
   523  	defer cleanupTempDir(t, captureDir)
   524  	assert.NoError(t, err)
   525  	defer cleanupTempDir(t, captureDir)
   526  	buf := new(bytes.Buffer)
   527  	errBuf := new(bytes.Buffer)
   528  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   529  	err = createFile(corev1.Pod{ObjectMeta: metav1.ObjectMeta{
   530  		Name:      constants.VerrazzanoPlatformOperator,
   531  		Namespace: constants.VerrazzanoInstall,
   532  	}}, constants.VerrazzanoInstall, "test-file", captureDir, rc)
   533  	assert.NoError(t, err)
   534  }
   535  
   536  // cleanupTempDir cleans up the given temp directory after the test run
   537  func cleanupTempDir(t *testing.T, dirName string) {
   538  	if err := os.RemoveAll(dirName); err != nil {
   539  		t.Fatalf("RemoveAll failed: %v", err)
   540  	}
   541  }
   542  
   543  // cleanupTempDir cleans up the given temp file after the test run
   544  func cleanupFile(t *testing.T, file *os.File) {
   545  	if err := file.Close(); err != nil {
   546  		t.Fatalf("RemoveAll failed: %v", err)
   547  	}
   548  }
   549  
   550  // TestGetPodListAll tests the functionality to return the list of all pods
   551  func TestGetPodListAll(t *testing.T) {
   552  	nsName := "test"
   553  	podLength := 5
   554  	var podList []client.Object
   555  	for i := 0; i < podLength; i++ {
   556  		podList = append(podList, &corev1.Pod{
   557  			ObjectMeta: metav1.ObjectMeta{
   558  				Name:      nsName + fmt.Sprint(i),
   559  				Namespace: nsName,
   560  				Labels:    map[string]string{"name": "myapp"},
   561  			},
   562  		})
   563  	}
   564  	//  GIVEN a k8s cluster with no pods,
   565  	//	WHEN I call functions to get the list of pods in the k8s cluster,
   566  	//	THEN expect it to be an empty list.
   567  	pods, err := GetPodListAll(fake.NewClientBuilder().Build(), nsName)
   568  	assert.NoError(t, err)
   569  	assert.Empty(t, pods)
   570  
   571  	//  GIVEN a k8s cluster with 5 pods,
   572  	//	WHEN I call functions to get the list of pods in the k8s cluster without label,
   573  	//	THEN expect it to be list all pods.
   574  	pods, err = GetPodListAll(fake.NewClientBuilder().WithObjects(podList...).Build(), nsName)
   575  	assert.NoError(t, err)
   576  	assert.Equal(t, podLength, len(pods))
   577  }
   578  
   579  // TestCreateInnoDBClusterFile tests that a InnoDBCluster file titled inno-db-cluster.json can be successfully written
   580  // GIVEN a k8s cluster with a inno-db-cluster resources present in a namespace,
   581  // WHEN I call functions to create a list of inno-db-cluster resources for the namespace
   582  // THEN expect it to write to the provided resource file and no error should be returned
   583  func TestCreateInnoDBClusterFile(t *testing.T) {
   584  	schemeForClient := runtime.NewScheme()
   585  	innoDBClusterGVK := schema.GroupVersionKind{
   586  		Group:   "mysql.oracle.com",
   587  		Version: "v2",
   588  		Kind:    "InnoDBCluster",
   589  	}
   590  	innoDBCluster := unstructured.Unstructured{}
   591  	innoDBCluster.SetGroupVersionKind(innoDBClusterGVK)
   592  	innoDBCluster.SetNamespace("keycloak")
   593  	innoDBCluster.SetName("my-sql")
   594  	innoDBClusterStatusFields := []string{"status", "cluster", "status"}
   595  	err := unstructured.SetNestedField(innoDBCluster.Object, "ONLINE", innoDBClusterStatusFields...)
   596  	assert.NoError(t, err)
   597  	metav1Time := metav1.Time{
   598  		Time: time.Now().UTC(),
   599  	}
   600  	innoDBCluster.SetDeletionTimestamp(&metav1Time)
   601  	cli := fake.NewClientBuilder().WithScheme(schemeForClient).WithObjects(&innoDBCluster).Build()
   602  	captureDir, err := os.MkdirTemp("", "testcaptureforinnodbclusters")
   603  	assert.Nil(t, err)
   604  	buf := new(bytes.Buffer)
   605  	errBuf := new(bytes.Buffer)
   606  	tempFile, err := os.CreateTemp(captureDir, "temporary-log-file-for-test")
   607  	assert.NoError(t, err)
   608  	SetMultiWriterOut(buf, tempFile)
   609  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   610  	err = captureInnoDBClusterResources(cli, "keycloak", captureDir, rc)
   611  	assert.NoError(t, err)
   612  	innoDBClusterLocation := filepath.Join(captureDir, "keycloak", constants.InnoDBClusterJSON)
   613  	innoDBClusterListToUnmarshalInto := unstructured.UnstructuredList{}
   614  	bytesToUnmarshall, err := returnBytesFromAFile(innoDBClusterLocation)
   615  	assert.NoError(t, err)
   616  	innoDBClusterListToUnmarshalInto.UnmarshalJSON(bytesToUnmarshall)
   617  	assert.NoError(t, err)
   618  	innoDBClusterResource := innoDBClusterListToUnmarshalInto.Items[0]
   619  	statusOfCluster, _, err := unstructured.NestedString(innoDBClusterResource.Object, "status", "cluster", "status")
   620  	assert.NoError(t, err)
   621  	assert.Equal(t, statusOfCluster, "ONLINE")
   622  
   623  }
   624  
   625  //		TestCreateCertificateFile tests that a certificate file titled certificates.json can be successfully written
   626  //	 	GIVEN a k8s cluster with certificates present in a namespace,
   627  //		WHEN I call functions to create a list of certificates for the namespace,
   628  //		THEN expect it to write to the provided resource file and no error should be returned.
   629  func TestCreateCertificateFile(t *testing.T) {
   630  	schemeForClient := k8scheme.Scheme
   631  	err := certmanagerv1.AddToScheme(schemeForClient)
   632  	assert.NoError(t, err)
   633  	sampleCert := certmanagerv1.Certificate{
   634  		ObjectMeta: metav1.ObjectMeta{Name: "testcertificate", Namespace: "cattle-system"},
   635  		Spec: certmanagerv1.CertificateSpec{
   636  			DNSNames:    []string{"example.com", "www.example.com", "api.example.com"},
   637  			IPAddresses: []string{dummyIP1, dummyIP2},
   638  		},
   639  	}
   640  	client := fake.NewClientBuilder().WithScheme(schemeForClient).WithObjects(&sampleCert).Build()
   641  	captureDir, err := os.MkdirTemp("", "testcaptureforcertificates")
   642  	assert.NoError(t, err)
   643  	t.Log(captureDir)
   644  	defer cleanupTempDir(t, captureDir)
   645  	buf := new(bytes.Buffer)
   646  	errBuf := new(bytes.Buffer)
   647  	tempFile, err := os.CreateTemp(captureDir, "temporary-log-file-for-test")
   648  	assert.NoError(t, err)
   649  	SetMultiWriterOut(buf, tempFile)
   650  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   651  	err = captureCertificates(client, "cattle-system", captureDir, rc)
   652  	assert.NoError(t, err)
   653  }
   654  
   655  // TestCreateCaCrtInfoFile tests that a caCrtInfo file titled caCrtInfo.json can be successfully written
   656  // GIVEN a k8s cluster with secrets containing caCrtInfo present in a namespace  ,
   657  // WHEN I call functions to create a list of caCrt for the namespace,
   658  // THEN expect it to write to the provided resource file and no error should be returned.
   659  func TestCreateCaCrtJsonFile(t *testing.T) {
   660  	schemeForClient := k8scheme.Scheme
   661  	err := certmanagerv1.AddToScheme(schemeForClient)
   662  	assert.NoError(t, err)
   663  	certificateListForTest := certmanagerv1.CertificateList{}
   664  	sampleCert := certmanagerv1.Certificate{
   665  		ObjectMeta: metav1.ObjectMeta{Name: "test-certificate-caCrt.json", Namespace: "cattle-system"},
   666  		Spec: certmanagerv1.CertificateSpec{
   667  			DNSNames:    []string{"example.com", "www.example.com", "api.example.com"},
   668  			IPAddresses: []string{dummyIP1, dummyIP2},
   669  			SecretName:  "test-secret-name",
   670  		},
   671  	}
   672  	certificateListForTest.Items = append(certificateListForTest.Items, sampleCert)
   673  	sampleSecret := corev1.Secret{
   674  		ObjectMeta: metav1.ObjectMeta{Name: "test-secret-name", Namespace: "cattle-system"},
   675  		Data: map[string][]byte{
   676  			"ca.crt": []byte("-----BEGIN CERTIFICATE-----\nMIIDvTCCAqWgAwIBAgIUJUr+YG3UuQJh6g4MKuRpZPnTVO0wDQYJKoZIhvcNAQEL\nBQAwbTELMAkGA1UEBhMCUEExDTALBgNVBAgMBFRlc3QxDTALBgNVBAcMBFRlc3Qx\nDTALBgNVBAoMBFRlc3QxDTALBgNVBAsMBFRlc3QxDTALBgNVBAMMBFRlc3QxEzAR\nBgkqhkiG9w0BCQEWBFRlc3QwIBcNMjMwODMwMTkxMjE4WhgPMzAyMjEyMzExOTEy\nMThaMG0xCzAJBgNVBAYTAlBBMQ0wCwYDVQQIDARUZXN0MQ0wCwYDVQQHDARUZXN0\nMQ0wCwYDVQQKDARUZXN0MQ0wCwYDVQQLDARUZXN0MQ0wCwYDVQQDDARUZXN0MRMw\nEQYJKoZIhvcNAQkBFgRUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\nAQEA5R5EAPbPhrfRnpGtC49OX9q4XDVP11C/nHZ13z4QMPQn3eD+S5DODjo95wVD\nbZlmOUdGhas037W/G4rsEr+fg2DF3tNV3bNtDU5NG+PjRDcmFDKup0q7Lh7Yf2FP\naNxi6wlIgmm8Yi4lQmaBSN5LZalIbTO+tk7PRa1FY2LCIKDzzY9ipc0h9nDQWXIz\nEUtjQdQuZsdcv+br2L6b891Pu/fiZgJg1Vzx8N9bBbxMl3usI/CT8qmJy4E9fh4q\n0LQMFcOXeVSR4dhGLpctXP82AH2wgz0mLmgXlYe3koX+TlOxGIG3tUKBndvII8wm\nO03wILuk63XhXg30EFjpj0qZiQIDAQABo1MwUTAdBgNVHQ4EFgQUxkWW0nvivNEy\nLAPMJYgNwpSHQ5IwHwYDVR0jBBgwFoAUxkWW0nvivNEyLAPMJYgNwpSHQ5IwDwYD\nVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAtUjYhkDzJoFNx84Y9KXJ\nVM5BRtiI7YuvrKujwFmct1uCDEDXxZivwDf7khbUlI/GDg13LXsHQbxRaZNotcju\nibG9DNwInlBDpJ/grjlz/KG/LCmYrQE5RAnuqxVe812pc2ndSkTOGvcds7n7Gir/\n1S6zn2d5g2KeYtaMEYV1jArjzsFIdZ4M2R0ZTAsArcJy2ZGZ655j54Df7yzviNpD\nTz6nQQv1DHEpdogys+rOUTXrVhSpnsTacwztp/lvQsZl231THlCJcsySHRgMKmB+\nRKLLMfDfIaGeiZWRvEPEdurMWYkwWdYz9d+iEo3YTpWKy2QeCOEFZKMX5B2MXkdd\nNA==\n-----END CERTIFICATE-----\n"),
   677  		},
   678  	}
   679  	client := fake.NewClientBuilder().WithScheme(schemeForClient).WithObjects(&sampleCert, &sampleSecret).Build()
   680  	captureDir, err := os.MkdirTemp("", "testcaptureforcaCrt.json")
   681  	assert.NoError(t, err)
   682  	t.Log(captureDir)
   683  	defer cleanupTempDir(t, captureDir)
   684  	buf := new(bytes.Buffer)
   685  	errBuf := new(bytes.Buffer)
   686  	tempFile, err := os.CreateTemp(captureDir, "temporary-log-file-for-ca-crt-test")
   687  	assert.NoError(t, err)
   688  	SetMultiWriterOut(buf, tempFile)
   689  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   690  	err = captureCaCrtExpirationInfo(client, certificateListForTest, "cattle-system", captureDir, rc)
   691  	assert.NoError(t, err)
   692  }
   693  
   694  // TestRedactHostNamesForCertificates tests the captureCertificates function
   695  // GIVEN when sample cert with DNSNames and IPAddresses which are sensitive information
   696  // WHEN captureCertificates is called on certain namespace
   697  // THEN it should obfuscate the known hostnames with hashed value
   698  // AND the output certificates.json file should NOT contain any of the sensitive information from KnownHostNames
   699  func TestRedactHostNamesForCertificates(t *testing.T) {
   700  	sampleCert := &certmanagerv1.Certificate{
   701  		ObjectMeta: metav1.ObjectMeta{
   702  			Name:      "test-certificate",
   703  			Namespace: "cattle-system",
   704  		},
   705  		Spec: certmanagerv1.CertificateSpec{
   706  			DNSNames:    []string{"example.com", "www.example.com", "api.example.com"},
   707  			IPAddresses: []string{dummyIP1, dummyIP2},
   708  		},
   709  	}
   710  
   711  	schemeForClient := k8scheme.Scheme
   712  	err := certmanagerv1.AddToScheme(schemeForClient)
   713  	assert.NoError(t, err)
   714  	client := fake.NewClientBuilder().WithScheme(schemeForClient).WithObjects(sampleCert).Build()
   715  	captureDir, err := os.MkdirTemp("", "testcaptureforcertificates")
   716  	assert.NoError(t, err)
   717  	t.Log(captureDir)
   718  	defer cleanupTempDir(t, captureDir)
   719  	buf := new(bytes.Buffer)
   720  	errBuf := new(bytes.Buffer)
   721  	tempFile, err := os.CreateTemp(captureDir, "temporary-log-file-for-test")
   722  	assert.NoError(t, err)
   723  	SetMultiWriterOut(buf, tempFile)
   724  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   725  
   726  	err = captureCertificates(client, common.CattleSystem, captureDir, rc)
   727  	assert.NoError(t, err)
   728  
   729  	// Check if the file is Sanitized as expected
   730  	certLocation := filepath.Join(captureDir, common.CattleSystem, constants.CertificatesJSON)
   731  	f, err := os.ReadFile(certLocation)
   732  	assert.NoError(t, err, "Should not error reading certificates.json file")
   733  	for k := range KnownHostNames {
   734  		keyMatch, err := regexp.Match(k, f)
   735  		assert.NoError(t, err, "Error while regex matching")
   736  		assert.Falsef(t, keyMatch, "%s should be obfuscated from certificates.json file %s", k, string(f))
   737  	}
   738  }
   739  
   740  // TestCreateParentsIfNecessary tests that parent directories are only created when intended
   741  // GIVEN a temporary directory and a string representing a filePath  ,
   742  // WHEN I call a function to create a parent directory
   743  // THEN expect it to only create the parent directories if it does not exist and if the file path contains a "/"
   744  func TestCreateParentsIfNecessary(t *testing.T) {
   745  	err := os.Mkdir(constants.TestDirectory, 0700)
   746  	defer os.RemoveAll(constants.TestDirectory)
   747  	assert.Nil(t, err)
   748  	createParentsIfNecessary(constants.TestDirectory, "files.txt")
   749  	createParentsIfNecessary(constants.TestDirectory, "cluster-snapshot/files.txt")
   750  	_, err = os.Stat(constants.TestDirectory + "/files.txt")
   751  	assert.NotNil(t, err)
   752  	_, err = os.Stat(constants.TestDirectory + "/cluster-snapshot")
   753  	assert.Nil(t, err)
   754  
   755  }
   756  
   757  // TestCreateNamespaceFile tests that a namespace file titled namespace.json can be successfully written
   758  // GIVEN a k8s cluster,
   759  // WHEN I call functions to get the namespace resource for that namespace
   760  // THEN expect it to write to the provided resource file with the correct information and no error should be returned.
   761  func TestCreateNamespaceFile(t *testing.T) {
   762  	listOfFinalizers := []corev1.FinalizerName{"test-finalizer-name"}
   763  	sampleNamespace := corev1.Namespace{
   764  		ObjectMeta: metav1.ObjectMeta{
   765  			Name: "test-namespace",
   766  		},
   767  		Spec: corev1.NamespaceSpec{
   768  			Finalizers: listOfFinalizers,
   769  		},
   770  		Status: corev1.NamespaceStatus{
   771  			Phase: corev1.NamespaceTerminating,
   772  		},
   773  	}
   774  	client := k8sfake.NewSimpleClientset(&sampleNamespace)
   775  	captureDir, err := os.MkdirTemp("", "testcapturefornamespaces")
   776  	assert.NoError(t, err)
   777  	t.Log(captureDir)
   778  	defer cleanupTempDir(t, captureDir)
   779  	buf := new(bytes.Buffer)
   780  	errBuf := new(bytes.Buffer)
   781  	tempFile, err := os.CreateTemp(captureDir, "temporary-log-file-for-test")
   782  	assert.NoError(t, err)
   783  	SetMultiWriterOut(buf, tempFile)
   784  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   785  	err = captureNamespaces(client, "test-namespace", captureDir, rc)
   786  	assert.NoError(t, err)
   787  	namespaceLocation := filepath.Join(captureDir, "test-namespace", constants.NamespaceJSON)
   788  	namespaceObjectToUnmarshalInto := &corev1.Namespace{}
   789  	err = unmarshallFile(namespaceLocation, namespaceObjectToUnmarshalInto)
   790  	assert.NoError(t, err)
   791  	assert.True(t, namespaceObjectToUnmarshalInto.Status.Phase == corev1.NamespaceTerminating)
   792  }
   793  
   794  // TestCreateMetadataFile tests that a metadata file titled metadata.json can be successfully written
   795  // GIVEN a k8s cluster,
   796  // WHEN I call functions to record the metadata for the capture
   797  // THEN expect it to write to the correct resource file with the correct information and no error should be returned.
   798  func TestCreateMetadataFile(t *testing.T) {
   799  	captureDir, err := os.MkdirTemp("", "testcaptureformetadata")
   800  	assert.NoError(t, err)
   801  	t.Log(captureDir)
   802  	defer cleanupTempDir(t, captureDir)
   803  	buf := new(bytes.Buffer)
   804  	errBuf := new(bytes.Buffer)
   805  	tempFile, err := os.CreateTemp(captureDir, "temporary-log-file-for-test")
   806  	assert.NoError(t, err)
   807  	SetMultiWriterOut(buf, tempFile)
   808  	SetMultiWriterErr(errBuf, tempFile)
   809  	err = CaptureMetadata(captureDir)
   810  	assert.NoError(t, err)
   811  	metadataLocation := filepath.Join(captureDir, constants.MetadataJSON)
   812  	metadataObjectToUnmarshalInto := &Metadata{}
   813  	err = unmarshallFile(metadataLocation, metadataObjectToUnmarshalInto)
   814  	assert.NoError(t, err)
   815  	timeObject, err := time.Parse(time.RFC3339, metadataObjectToUnmarshalInto.Time)
   816  	assert.NoError(t, err)
   817  	assert.True(t, time.Now().UTC().Sub(timeObject).Minutes() < 60)
   818  
   819  }
   820  
   821  // unmarshallFile is a helper function that is used to place the contents of a file into a defined struct
   822  func unmarshallFile(clusterPath string, object interface{}) error {
   823  	// Parse the json into local struct
   824  	file, err := os.Open(clusterPath)
   825  	if os.IsNotExist(err) {
   826  		// The file may not exist if the component is not installed.
   827  		return nil
   828  	}
   829  	if err != nil {
   830  		return fmt.Errorf("failed to open file %s from cluster snapshot: %s", clusterPath, err.Error())
   831  	}
   832  	defer file.Close()
   833  
   834  	fileBytes, err := io.ReadAll(file)
   835  	if err != nil {
   836  		return fmt.Errorf("Failed reading Json file %s: %s", clusterPath, err.Error())
   837  	}
   838  	// Unmarshall file contents into a struct
   839  	err = json.Unmarshal(fileBytes, object)
   840  	if err != nil {
   841  		return fmt.Errorf("Failed to unmarshal %s: %s", clusterPath, err.Error())
   842  	}
   843  
   844  	return nil
   845  }
   846  
   847  // returnBytesFromAFile is a helper function that returns the bytes of a file
   848  func returnBytesFromAFile(clusterPath string) ([]byte, error) {
   849  	var byteArray = []byte{}
   850  	// Parse the json into local struct
   851  	file, err := os.Open(clusterPath)
   852  	if os.IsNotExist(err) {
   853  		// The file may not exist if the component is not installed.
   854  		return byteArray, nil
   855  	}
   856  	if err != nil {
   857  		return byteArray, fmt.Errorf("failed to open file %s from cluster snapshot: %s", clusterPath, err.Error())
   858  	}
   859  	defer file.Close()
   860  
   861  	byteArray, err = io.ReadAll(file)
   862  	if err != nil {
   863  		return byteArray, fmt.Errorf("Failed reading Json file %s: %s", clusterPath, err.Error())
   864  	}
   865  
   866  	return byteArray, nil
   867  }