istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/cmd/mesh/operator-remove.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 mesh 16 17 import ( 18 "fmt" 19 "os" 20 21 "github.com/fatih/color" 22 "github.com/spf13/cobra" 23 24 "istio.io/api/operator/v1alpha1" 25 "istio.io/istio/istioctl/pkg/cli" 26 iopv1alpha1 "istio.io/istio/operator/pkg/apis/istio/v1alpha1" 27 "istio.io/istio/operator/pkg/helmreconciler" 28 "istio.io/istio/operator/pkg/name" 29 "istio.io/istio/operator/pkg/translate" 30 "istio.io/istio/operator/pkg/util/clog" 31 "istio.io/istio/pkg/kube" 32 ) 33 34 type operatorRemoveArgs struct { 35 // skipConfirmation determines whether the user is prompted for confirmation. 36 // If set to true, the user is not prompted and a Yes response is assumed in all cases. 37 skipConfirmation bool 38 // force proceeds even if there are validation errors 39 force bool 40 // operatorNamespace is the namespace the operator controller is installed into. 41 operatorNamespace string 42 // revision is the Istio control plane revision the command targets. 43 revision string 44 // purge if set to true, all revisions of Istio operator will be specified. 45 purge bool 46 } 47 48 func addOperatorRemoveFlags(cmd *cobra.Command, oiArgs *operatorRemoveArgs) { 49 cmd.PersistentFlags().BoolVarP(&oiArgs.skipConfirmation, "skip-confirmation", "y", false, skipConfirmationFlagHelpStr) 50 cmd.PersistentFlags().BoolVar(&oiArgs.force, "force", false, ForceFlagHelpStr) 51 cmd.PersistentFlags().StringVar(&oiArgs.operatorNamespace, "operatorNamespace", operatorDefaultNamespace, OperatorNamespaceHelpstr) 52 cmd.PersistentFlags().StringVarP(&oiArgs.revision, "revision", "r", "", OperatorRevFlagHelpStr) 53 cmd.PersistentFlags().BoolVar(&oiArgs.purge, "purge", false, AllOperatorRevFlagHelpStr) 54 } 55 56 func operatorRemoveCmd(ctx cli.Context, rootArgs *RootArgs, orArgs *operatorRemoveArgs) *cobra.Command { 57 return &cobra.Command{ 58 Use: "remove", 59 Short: "Removes the Istio operator controller from the cluster.", 60 Long: "The remove subcommand removes the Istio operator controller from the cluster.", 61 Args: func(cmd *cobra.Command, args []string) error { 62 if orArgs.revision == "" && !orArgs.purge { 63 return fmt.Errorf("at least one of the --revision or --purge flags must be set") 64 } 65 if len(args) > 0 { 66 return fmt.Errorf("istioctl operator remove does not take arguments") 67 } 68 return nil 69 }, 70 RunE: func(cmd *cobra.Command, args []string) error { 71 client, err := ctx.CLIClient() 72 if err != nil { 73 return err 74 } 75 l := clog.NewConsoleLogger(cmd.OutOrStdout(), cmd.OutOrStderr(), installerScope) 76 operatorRemove(cmd, client, rootArgs, orArgs, l) 77 return nil 78 }, 79 } 80 } 81 82 // operatorRemove removes the Istio operator controller from the cluster. 83 func operatorRemove(cmd *cobra.Command, cliClient kube.CLIClient, args *RootArgs, orArgs *operatorRemoveArgs, l clog.Logger) { 84 kubeClient, client, err := KubernetesClients(cliClient, l) 85 if err != nil { 86 l.LogAndFatal(err) 87 } 88 89 // If the user is performing purge but also specified a revision, we should warn 90 // that the purge will still remove all resources 91 if orArgs.purge && orArgs.revision != "" { 92 orArgs.revision = "" 93 l.LogAndPrint("Purge remove will remove all Istio operator controller, ignoring the specified revision\n") 94 } 95 96 var installed bool 97 if orArgs.revision == "default" { 98 installed, err = isControllerInstalled(kubeClient.Kube(), orArgs.operatorNamespace, "") 99 } else { 100 installed, err = isControllerInstalled(kubeClient.Kube(), orArgs.operatorNamespace, orArgs.revision) 101 } 102 103 if installed && err != nil { 104 l.LogAndFatal(err) 105 } 106 if !installed && !orArgs.purge { 107 l.LogAndPrintf("Operator controller is not installed in %s namespace (no Deployment detected).", orArgs.operatorNamespace) 108 if !orArgs.force { 109 l.LogAndFatal("Aborting, use --force to override.") 110 } 111 } 112 113 var message string 114 message = "All revisions of Istio operator will be removed from cluster, Proceed? (y/N)" 115 if orArgs.revision != "" { 116 message = "Istio operator revision " + orArgs.revision + " will be removed from cluster, Proceed? (y/N)" 117 } 118 if !orArgs.skipConfirmation && !args.DryRun && !Confirm(message, cmd.OutOrStdout()) { 119 cmd.Print("Cancelled.\n") 120 os.Exit(1) 121 } 122 123 l.LogAndPrintf("Removing Istio operator...") 124 // Create an empty IOP for the purpose of populating revision. Apply code requires a non-nil IOP. 125 var iop *iopv1alpha1.IstioOperator 126 if orArgs.revision != "" { 127 emptyiops := &v1alpha1.IstioOperatorSpec{Profile: "empty", Revision: orArgs.revision} 128 iop, err = translate.IOPStoIOP(emptyiops, "", "") 129 if err != nil { 130 l.LogAndFatal(err) 131 } 132 } 133 reconciler, err := helmreconciler.NewHelmReconciler(client, kubeClient, iop, &helmreconciler.Options{DryRun: args.DryRun, Log: l}) 134 if err != nil { 135 l.LogAndFatal(err) 136 } 137 rs, err := reconciler.GetPrunedResources(orArgs.revision, false, string(name.IstioOperatorComponentName)) 138 if err != nil { 139 l.LogAndFatal(err) 140 } 141 if err := reconciler.DeleteObjectsList(rs, string(name.IstioOperatorComponentName)); err != nil { 142 l.LogAndFatal(err) 143 } 144 145 l.LogAndPrint(color.New(color.FgGreen).Sprint("✔ ") + "Removal complete") 146 }