istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/framework/components/istio/cleanup.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 istio
    16  
    17  import (
    18  	"context"
    19  	"regexp"
    20  	"time"
    21  
    22  	"github.com/hashicorp/go-multierror"
    23  	"golang.org/x/sync/errgroup"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  
    26  	"istio.io/istio/pkg/test/framework/components/cluster"
    27  	"istio.io/istio/pkg/test/framework/resource"
    28  	kube2 "istio.io/istio/pkg/test/kube"
    29  	"istio.io/istio/pkg/test/scopes"
    30  	"istio.io/istio/pkg/test/util/yml"
    31  )
    32  
    33  func (i *istioImpl) Close() error {
    34  	t0 := time.Now()
    35  	scopes.Framework.Infof("=== BEGIN: Cleanup Istio [Suite=%s] ===", i.ctx.Settings().TestID)
    36  
    37  	// Write time spent for cleanup and deploy to ARTIFACTS/trace.yaml and logs to allow analyzing test times
    38  	defer func() {
    39  		delta := time.Since(t0)
    40  		i.ctx.RecordTraceEvent("istio-cleanup", delta.Seconds())
    41  		scopes.Framework.Infof("=== SUCCEEDED: Cleanup Istio in %v [Suite=%s] ===", delta, i.ctx.Settings().TestID)
    42  	}()
    43  
    44  	if i.cfg.DumpKubernetesManifests {
    45  		i.installer.Dump(i.ctx)
    46  	}
    47  
    48  	if i.cfg.DeployIstio {
    49  		errG := multierror.Group{}
    50  		// Make sure to clean up primary clusters before remotes, or istiod will recreate some of the CMs that we delete
    51  		// in the remote clusters before it's deleted.
    52  		for _, c := range i.ctx.AllClusters().Primaries().Kube() {
    53  			i.cleanupCluster(c, &errG)
    54  		}
    55  		for _, c := range i.ctx.Clusters().Remotes().Kube() {
    56  			i.cleanupCluster(c, &errG)
    57  		}
    58  		return errG.Wait().ErrorOrNil()
    59  	}
    60  	for _, f := range i.istiod {
    61  		f.Close()
    62  	}
    63  	return nil
    64  }
    65  
    66  func (i *istioImpl) Dump(ctx resource.Context) {
    67  	scopes.Framework.Errorf("=== Dumping Istio Deployment State for %v...", ctx.ID())
    68  	ns := i.cfg.SystemNamespace
    69  	d, err := ctx.CreateTmpDirectory("istio-state")
    70  	if err != nil {
    71  		scopes.Framework.Errorf("Unable to create directory for dumping Istio contents: %v", err)
    72  		return
    73  	}
    74  	g := errgroup.Group{}
    75  	g.Go(func() error {
    76  		kube2.DumpPods(ctx, d, ns, []string{})
    77  		return nil
    78  	})
    79  
    80  	g.Go(func() error {
    81  		kube2.DumpWebhooks(ctx, d)
    82  		return nil
    83  	})
    84  	for _, c := range ctx.Clusters().Kube().Primaries() {
    85  		c := c
    86  		g.Go(func() error {
    87  			kube2.DumpDebug(ctx, c, d, "configz", ns)
    88  			return nil
    89  		})
    90  		g.Go(func() error {
    91  			kube2.DumpDebug(ctx, c, d, "mcsz", ns)
    92  			return nil
    93  		})
    94  		g.Go(func() error {
    95  			kube2.DumpDebug(ctx, c, d, "clusterz", ns)
    96  			return nil
    97  		})
    98  	}
    99  	// Dump istio-cni.
   100  	g.Go(func() error {
   101  		kube2.DumpPods(ctx, d, "kube-system", []string{"k8s-app=istio-cni-node"})
   102  		return nil
   103  	})
   104  }
   105  
   106  func (i *istioImpl) cleanupCluster(c cluster.Cluster, errG *multierror.Group) {
   107  	scopes.Framework.Infof("clean up cluster %s", c.Name())
   108  	errG.Go(func() (err error) {
   109  		if e := i.installer.Close(c); e != nil {
   110  			err = multierror.Append(err, e)
   111  		}
   112  
   113  		// Cleanup all secrets and configmaps - these are dynamically created by tests and/or istiod so they are not captured above
   114  		// This includes things like leader election locks (allowing next test to start without 30s delay),
   115  		// custom cacerts, custom kubeconfigs, etc.
   116  		// We avoid deleting the whole namespace since its extremely slow in Kubernetes (30-60s+)
   117  		if e := c.Kube().CoreV1().Secrets(i.cfg.SystemNamespace).DeleteCollection(
   118  			context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{}); e != nil {
   119  			err = multierror.Append(err, e)
   120  		}
   121  		if e := c.Kube().CoreV1().ConfigMaps(i.cfg.SystemNamespace).DeleteCollection(
   122  			context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{}); e != nil {
   123  			err = multierror.Append(err, e)
   124  		}
   125  		// Delete validating and mutating webhook configurations. These can be created outside of generated manifests
   126  		// when installing with istioctl and must be deleted separately.
   127  		if e := c.Kube().AdmissionregistrationV1().ValidatingWebhookConfigurations().DeleteCollection(
   128  			context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{}); e != nil {
   129  			err = multierror.Append(err, e)
   130  		}
   131  		if e := c.Kube().AdmissionregistrationV1().MutatingWebhookConfigurations().DeleteCollection(
   132  			context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{}); e != nil {
   133  			err = multierror.Append(err, e)
   134  		}
   135  		return
   136  	})
   137  }
   138  
   139  // When we cleanup, we should not delete CRDs. This will filter out all the crds
   140  func removeCRDs(istioYaml string) string {
   141  	allParts := yml.SplitString(istioYaml)
   142  	nonCrds := make([]string, 0, len(allParts))
   143  
   144  	// Make the regular expression multi-line and anchor to the beginning of the line.
   145  	r := regexp.MustCompile(`(?m)^kind: CustomResourceDefinition$`)
   146  
   147  	for _, p := range allParts {
   148  		if r.MatchString(p) {
   149  			continue
   150  		}
   151  		nonCrds = append(nonCrds, p)
   152  	}
   153  
   154  	return yml.JoinString(nonCrds...)
   155  }