istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/helmreconciler/prune_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package helmreconciler
    16  
    17  import (
    18  	_ "embed"
    19  	"sync"
    20  	"testing"
    21  
    22  	v1 "k8s.io/api/core/v1"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/runtime/schema"
    25  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    26  	"sigs.k8s.io/yaml"
    27  
    28  	"istio.io/api/label"
    29  	"istio.io/istio/operator/pkg/apis/istio/v1alpha1"
    30  	"istio.io/istio/operator/pkg/name"
    31  	"istio.io/istio/operator/pkg/object"
    32  	"istio.io/istio/operator/pkg/util/clog"
    33  	"istio.io/istio/operator/pkg/util/progress"
    34  	"istio.io/istio/pkg/kube"
    35  	"istio.io/istio/pkg/test/util/assert"
    36  )
    37  
    38  var (
    39  	//go:embed testdata/iop-test-gw-1.yaml
    40  	iopTestGwData1 []byte
    41  	//go:embed testdata/iop-test-gw-2.yaml
    42  	iopTestGwData2 []byte
    43  )
    44  
    45  func applyResourcesIntoCluster(t *testing.T, h *HelmReconciler, manifestMap name.ManifestMap) {
    46  	for cn, ms := range manifestMap.Consolidated() {
    47  		objects, err := object.ParseK8sObjectsFromYAMLManifest(ms)
    48  		if err != nil {
    49  			t.Fatalf("failed parse k8s objects from yaml: %v", err)
    50  		}
    51  		for _, obj := range objects {
    52  			obju := obj.UnstructuredObject()
    53  			if err := h.applyLabelsAndAnnotations(obju, cn); err != nil {
    54  				t.Errorf("failed to apply label and annotations: %v", err)
    55  			}
    56  			if err := h.ApplyObject(obj.UnstructuredObject()); err != nil {
    57  				t.Errorf("HelmReconciler.ApplyObject() error = %v", err)
    58  			}
    59  		}
    60  	}
    61  }
    62  
    63  func TestHelmReconciler_GetPrunedResources(t *testing.T) {
    64  	t.Run("get gateway pruned resources", func(t *testing.T) {
    65  		var h1 *HelmReconciler
    66  		cl := fake.NewClientBuilder().WithInterceptorFuncs(interceptorFunc).Build()
    67  		// init two custom gateways with revision
    68  		gateways := [][]byte{iopTestGwData1, iopTestGwData2}
    69  		for i, data := range gateways {
    70  			iop := &v1alpha1.IstioOperator{}
    71  			err := yaml.UnmarshalStrict(data, iop)
    72  			assert.NoError(t, err)
    73  			h := &HelmReconciler{
    74  				client:     cl,
    75  				kubeClient: kube.NewFakeClientWithVersion("24"),
    76  				opts: &Options{
    77  					ProgressLog: progress.NewLog(),
    78  					Log:         clog.NewDefaultLogger(),
    79  				},
    80  				iop:           iop,
    81  				countLock:     &sync.Mutex{},
    82  				prunedKindSet: map[schema.GroupKind]struct{}{},
    83  			}
    84  			if i == 0 {
    85  				h1 = h
    86  			}
    87  			manifestMap, err := h.RenderCharts()
    88  			if err != nil {
    89  				t.Fatalf("failed to render manifest: %v", err)
    90  			}
    91  			applyResourcesIntoCluster(t, h, manifestMap)
    92  		}
    93  		// delete one iop: iop-test-gw-1, get its pruned resources
    94  		componentName := string(name.IngressComponentName)
    95  		resources, err := h1.GetPrunedResources(h1.iop.Spec.Revision, false, componentName)
    96  		assert.NoError(t, err)
    97  		assert.Equal(t, true, len(resources) > 0)
    98  		// check resources, only associated with iop-test-gw-1 istiooperator CR,
    99  		// otherwise, the resources of all IngressGateways components will be deleted.
   100  		// See https://github.com/istio/istio/issues/40577 for more details.
   101  		for _, uslist := range resources {
   102  			for _, u := range uslist.Items {
   103  				assert.Equal(t, h1.iop.Spec.Revision, u.GetLabels()[label.IoIstioRev.Name])
   104  				assert.Equal(t, componentName, u.GetLabels()[IstioComponentLabelStr])
   105  				assert.Equal(t, h1.iop.GetName(), u.GetLabels()[OwningResourceName])
   106  				assert.Equal(t, h1.iop.GetNamespace(), u.GetLabels()[OwningResourceNamespace])
   107  			}
   108  		}
   109  	})
   110  }
   111  
   112  func TestPilotExist(t *testing.T) {
   113  	t.Run("exist", func(t *testing.T) {
   114  		cl := fake.NewClientBuilder().WithInterceptorFuncs(interceptorFunc).Build()
   115  		iop := &v1alpha1.IstioOperator{}
   116  		h := &HelmReconciler{
   117  			client:     cl,
   118  			kubeClient: kube.NewFakeClientWithVersion("24"),
   119  			opts: &Options{
   120  				ProgressLog: progress.NewLog(),
   121  				Log:         clog.NewDefaultLogger(),
   122  			},
   123  			iop:           iop,
   124  			countLock:     &sync.Mutex{},
   125  			prunedKindSet: map[schema.GroupKind]struct{}{},
   126  		}
   127  		mockClient := kube.NewFakeClient(&v1.Pod{
   128  			ObjectMeta: metav1.ObjectMeta{
   129  				Name:      "istiod",
   130  				Namespace: "istio-system",
   131  				Labels:    map[string]string{"app": "istiod"},
   132  			},
   133  		})
   134  
   135  		if exist, err := h.pilotExists(mockClient, "istio-system"); err != nil {
   136  			t.Fatalf("HelmReconciler.pilotExists error = %v", err)
   137  		} else if !exist {
   138  			t.Errorf("HelmReconciler.pilotExists fail")
   139  		}
   140  	})
   141  
   142  	t.Run("non-exist", func(t *testing.T) {
   143  		cl := fake.NewClientBuilder().WithInterceptorFuncs(interceptorFunc).Build()
   144  		iop := &v1alpha1.IstioOperator{}
   145  		kc := kube.NewFakeClientWithVersion("24")
   146  		h := &HelmReconciler{
   147  			client:     cl,
   148  			kubeClient: kc,
   149  			opts: &Options{
   150  				ProgressLog: progress.NewLog(),
   151  				Log:         clog.NewDefaultLogger(),
   152  			},
   153  			iop:           iop,
   154  			countLock:     &sync.Mutex{},
   155  			prunedKindSet: map[schema.GroupKind]struct{}{},
   156  		}
   157  		if exist, err := h.pilotExists(kc, "istio-system"); err != nil {
   158  			t.Fatalf("HelmReconciler.pilotExists error = %v", err)
   159  		} else if exist {
   160  			t.Errorf("HelmReconciler.pilotExists fail")
   161  		}
   162  	})
   163  }