istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/cmd/mesh/shared.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 contains types and functions.
    16  package mesh
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"strings"
    23  	"time"
    24  
    25  	"sigs.k8s.io/controller-runtime/pkg/client"
    26  	controllruntimelog "sigs.k8s.io/controller-runtime/pkg/log"
    27  
    28  	"istio.io/istio/istioctl/pkg/install/k8sversion"
    29  	"istio.io/istio/operator/pkg/apis/istio/v1alpha1"
    30  	"istio.io/istio/operator/pkg/cache"
    31  	"istio.io/istio/operator/pkg/helmreconciler"
    32  	"istio.io/istio/operator/pkg/manifest"
    33  	"istio.io/istio/operator/pkg/name"
    34  	"istio.io/istio/operator/pkg/util/clog"
    35  	"istio.io/istio/pkg/kube"
    36  	"istio.io/istio/pkg/log"
    37  )
    38  
    39  // installerScope is the scope for all commands in the mesh package.
    40  var installerScope = log.RegisterScope("installer", "installer")
    41  
    42  func init() {
    43  	// adding to remove message about the controller-runtime logs not getting displayed
    44  	// We cannot do this in the `log` package since it would place a runtime dependency on controller-runtime for all binaries.
    45  	scope := log.RegisterScope("controlleruntime", "scope for controller runtime")
    46  	controllruntimelog.SetLogger(log.NewLogrAdapter(scope))
    47  }
    48  
    49  type Printer interface {
    50  	Printf(format string, a ...any)
    51  	Println(string)
    52  }
    53  
    54  func NewPrinterForWriter(w io.Writer) Printer {
    55  	return &writerPrinter{writer: w}
    56  }
    57  
    58  type writerPrinter struct {
    59  	writer io.Writer
    60  }
    61  
    62  func (w *writerPrinter) Printf(format string, a ...any) {
    63  	_, _ = fmt.Fprintf(w.writer, format, a...)
    64  }
    65  
    66  func (w *writerPrinter) Println(str string) {
    67  	_, _ = fmt.Fprintln(w.writer, str)
    68  }
    69  
    70  func refreshGoldenFiles() bool {
    71  	ev := os.Getenv("REFRESH_GOLDEN")
    72  	return ev == "true" || ev == "1"
    73  }
    74  
    75  func kubeBuilderInstalled() bool {
    76  	ev := os.Getenv("KUBEBUILDER")
    77  	return ev == "true" || ev == "1"
    78  }
    79  
    80  // Confirm waits for a user to confirm with the supplied message.
    81  func Confirm(msg string, writer io.Writer) bool {
    82  	for {
    83  		_, _ = fmt.Fprintf(writer, "%s ", msg)
    84  		var response string
    85  		_, err := fmt.Scanln(&response)
    86  		if err != nil {
    87  			return false
    88  		}
    89  		switch strings.ToUpper(response) {
    90  		case "Y", "YES":
    91  			return true
    92  		case "N", "NO":
    93  			return false
    94  		}
    95  	}
    96  }
    97  
    98  func KubernetesClients(kubeClient kube.CLIClient, l clog.Logger) (kube.CLIClient, client.Client, error) {
    99  	client, err := client.New(kubeClient.RESTConfig(), client.Options{Scheme: kube.IstioScheme})
   100  	if err != nil {
   101  		return nil, nil, err
   102  	}
   103  	if err := k8sversion.IsK8VersionSupported(kubeClient, l); err != nil {
   104  		return nil, nil, fmt.Errorf("check minimum supported Kubernetes version: %v", err)
   105  	}
   106  	return kubeClient, client, nil
   107  }
   108  
   109  // applyOptions contains the startup options for applying the manifest.
   110  type applyOptions struct {
   111  	// Path to the kubeconfig file.
   112  	Kubeconfig string
   113  	// ComponentName of the kubeconfig context to use.
   114  	Context string
   115  	// DryRun performs all steps except actually applying the manifests or creating output dirs/files.
   116  	DryRun bool
   117  	// Maximum amount of time to wait for resources to be ready after install when Wait=true.
   118  	WaitTimeout time.Duration
   119  }
   120  
   121  func applyManifest(kubeClient kube.Client, client client.Client, manifestStr string,
   122  	componentName name.ComponentName, opts *applyOptions, iop *v1alpha1.IstioOperator, l clog.Logger,
   123  ) error {
   124  	// Needed in case we are running a test through this path that doesn't start a new process.
   125  	cache.FlushObjectCaches()
   126  	reconciler, err := helmreconciler.NewHelmReconciler(client, kubeClient, iop, &helmreconciler.Options{DryRun: opts.DryRun, Log: l})
   127  	if err != nil {
   128  		l.LogAndError(err)
   129  		return err
   130  	}
   131  	ms := name.Manifest{
   132  		Name:    componentName,
   133  		Content: manifestStr,
   134  	}
   135  	_, err = reconciler.ApplyManifest(ms)
   136  	return err
   137  }
   138  
   139  // --manifests is an alias for --set installPackagePath=
   140  // --revision is an alias for --set revision=
   141  func applyFlagAliases(flags []string, manifestsPath, revision string) []string {
   142  	if manifestsPath != "" {
   143  		flags = append(flags, fmt.Sprintf("installPackagePath=%s", manifestsPath))
   144  	}
   145  	if revision != "" && revision != "default" {
   146  		flags = append(flags, fmt.Sprintf("revision=%s", revision))
   147  	}
   148  	return flags
   149  }
   150  
   151  // getCRAndNamespaceFromFile returns the CR name and istio namespace from a file containing an IstioOperator CR.
   152  func getCRAndNamespaceFromFile(filePath string, l clog.Logger) (customResource string, istioNamespace string, err error) {
   153  	if filePath == "" {
   154  		return "", "", nil
   155  	}
   156  
   157  	_, mergedIOPS, err := manifest.GenerateConfig([]string{filePath}, nil, false, nil, l)
   158  	if err != nil {
   159  		return "", "", err
   160  	}
   161  
   162  	b, err := os.ReadFile(filePath)
   163  	if err != nil {
   164  		return "", "", fmt.Errorf("could not read values from file %s: %s", filePath, err)
   165  	}
   166  	customResource = string(b)
   167  	istioNamespace = mergedIOPS.Namespace
   168  	return
   169  }