istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/tag/util.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 tag 16 17 import ( 18 "context" 19 "fmt" 20 21 "github.com/hashicorp/go-multierror" 22 admitv1 "k8s.io/api/admissionregistration/v1" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/client-go/kubernetes" 25 26 "istio.io/api/label" 27 "istio.io/istio/istioctl/pkg/util" 28 ) 29 30 func GetRevisionWebhooks(ctx context.Context, client kubernetes.Interface) ([]admitv1.MutatingWebhookConfiguration, error) { 31 webhooks, err := client.AdmissionregistrationV1().MutatingWebhookConfigurations().List(ctx, metav1.ListOptions{ 32 LabelSelector: label.IoIstioRev.Name, 33 }) 34 if err != nil { 35 return nil, err 36 } 37 return webhooks.Items, nil 38 } 39 40 // GetWebhooksWithTag returns webhooks tagged with istio.io/tag=<tag>. 41 func GetWebhooksWithTag(ctx context.Context, client kubernetes.Interface, tag string) ([]admitv1.MutatingWebhookConfiguration, error) { 42 webhooks, err := client.AdmissionregistrationV1().MutatingWebhookConfigurations().List(ctx, metav1.ListOptions{ 43 LabelSelector: fmt.Sprintf("%s=%s", IstioTagLabel, tag), 44 }) 45 if err != nil { 46 return nil, err 47 } 48 return webhooks.Items, nil 49 } 50 51 // GetWebhooksWithRevision returns webhooks tagged with istio.io/rev=<rev> and NOT TAGGED with istio.io/tag. 52 // this retrieves the webhook created at revision installation rather than tag webhooks 53 func GetWebhooksWithRevision(ctx context.Context, client kubernetes.Interface, rev string) ([]admitv1.MutatingWebhookConfiguration, error) { 54 webhooks, err := client.AdmissionregistrationV1().MutatingWebhookConfigurations().List(ctx, metav1.ListOptions{ 55 LabelSelector: fmt.Sprintf("%s=%s,!%s", label.IoIstioRev.Name, rev, IstioTagLabel), 56 }) 57 if err != nil { 58 return nil, err 59 } 60 return webhooks.Items, nil 61 } 62 63 // GetNamespacesWithTag retrieves all namespaces pointed at the given tag. 64 func GetNamespacesWithTag(ctx context.Context, client kubernetes.Interface, tag string) ([]string, error) { 65 namespaces, err := client.CoreV1().Namespaces().List(ctx, metav1.ListOptions{ 66 LabelSelector: fmt.Sprintf("%s=%s", label.IoIstioRev.Name, tag), 67 }) 68 if err != nil { 69 return nil, err 70 } 71 72 nsNames := make([]string, len(namespaces.Items)) 73 for i, ns := range namespaces.Items { 74 nsNames[i] = ns.Name 75 } 76 return nsNames, nil 77 } 78 79 // GetWebhookTagName extracts tag name from webhook object. 80 func GetWebhookTagName(wh admitv1.MutatingWebhookConfiguration) string { 81 return wh.ObjectMeta.Labels[IstioTagLabel] 82 } 83 84 // GetWebhookRevision extracts tag target revision from webhook object. 85 func GetWebhookRevision(wh admitv1.MutatingWebhookConfiguration) (string, error) { 86 if tagName, ok := wh.ObjectMeta.Labels[label.IoIstioRev.Name]; ok { 87 return tagName, nil 88 } 89 return "", fmt.Errorf("could not extract tag revision from webhook") 90 } 91 92 // DeleteTagWebhooks deletes the given webhooks. 93 func DeleteTagWebhooks(ctx context.Context, client kubernetes.Interface, tag string) error { 94 webhooks, err := GetWebhooksWithTag(ctx, client, tag) 95 if err != nil { 96 return err 97 } 98 var result error 99 for _, wh := range webhooks { 100 result = multierror.Append(result, client.AdmissionregistrationV1().MutatingWebhookConfigurations().Delete(ctx, wh.Name, metav1.DeleteOptions{})).ErrorOrNil() 101 } 102 return result 103 } 104 105 // PreviousInstallExists checks whether there is an existing Istio installation. Should be used in installer when deciding 106 // whether to make an installation the default. 107 func PreviousInstallExists(ctx context.Context, client kubernetes.Interface) bool { 108 mwhs, err := client.AdmissionregistrationV1().MutatingWebhookConfigurations().List(ctx, metav1.ListOptions{ 109 LabelSelector: "app=sidecar-injector", 110 }) 111 if err != nil { 112 return false 113 } 114 return len(mwhs.Items) > 0 115 } 116 117 // DeactivateIstioInjectionWebhook deactivates the istio-injection webhook from the given MutatingWebhookConfiguration if exists. 118 // used rather than just deleting the webhook since we want to keep it around after changing the default so user can later 119 // switch back to it. This is a hack but it is meant to cover a corner case where a user wants to migrate from a non-revisioned 120 // old version and then later decides to switch back to the old revision again. 121 func DeactivateIstioInjectionWebhook(ctx context.Context, client kubernetes.Interface) error { 122 whs, err := GetWebhooksWithRevision(ctx, client, DefaultRevisionName) 123 if err != nil { 124 return err 125 } 126 if len(whs) == 0 { 127 // no revision with default, no action required. 128 return nil 129 } 130 if len(whs) > 1 { 131 return fmt.Errorf("expected a single webhook for default revision") 132 } 133 webhook := whs[0] 134 for i := range webhook.Webhooks { 135 wh := webhook.Webhooks[i] 136 // this is an abomination, but if this isn't a per-revision webhook, we want to make it ineffectual 137 // without deleting it. Add a nonsense match. 138 wh.NamespaceSelector = util.NeverMatch 139 wh.ObjectSelector = util.NeverMatch 140 webhook.Webhooks[i] = wh 141 } 142 admit := client.AdmissionregistrationV1().MutatingWebhookConfigurations() 143 _, err = admit.Update(ctx, &webhook, metav1.UpdateOptions{}) 144 if err != nil { 145 return err 146 } 147 148 return nil 149 }