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 }