istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/framework/components/cluster/clusterboot/factory.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 clusterboot 16 17 import ( 18 "fmt" 19 20 "github.com/hashicorp/go-multierror" 21 22 "istio.io/istio/pkg/test/framework/components/cluster" 23 // imported to trigger registration 24 _ "istio.io/istio/pkg/test/framework/components/cluster/kube" 25 // imported to trigger registration 26 _ "istio.io/istio/pkg/test/framework/components/cluster/staticvm" 27 "istio.io/istio/pkg/test/framework/config" 28 "istio.io/istio/pkg/test/scopes" 29 ) 30 31 var _ cluster.Factory = factory{} 32 33 func NewFactory() cluster.Factory { 34 return factory{} 35 } 36 37 type factory struct { 38 configs []cluster.Config 39 } 40 41 func (a factory) Kind() cluster.Kind { 42 return cluster.Aggregate 43 } 44 45 func (a factory) With(configs ...cluster.Config) cluster.Factory { 46 return factory{configs: append(a.configs, configs...)} 47 } 48 49 func (a factory) Build() (cluster.Clusters, error) { 50 scopes.Framework.Infof("=== BEGIN: Building clusters ===") 51 52 // use multierror to give as much detail as possible if the config is bad 53 var errs error 54 defer func() { 55 if errs != nil { 56 scopes.Framework.Infof("=== FAILED: Building clusters ===") 57 } 58 }() 59 60 allClusters := make(cluster.Map) 61 var clusters cluster.Clusters 62 for i, cfg := range a.configs { 63 c, err := buildCluster(cfg, allClusters) 64 if err != nil { 65 errs = multierror.Append(errs, fmt.Errorf("failed building cluster from config %d: %v", i, err)) 66 continue 67 } 68 if _, ok := allClusters[c.Name()]; ok { 69 errs = multierror.Append(errs, fmt.Errorf("more than one cluster named %s", c.Name())) 70 continue 71 } 72 allClusters[c.Name()] = c 73 clusters = append(clusters, c) 74 } 75 if errs != nil { 76 return nil, errs 77 } 78 79 // validate the topology has no open edges 80 for _, c := range allClusters { 81 if primary, ok := allClusters[c.PrimaryName()]; !ok { 82 errs = multierror.Append(errs, fmt.Errorf("primary %s for %s is not in the topology", c.PrimaryName(), c.Name())) 83 continue 84 } else if !validPrimaryOrConfig(primary) { 85 errs = multierror.Append(errs, fmt.Errorf("primary %s for %s is of kind %s, primaries must be Kubernetes", primary.Name(), c.Name(), primary.Kind())) 86 continue 87 } 88 if cfg, ok := allClusters[c.ConfigName()]; !ok { 89 errs = multierror.Append(errs, fmt.Errorf("config %s for %s is not in the topology", c.ConfigName(), c.Name())) 90 continue 91 } else if !validPrimaryOrConfig(cfg) { 92 errs = multierror.Append(errs, fmt.Errorf("config %s for %s is of kind %s, primaries must be Kubernetes", cfg.Name(), c.Name(), cfg.Kind())) 93 continue 94 } 95 } 96 if errs != nil { 97 return nil, errs 98 } 99 100 for _, c := range clusters { 101 scopes.Framework.Infof("Built Cluster:\n%s", c.String()) 102 } 103 104 scopes.Framework.Infof("=== DONE: Building clusters ===") 105 return clusters, errs 106 } 107 108 func validPrimaryOrConfig(c cluster.Cluster) bool { 109 return c.Kind() == cluster.Kubernetes || c.Kind() == cluster.Fake 110 } 111 112 func buildCluster(cfg cluster.Config, allClusters cluster.Map) (cluster.Cluster, error) { 113 cfg, err := validConfig(cfg) 114 if err != nil { 115 return nil, err 116 } 117 f, err := cluster.GetFactory(cfg) 118 if err != nil { 119 return nil, err 120 } 121 return f(cfg, cluster.NewTopology(cfg, allClusters)) 122 } 123 124 func validConfig(cfg cluster.Config) (cluster.Config, error) { 125 if cfg.Name == "" { 126 return cfg, fmt.Errorf("empty cluster name") 127 } 128 if cfg.Kind == "" { 129 return cfg, fmt.Errorf("unspecified Kind for %s", cfg.Name) 130 } 131 if cfg.PrimaryClusterName == "" { 132 cfg.PrimaryClusterName = cfg.Name 133 } 134 if cfg.ConfigClusterName == "" { 135 cfg.ConfigClusterName = cfg.PrimaryClusterName 136 } 137 if cfg.Meta == nil { 138 cfg.Meta = config.Map{} 139 } 140 return cfg, nil 141 }