istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/framework/components/cluster/clusters.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 "fmt" 19 "sort" 20 21 "istio.io/istio/pkg/util/sets" 22 ) 23 24 // Clusters is an ordered list of Cluster instances. 25 type Clusters []Cluster 26 27 func (c Clusters) Len() int { 28 return len(c) 29 } 30 31 // IsMulticluster is a utility method that indicates whether there are multiple Clusters available. 32 func (c Clusters) IsMulticluster() bool { 33 return c.Len() > 1 34 } 35 36 // Default returns the first cluster in the list. 37 func (c Clusters) Default() Cluster { 38 return c[0] 39 } 40 41 // GetOrDefault returns the given cluster if non-nil. Otherwise returns the first 42 // Cluster in the list. 43 func (c Clusters) GetOrDefault(cluster Cluster) Cluster { 44 if cluster != nil { 45 return cluster 46 } 47 return c.Default() 48 } 49 50 // GetByName returns the Cluster with the given name or nil if it is not in the list. 51 func (c Clusters) GetByName(name string) Cluster { 52 for _, cc := range c { 53 if cc.Name() == name { 54 return cc 55 } 56 } 57 return nil 58 } 59 60 // Contains returns true if a cluster with the given name is found in the list. 61 func (c Clusters) Contains(cc Cluster) bool { 62 return c.GetByName(cc.Name()) != nil 63 } 64 65 // Names returns the deduped list of names of the clusters. 66 func (c Clusters) Names() []string { 67 dedup := sets.String{} 68 for _, cc := range c { 69 dedup.Insert(cc.Name()) 70 } 71 return dedup.UnsortedList() 72 } 73 74 type ClustersByNetwork map[string]Clusters 75 76 func (c ClustersByNetwork) Networks() []string { 77 out := make([]string, 0, len(c)) 78 for n := range c { 79 out = append(out, n) 80 } 81 sort.Strings(out) 82 return out 83 } 84 85 // ByNetwork returns a map of network name to a subset of clusters 86 func (c Clusters) ByNetwork() ClustersByNetwork { 87 out := make(ClustersByNetwork) 88 for _, cc := range c { 89 out[cc.NetworkName()] = append(out[cc.NetworkName()], cc) 90 } 91 return out 92 } 93 94 // Networks returns the list of network names for the clusters. 95 func (c Clusters) Networks() []string { 96 return c.ByNetwork().Networks() 97 } 98 99 // ForNetworks returns the list of clusters in the given networks. 100 func (c Clusters) ForNetworks(networks ...string) Clusters { 101 out := make(Clusters, 0, len(c)) 102 for _, cc := range c { 103 for _, network := range networks { 104 if cc.NetworkName() == network { 105 out = append(out, cc) 106 break 107 } 108 } 109 } 110 return out 111 } 112 113 // Primaries returns the subset that are primary clusters. 114 func (c Clusters) Primaries(excluded ...Cluster) Clusters { 115 return c.filterClusters(func(cc Cluster) bool { 116 return cc.IsPrimary() 117 }, exclude(excluded...)) 118 } 119 120 // Exclude returns all clusters not given as input. 121 func (c Clusters) Exclude(excluded ...Cluster) Clusters { 122 return c.filterClusters(func(cc Cluster) bool { 123 return true 124 }, exclude(excluded...)) 125 } 126 127 // Configs returns the subset that are config clusters. 128 func (c Clusters) Configs(excluded ...Cluster) Clusters { 129 return c.filterClusters(func(cc Cluster) bool { 130 return cc.IsConfig() 131 }, exclude(excluded...)) 132 } 133 134 // Remotes returns the subset that are remote clusters. 135 func (c Clusters) Remotes(excluded ...Cluster) Clusters { 136 return c.filterClusters(func(cc Cluster) bool { 137 return cc.IsRemote() 138 }, exclude(excluded...)) 139 } 140 141 // MeshClusters returns the subset that are not external control plane clusters. 142 func (c Clusters) MeshClusters(excluded ...Cluster) Clusters { 143 return c.filterClusters(func(cc Cluster) bool { 144 return !cc.IsExternalControlPlane() 145 }, exclude(excluded...)) 146 } 147 148 // IsExternalControlPlane indicates whether the clusters are set up in an enternal 149 // control plane configuration. An external control plane is a primary cluster that 150 // gets its Istio configuration from a different cluster. 151 func (c Clusters) IsExternalControlPlane() bool { 152 for _, cc := range c { 153 if cc.IsExternalControlPlane() { 154 return true 155 } 156 } 157 return false 158 } 159 160 // Kube returns OfKind(cluster.Kubernetes) 161 func (c Clusters) Kube() Clusters { 162 return c.OfKind(Kubernetes) 163 } 164 165 // OfKind filters clusters by their Kind. 166 func (c Clusters) OfKind(kind Kind) Clusters { 167 return c.filterClusters(func(cc Cluster) bool { 168 return cc.Kind() == kind 169 }, none) 170 } 171 172 func none(Cluster) bool { 173 return false 174 } 175 176 func exclude(exclude ...Cluster) func(Cluster) bool { 177 return func(cc Cluster) bool { 178 for _, e := range exclude { 179 if cc.Name() == e.Name() { 180 return true 181 } 182 } 183 return false 184 } 185 } 186 187 func (c Clusters) filterClusters(included func(Cluster) bool, 188 excluded func(Cluster) bool, 189 ) Clusters { 190 var out Clusters 191 for _, cc := range c { 192 if !excluded(cc) && included(cc) { 193 out = append(out, cc) 194 } 195 } 196 return out 197 } 198 199 func (c Clusters) String() string { 200 return fmt.Sprintf("%v", c.Names()) 201 }