istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/framework/components/echo/staticvm/instance.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 staticvm 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 "sync" 22 23 "github.com/hashicorp/go-multierror" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 26 "istio.io/istio/pkg/config/protocol" 27 "istio.io/istio/pkg/test" 28 echoClient "istio.io/istio/pkg/test/echo" 29 "istio.io/istio/pkg/test/framework/components/cluster" 30 "istio.io/istio/pkg/test/framework/components/echo" 31 "istio.io/istio/pkg/test/framework/components/echo/common" 32 "istio.io/istio/pkg/test/framework/resource" 33 ) 34 35 var _ echo.Instance = &instance{} 36 37 func init() { 38 echo.RegisterFactory(cluster.StaticVM, newInstances) 39 } 40 41 type instance struct { 42 id resource.ID 43 config echo.Config 44 address string 45 workloads echo.Workloads 46 workloadFilter []echo.Workload 47 } 48 49 func newInstances(ctx resource.Context, config []echo.Config) (echo.Instances, error) { 50 errG := multierror.Group{} 51 mu := sync.Mutex{} 52 var out echo.Instances 53 for _, c := range config { 54 c := c 55 errG.Go(func() error { 56 i, err := newInstance(ctx, c) 57 if err != nil { 58 return err 59 } 60 mu.Lock() 61 defer mu.Unlock() 62 out = append(out, i) 63 return nil 64 }) 65 } 66 if err := errG.Wait().ErrorOrNil(); err != nil { 67 return nil, err 68 } 69 return out, nil 70 } 71 72 func newInstance(ctx resource.Context, config echo.Config) (echo.Instance, error) { 73 // TODO is there a need for static cluster to create workload group/entry? 74 75 grpcPort, found := config.Ports.ForProtocol(protocol.GRPC) 76 if !found { 77 return nil, errors.New("unable to find GRPC command port") 78 } 79 workloads, err := newWorkloads(config.StaticAddresses, grpcPort.WorkloadPort, config.TLSSettings, config.Cluster) 80 if err != nil { 81 return nil, err 82 } 83 if len(workloads) == 0 { 84 return nil, fmt.Errorf("no workloads for %s", config.Service) 85 } 86 svcAddr, err := getClusterIP(config) 87 if err != nil { 88 return nil, err 89 } 90 i := &instance{ 91 config: config, 92 address: svcAddr, 93 workloads: workloads, 94 } 95 i.id = ctx.TrackResource(i) 96 return i, nil 97 } 98 99 func getClusterIP(config echo.Config) (string, error) { 100 svc, err := config.Cluster.Primary().Kube().CoreV1(). 101 Services(config.Namespace.Name()).Get(context.TODO(), config.Service, metav1.GetOptions{}) 102 if err != nil { 103 return "", err 104 } 105 return svc.Spec.ClusterIP, nil 106 } 107 108 func (i *instance) ID() resource.ID { 109 return i.id 110 } 111 112 func (i *instance) NamespacedName() echo.NamespacedName { 113 return i.config.NamespacedName() 114 } 115 116 func (i *instance) PortForName(name string) echo.Port { 117 return i.Config().Ports.MustForName(name) 118 } 119 120 func (i *instance) ServiceName() string { 121 return i.Config().Service 122 } 123 124 func (i *instance) NamespaceName() string { 125 return i.Config().NamespaceName() 126 } 127 128 func (i *instance) ServiceAccountName() string { 129 return i.Config().ServiceAccountName() 130 } 131 132 func (i *instance) ClusterLocalFQDN() string { 133 return i.Config().ClusterLocalFQDN() 134 } 135 136 func (i *instance) ClusterSetLocalFQDN() string { 137 return i.Config().ClusterSetLocalFQDN() 138 } 139 140 func (i *instance) Config() echo.Config { 141 return i.config 142 } 143 144 func (i *instance) Address() string { 145 return i.address 146 } 147 148 func (i *instance) Addresses() []string { 149 return []string{i.address} 150 } 151 152 func (i *instance) WithWorkloads(wls ...echo.Workload) echo.Instance { 153 n := *i 154 i.workloadFilter = wls 155 return &n 156 } 157 158 func (i *instance) Workloads() (echo.Workloads, error) { 159 final := []echo.Workload{} 160 for _, wl := range i.workloads { 161 filtered := false 162 for _, filter := range i.workloadFilter { 163 if wl.Address() != filter.Address() { 164 filtered = true 165 break 166 } 167 } 168 if !filtered { 169 final = append(final, wl) 170 } 171 } 172 return final, nil 173 } 174 175 func (i *instance) WorkloadsOrFail(t test.Failer) echo.Workloads { 176 w, err := i.Workloads() 177 if err != nil { 178 t.Fatalf("failed getting workloads for %s", i.Config().Service) 179 } 180 return w 181 } 182 183 func (i *instance) MustWorkloads() echo.Workloads { 184 out, err := i.Workloads() 185 if err != nil { 186 panic(err) 187 } 188 return out 189 } 190 191 func (i *instance) Clusters() cluster.Clusters { 192 var out cluster.Clusters 193 if i.config.Cluster != nil { 194 out = append(out, i.config.Cluster) 195 } 196 return out 197 } 198 199 func (i *instance) Instances() echo.Instances { 200 return echo.Instances{i} 201 } 202 203 func (i *instance) defaultClient() (*echoClient.Client, error) { 204 wl, err := i.Workloads() 205 if err != nil { 206 return nil, err 207 } 208 return wl[0].(*workload).Client, nil 209 } 210 211 func (i *instance) Call(opts echo.CallOptions) (echo.CallResult, error) { 212 return common.ForwardEcho(i.Config().Service, i, opts, i.defaultClient) 213 } 214 215 func (i *instance) CallOrFail(t test.Failer, opts echo.CallOptions) echo.CallResult { 216 t.Helper() 217 res, err := i.Call(opts) 218 if err != nil { 219 t.Fatal(err) 220 } 221 return res 222 } 223 224 func (i *instance) UpdateWorkloadLabel(add map[string]string, remove []string) error { 225 panic("cannot trigger UpdateWorkloadLabel of a static VM") 226 } 227 228 func (i *instance) Restart() error { 229 panic("cannot trigger restart of a static VM") 230 }