istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/framework/components/cluster/topology.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 cluster
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  
    21  	"istio.io/istio/pkg/kube"
    22  	"istio.io/istio/pkg/test/framework/config"
    23  )
    24  
    25  // Map can be given as a shared reference to multiple Topology/Cluster implementations.
    26  // allowing clusters to find each other for lookups of Primary, ConfigCluster, etc.
    27  type Map = map[string]Cluster
    28  
    29  func NewTopology(config Config, allClusters Map) Topology {
    30  	return Topology{
    31  		ClusterName:             config.Name,
    32  		ClusterKind:             config.Kind,
    33  		Network:                 config.Network,
    34  		ClusterHTTPProxy:        config.HTTPProxy,
    35  		PrimaryClusterName:      config.PrimaryClusterName,
    36  		ConfigClusterName:       config.ConfigClusterName,
    37  		ClusterProxyKubectlOnly: config.ProxyKubectlOnly,
    38  		AllClusters:             allClusters,
    39  		Index:                   len(allClusters),
    40  		ConfigMetadata:          config.Meta,
    41  	}
    42  }
    43  
    44  // Topology gives information about the relationship between clusters.
    45  // Cluster implementations can embed this struct to include common functionality.
    46  type Topology struct {
    47  	ClusterName             string
    48  	ClusterKind             Kind
    49  	Network                 string
    50  	ClusterHTTPProxy        string
    51  	PrimaryClusterName      string
    52  	ConfigClusterName       string
    53  	ClusterProxyKubectlOnly bool
    54  	Index                   int
    55  	// AllClusters should contain all AllClusters in the context
    56  	AllClusters    Map
    57  	ConfigMetadata config.Map
    58  }
    59  
    60  // MetadataValue provides the configured value for a metadata key in the cluster configuration.
    61  func (c Topology) MetadataValue(key string) string {
    62  	return c.ConfigMetadata.String(key)
    63  }
    64  
    65  // NetworkName the cluster is on
    66  func (c Topology) NetworkName() string {
    67  	return c.Network
    68  }
    69  
    70  // Name provides the ClusterName this cluster used by Istio.
    71  func (c Topology) Name() string {
    72  	return c.ClusterName
    73  }
    74  
    75  // HTTPProxy to connect to the cluster
    76  func (c Topology) HTTPProxy() string {
    77  	return c.ClusterHTTPProxy
    78  }
    79  
    80  func (c Topology) ProxyKubectlOnly() bool {
    81  	return c.ClusterProxyKubectlOnly
    82  }
    83  
    84  // knownClusterNames maintains a well-known set of cluster names. These will always be used with
    85  // StableNames if encountered.
    86  var knownClusterNames = map[string]struct{}{
    87  	"primary":               {},
    88  	"remote":                {},
    89  	"cross-network-primary": {},
    90  }
    91  
    92  // StableName provides a name used for testcase names. Deterministic, so testgrid
    93  // can be consistent when the underlying cluster names are dynamic.
    94  func (c Topology) StableName() string {
    95  	var prefix string
    96  	switch c.Kind() {
    97  	case Kubernetes:
    98  		// If its a known cluster name, use that directly.
    99  		// This will not be dynamic, and allows 1:1 correlation of cluster name and test name for simplicity.
   100  		if _, f := knownClusterNames[c.Name()]; f {
   101  			return c.Name()
   102  		}
   103  		if c.IsPrimary() {
   104  			if c.IsConfig() {
   105  				prefix = "primary"
   106  			} else {
   107  				prefix = "externalistiod"
   108  			}
   109  		} else if c.IsRemote() {
   110  			if c.IsConfig() {
   111  				prefix = "config"
   112  			} else {
   113  				prefix = "remote"
   114  			}
   115  		}
   116  	default:
   117  		prefix = string(c.Kind())
   118  	}
   119  
   120  	return fmt.Sprintf("%s-%d", prefix, c.Index)
   121  }
   122  
   123  func (c Topology) Kind() Kind {
   124  	return c.ClusterKind
   125  }
   126  
   127  func (c Topology) IsPrimary() bool {
   128  	return c.Primary().Name() == c.Name()
   129  }
   130  
   131  func (c Topology) IsConfig() bool {
   132  	return c.Config().Name() == c.Name()
   133  }
   134  
   135  func (c Topology) IsRemote() bool {
   136  	return !c.IsPrimary()
   137  }
   138  
   139  func (c Topology) IsExternalControlPlane() bool {
   140  	return c.IsPrimary() && !c.IsConfig()
   141  }
   142  
   143  func (c Topology) Primary() Cluster {
   144  	cluster, ok := c.AllClusters[c.PrimaryClusterName]
   145  	if !ok || cluster == nil {
   146  		panic(fmt.Errorf("cannot find %s, the primary cluster for %s", c.PrimaryClusterName, c.Name()))
   147  	}
   148  	return cluster
   149  }
   150  
   151  func (c Topology) PrimaryName() string {
   152  	return c.PrimaryClusterName
   153  }
   154  
   155  func (c Topology) Config() Cluster {
   156  	cluster, ok := c.AllClusters[c.ConfigClusterName]
   157  	if !ok || cluster == nil {
   158  		panic(fmt.Errorf("cannot find %s, the config cluster for %s", c.ConfigClusterName, c.Name()))
   159  	}
   160  	return cluster
   161  }
   162  
   163  func (c Topology) ConfigName() string {
   164  	return c.ConfigClusterName
   165  }
   166  
   167  func (c Topology) WithPrimary(primaryClusterName string) Topology {
   168  	// TODO remove this, should only be provided by external config
   169  	c.PrimaryClusterName = primaryClusterName
   170  	return c
   171  }
   172  
   173  func (c Topology) WithConfig(configClusterName string) Topology {
   174  	// TODO remove this, should only be provided by external config
   175  	c.ConfigClusterName = configClusterName
   176  	return c
   177  }
   178  
   179  func (c Topology) MinKubeVersion(minor uint) bool {
   180  	cluster := c.AllClusters[c.ClusterName]
   181  	if cluster.Kind() != Kubernetes && cluster.Kind() != Fake {
   182  		return c.Primary().MinKubeVersion(minor)
   183  	}
   184  	return kube.IsAtLeastVersion(cluster, minor)
   185  }
   186  
   187  func (c Topology) MaxKubeVersion(minor uint) bool {
   188  	cluster := c.AllClusters[c.ClusterName]
   189  	if cluster.Kind() != Kubernetes && cluster.Kind() != Fake {
   190  		return c.Primary().MaxKubeVersion(minor)
   191  	}
   192  	return kube.IsLessThanVersion(cluster, minor+1)
   193  }
   194  
   195  func (c Topology) String() string {
   196  	buf := &bytes.Buffer{}
   197  
   198  	_, _ = fmt.Fprintf(buf, "Name:               %s\n", c.Name())
   199  	_, _ = fmt.Fprintf(buf, "StableName:         %s\n", c.StableName())
   200  	_, _ = fmt.Fprintf(buf, "Kind:               %s\n", c.Kind())
   201  	_, _ = fmt.Fprintf(buf, "PrimaryCluster:     %s\n", c.Primary().Name())
   202  	_, _ = fmt.Fprintf(buf, "ConfigCluster:      %s\n", c.Config().Name())
   203  	_, _ = fmt.Fprintf(buf, "Network:            %s\n", c.NetworkName())
   204  	_, _ = fmt.Fprintf(buf, "HTTPProxy:          %s\n", c.HTTPProxy())
   205  	_, _ = fmt.Fprintf(buf, "ProxyKubectlOnly:   %t\n", c.ProxyKubectlOnly())
   206  
   207  	return buf.String()
   208  }