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  }