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 }