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  }