istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/util/k8s.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 util
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strconv"
    21  
    22  	"github.com/prometheus/prometheus/util/strutil"
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/api/errors"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  	"k8s.io/client-go/kubernetes"
    28  
    29  	"istio.io/api/label"
    30  	iopv1alpha1 "istio.io/istio/operator/pkg/apis/istio/v1alpha1"
    31  	"istio.io/istio/pkg/config/constants"
    32  	"istio.io/istio/pkg/kube"
    33  )
    34  
    35  // GKString differs from default representation of GroupKind
    36  func GKString(gvk schema.GroupKind) string {
    37  	return fmt.Sprintf("%s/%s", gvk.Group, gvk.Kind)
    38  }
    39  
    40  // ValidateIOPCAConfig validates if the IstioOperator CA configs are applicable to the K8s cluster
    41  func ValidateIOPCAConfig(client kube.Client, iop *iopv1alpha1.IstioOperator) error {
    42  	globalI := iop.Spec.Values.AsMap()["global"]
    43  	global, ok := globalI.(map[string]any)
    44  	if !ok {
    45  		// This means no explicit global configuration. Still okay
    46  		return nil
    47  	}
    48  	ca, ok := global["pilotCertProvider"].(string)
    49  	if !ok {
    50  		// This means the default pilotCertProvider is being used
    51  		return nil
    52  	}
    53  	if ca == "kubernetes" {
    54  		ver, err := client.GetKubernetesVersion()
    55  		if err != nil {
    56  			return fmt.Errorf("failed to determine support for K8s legacy signer. Use the --force flag to ignore this: %v", err)
    57  		}
    58  
    59  		if kube.IsAtLeastVersion(client, 22) {
    60  			return fmt.Errorf("configuration PILOT_CERT_PROVIDER=%s not supported in Kubernetes %v."+
    61  				"Please pick another value for PILOT_CERT_PROVIDER", ca, ver.String())
    62  		}
    63  	}
    64  	return nil
    65  }
    66  
    67  // CreateNamespace creates a namespace using the given k8s interface.
    68  func CreateNamespace(cs kubernetes.Interface, namespace string, network string, dryRun bool) error {
    69  	if dryRun {
    70  		scope.Infof("Not applying Namespace %s because of dry run.", namespace)
    71  		return nil
    72  	}
    73  	if namespace == "" {
    74  		// Setup default namespace
    75  		namespace = constants.IstioSystemNamespace
    76  	}
    77  	// check if the namespace already exists. If yes, do nothing. If no, create a new one.
    78  	if _, err := cs.CoreV1().Namespaces().Get(context.TODO(), namespace, metav1.GetOptions{}); err != nil {
    79  		if errors.IsNotFound(err) {
    80  			ns := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{
    81  				Name:   namespace,
    82  				Labels: map[string]string{},
    83  			}}
    84  			if network != "" {
    85  				ns.Labels[label.TopologyNetwork.Name] = network
    86  			}
    87  			_, err := cs.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{})
    88  			if err != nil {
    89  				return fmt.Errorf("failed to create namespace %v: %v", namespace, err)
    90  			}
    91  
    92  			return nil
    93  		}
    94  
    95  		return fmt.Errorf("failed to check if namespace %v exists: %v", namespace, err)
    96  	}
    97  
    98  	return nil
    99  }
   100  
   101  func PrometheusPathAndPort(pod *v1.Pod) (string, int, error) {
   102  	path := "/metrics"
   103  	port := 9090
   104  	for key, val := range pod.ObjectMeta.Annotations {
   105  		switch strutil.SanitizeLabelName(key) {
   106  		case "prometheus_io_port":
   107  			p, err := strconv.Atoi(val)
   108  			if err != nil {
   109  				return "", 0, fmt.Errorf("failed to parse port from annotation: %v", err)
   110  			}
   111  
   112  			port = p
   113  		case "prometheus_io_path":
   114  			path = val
   115  		}
   116  	}
   117  
   118  	return path, port, nil
   119  }