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 }