istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/cmd/mesh/operator-init.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  	"strings"
    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/name"
    28  	"istio.io/istio/operator/pkg/translate"
    29  	operatorutil "istio.io/istio/operator/pkg/util"
    30  	"istio.io/istio/operator/pkg/util/clog"
    31  	"istio.io/istio/pkg/config/constants"
    32  	"istio.io/istio/pkg/config/labels"
    33  	"istio.io/istio/pkg/kube"
    34  	buildversion "istio.io/istio/pkg/version"
    35  )
    36  
    37  type operatorInitArgs struct {
    38  	// inFilenames is the path to the input IstioOperator CR.
    39  	inFilename string
    40  
    41  	// common is shared operator args
    42  	common operatorCommonArgs
    43  }
    44  
    45  // kubeClients is a unit test override variable for client interfaces creation.
    46  var kubeClients = KubernetesClients
    47  
    48  func addOperatorInitFlags(cmd *cobra.Command, args *operatorInitArgs) {
    49  	hub, tag := buildversion.DockerInfo.Hub, buildversion.DockerInfo.Tag
    50  
    51  	cmd.PersistentFlags().StringVarP(&args.inFilename, "filename", "f", "", filenameFlagHelpStr)
    52  	cmd.PersistentFlags().StringVar(&args.common.hub, "hub", hub, HubFlagHelpStr)
    53  	cmd.PersistentFlags().StringVar(&args.common.tag, "tag", tag, TagFlagHelpStr)
    54  	cmd.PersistentFlags().StringSliceVar(&args.common.imagePullSecrets, "imagePullSecrets", nil, ImagePullSecretsHelpStr)
    55  	cmd.PersistentFlags().StringVar(&args.common.operatorNamespace, "operatorNamespace", operatorDefaultNamespace, OperatorNamespaceHelpstr)
    56  	cmd.PersistentFlags().StringVar(&args.common.watchedNamespaces, "watchedNamespaces", constants.IstioSystemNamespace,
    57  		"The namespaces the operator controller watches, could be namespace list separated by comma, eg. 'ns1,ns2'")
    58  	cmd.PersistentFlags().StringVarP(&args.common.manifestsPath, "charts", "", "", ChartsDeprecatedStr)
    59  	cmd.PersistentFlags().StringVarP(&args.common.manifestsPath, "manifests", "d", "", ManifestsFlagHelpStr)
    60  	cmd.PersistentFlags().StringVarP(&args.common.revision, "revision", "r", "", OperatorRevFlagHelpStr)
    61  }
    62  
    63  func operatorInitCmd(ctx cli.Context, rootArgs *RootArgs, oiArgs *operatorInitArgs) *cobra.Command {
    64  	return &cobra.Command{
    65  		Use:   "init",
    66  		Short: "Installs the Istio operator controller in the cluster.",
    67  		Long:  "The init subcommand installs the Istio operator controller in the cluster.",
    68  		Args:  cobra.ExactArgs(0),
    69  		PreRunE: func(cmd *cobra.Command, args []string) error {
    70  			if !labels.IsDNS1123Label(oiArgs.common.revision) && cmd.PersistentFlags().Changed("revision") {
    71  				return fmt.Errorf("invalid revision specified: %v", oiArgs.common.revision)
    72  			}
    73  			return nil
    74  		},
    75  		RunE: func(cmd *cobra.Command, args []string) error {
    76  			client, err := ctx.CLIClient()
    77  			if err != nil {
    78  				return err
    79  			}
    80  			l := clog.NewConsoleLogger(cmd.OutOrStdout(), cmd.ErrOrStderr(), installerScope)
    81  			operatorInit(client, rootArgs, oiArgs, l)
    82  			return nil
    83  		},
    84  	}
    85  }
    86  
    87  // operatorInit installs the Istio operator controller into the cluster.
    88  func operatorInit(cliClient kube.CLIClient, args *RootArgs, oiArgs *operatorInitArgs, l clog.Logger) {
    89  	kubeClient, client, err := kubeClients(cliClient, l)
    90  	if err != nil {
    91  		l.LogAndFatal(err)
    92  	}
    93  	if oiArgs.common.revision == "default" {
    94  		oiArgs.common.revision = ""
    95  	}
    96  	// Error here likely indicates Deployment is missing. If some other K8s error, we will hit it again later.
    97  	already, _ := isControllerInstalled(kubeClient.Kube(), oiArgs.common.operatorNamespace, oiArgs.common.revision)
    98  	if already {
    99  		l.LogAndPrintf("Operator controller is already installed in %s namespace.", oiArgs.common.operatorNamespace)
   100  		l.LogAndPrintf("Upgrading operator controller in namespace: %s using image: %s/operator:%s",
   101  			oiArgs.common.operatorNamespace, oiArgs.common.hub, oiArgs.common.tag)
   102  	} else {
   103  		l.LogAndPrintf("Installing operator controller in namespace: %s using image: %s/operator:%s",
   104  			oiArgs.common.operatorNamespace, oiArgs.common.hub, oiArgs.common.tag)
   105  	}
   106  
   107  	l.LogAndPrintf("Operator controller will watch namespaces: %s", oiArgs.common.watchedNamespaces)
   108  
   109  	vals, mstr, err := renderOperatorManifest(args, &oiArgs.common)
   110  	if err != nil {
   111  		l.LogAndFatal(err)
   112  	}
   113  
   114  	installerScope.Debugf("Installing operator charts with the following values:\n%s", vals)
   115  	installerScope.Debugf("Using the following manifest to install operator:\n%s\n", mstr)
   116  
   117  	opts := &applyOptions{
   118  		DryRun: args.DryRun,
   119  	}
   120  
   121  	// If CR was passed, we must create a namespace for it and install CR into it.
   122  	customResource, istioNamespace, err := getCRAndNamespaceFromFile(oiArgs.inFilename, l)
   123  	if err != nil {
   124  		l.LogAndFatal(err)
   125  	}
   126  	var iop *iopv1alpha1.IstioOperator
   127  	if oiArgs.common.revision != "" {
   128  		emptyiops := &v1alpha1.IstioOperatorSpec{Profile: "empty", Revision: oiArgs.common.revision}
   129  		iop, err = translate.IOPStoIOP(emptyiops, "", "")
   130  		if err != nil {
   131  			l.LogAndFatal(err)
   132  		}
   133  	}
   134  
   135  	if err := operatorutil.CreateNamespace(kubeClient.Kube(), oiArgs.common.operatorNamespace, "", opts.DryRun); err != nil {
   136  		l.LogAndFatal(err)
   137  	}
   138  
   139  	// create watched namespaces
   140  	namespaces := strings.Split(oiArgs.common.watchedNamespaces, ",")
   141  	// if the namespace in the CR is provided, consider creating it too.
   142  	if istioNamespace != "" {
   143  		namespaces = append(namespaces, istioNamespace)
   144  	}
   145  	for _, ns := range namespaces {
   146  		if err := operatorutil.CreateNamespace(kubeClient.Kube(), ns, "", opts.DryRun); err != nil {
   147  			l.LogAndFatal(err)
   148  		}
   149  	}
   150  
   151  	if err := applyManifest(kubeClient, client, mstr, name.IstioOperatorComponentName, opts, iop, l); err != nil {
   152  		l.LogAndFatal(err)
   153  	}
   154  
   155  	if customResource != "" {
   156  		if err := applyManifest(kubeClient, client, customResource, name.IstioOperatorComponentName, opts, iop, l); err != nil {
   157  			l.LogAndFatal(err)
   158  		}
   159  	}
   160  
   161  	l.LogAndPrint(color.New(color.FgGreen).Sprint("✔ ") + installationCompleteStr)
   162  }