istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/framework/resource/settings.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 resource
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"path"
    21  	"strings"
    22  
    23  	"github.com/google/uuid"
    24  	"gopkg.in/yaml.v3"
    25  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    26  	gwConformanceConfig "sigs.k8s.io/gateway-api/conformance/utils/config"
    27  
    28  	"istio.io/istio/pkg/test"
    29  	"istio.io/istio/pkg/test/framework/label"
    30  	"istio.io/istio/pkg/util/sets"
    31  )
    32  
    33  const (
    34  	// maxTestIDLength is the maximum length allowed for testID.
    35  	maxTestIDLength = 30
    36  )
    37  
    38  // ImageSettings for container images.
    39  type ImageSettings struct {
    40  	// Hub value to use in Helm templates
    41  	Hub string
    42  
    43  	// Tag value to use in Helm templates
    44  	Tag string
    45  
    46  	// Variant value to use in Helm templates
    47  	Variant string
    48  
    49  	// Image pull policy to use for deployments. If not specified, the defaults of each deployment will be used.
    50  	PullPolicy string
    51  
    52  	// PullSecret path to a file containing a k8s secret in yaml so test pods can pull from protected registries.
    53  	PullSecret string
    54  }
    55  
    56  func (s *ImageSettings) PullSecretName() (string, error) {
    57  	if s.PullSecret == "" {
    58  		return "", nil
    59  	}
    60  	data, err := os.ReadFile(s.PullSecret)
    61  	if err != nil {
    62  		return "", err
    63  	}
    64  	secret := unstructured.Unstructured{Object: map[string]any{}}
    65  	if err := yaml.Unmarshal(data, secret.Object); err != nil {
    66  		return "", err
    67  	}
    68  	return secret.GetName(), nil
    69  }
    70  
    71  func (s *ImageSettings) PullSecretNameOrFail(t test.Failer) string {
    72  	t.Helper()
    73  	out, err := s.PullSecretName()
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	return out
    78  }
    79  
    80  // Settings is the set of arguments to the test driver.
    81  type Settings struct {
    82  	// Name of the test
    83  	TestID string
    84  
    85  	RunID uuid.UUID
    86  
    87  	// Do not cleanup the resources after the test run.
    88  	NoCleanup bool
    89  
    90  	// Indicates that the tests are running in CI Mode
    91  	CIMode bool
    92  
    93  	// Should the tests fail if usage of deprecated stuff (e.g. Envoy flags) is detected
    94  	FailOnDeprecation bool
    95  
    96  	// Local working directory root for creating temporary directories / files in. If left empty,
    97  	// os.TempDir() will be used.
    98  	BaseDir string
    99  
   100  	// The number of times to retry failed tests.
   101  	// This should not be depended on as a primary means for reducing test flakes.
   102  	Retries int
   103  
   104  	// If enabled, namespaces will be reused rather than created with dynamic names each time.
   105  	// This is useful when combined with NoCleanup, to allow quickly iterating on tests.
   106  	StableNamespaces bool
   107  
   108  	// The label selector that the user has specified.
   109  	SelectorString string
   110  
   111  	// The regex specifying which tests to skip. This follows inverted semantics of golang's
   112  	// -test.run flag, which only supports positive match. If an entire package is meant to be
   113  	// excluded, it can be filtered with `go list` and explicitly passing the list of desired
   114  	// packages. For example: `go test $(go list ./... | grep -v bad-package)`.
   115  	SkipString  ArrayFlags
   116  	SkipMatcher *Matcher
   117  
   118  	// SkipWorkloadClasses can be used to skip deploying special workload types like TPROXY, VMs, etc.
   119  	SkipWorkloadClasses ArrayFlags
   120  
   121  	// OnlyWorkloadClasses can be used to only deploy specific workload types like TPROXY, VMs, etc.
   122  	OnlyWorkloadClasses ArrayFlags
   123  
   124  	// The label selector, in parsed form.
   125  	Selector label.Selector
   126  
   127  	// EnvironmentFactory allows caller to override the environment creation. If nil, a default is used based
   128  	// on the known environment names.
   129  	EnvironmentFactory EnvironmentFactory
   130  
   131  	// Deprecated: prefer to use `--istio.test.revisions=<revision name>`.
   132  	// The revision label on a namespace for injection webhook.
   133  	// If set to XXX, all the namespaces created with istio-injection=enabled will be replaced with istio.io/rev=XXX.
   134  	Revision string
   135  
   136  	// Skip VM related parts for all the tests.
   137  	SkipVM bool
   138  
   139  	// Skip TProxy related parts for all the tests.
   140  	SkipTProxy bool
   141  
   142  	// Ambient mesh is being used
   143  	Ambient bool
   144  
   145  	// Use ambient instead of sidecars
   146  	AmbientEverywhere bool
   147  
   148  	// Compatibility determines whether we should transparently deploy echo workloads attached to each revision
   149  	// specified in `Revisions` when creating echo instances. Used primarily for compatibility testing between revisions
   150  	// on different control plane versions.
   151  	Compatibility bool
   152  
   153  	// Revisions maps the Istio revisions that are available to each cluster to their corresponding versions.
   154  	// This flag must be used with --istio.test.kube.deploy=false with the versions pre-installed.
   155  	// This flag should be passed in as comma-separated values, such as "rev-a=1.7.3,rev-b=1.8.2,rev-c=1.9.0", and the test framework will
   156  	// spin up pods pointing to these revisions for each echo instance and skip tests accordingly.
   157  	// To configure it so that an Istio revision is on the latest version simply list the revision name without the version (i.e. "rev-a,rev-b")
   158  	// If using this flag with --istio.test.revision, this flag will take precedence.
   159  	Revisions RevVerMap
   160  
   161  	// Image settings
   162  	Image ImageSettings
   163  
   164  	// EchoImage is the app image to be used by echo deployments.
   165  	EchoImage string
   166  
   167  	// CustomGRPCEchoImage if specified will run an extra container in the echo Pods responsible for gRPC ports
   168  	CustomGRPCEchoImage string
   169  
   170  	// MaxDumps is the maximum number of full test dumps that are allowed to occur within a test suite.
   171  	MaxDumps uint64
   172  
   173  	// EnableDualStack indicates the test should have dual stack enabled or not.
   174  	EnableDualStack bool
   175  
   176  	// Helm repo to be used for tests
   177  	HelmRepo string
   178  
   179  	DisableDefaultExternalServiceConnectivity bool
   180  
   181  	PeerMetadataDiscovery bool
   182  
   183  	// GatewayConformanceStandardOnly indicates that only the standard gateway conformance tests should be run.
   184  	GatewayConformanceStandardOnly bool
   185  
   186  	GatewayConformanceTimeoutConfig gwConformanceConfig.TimeoutConfig
   187  
   188  	// OpenShift indicates the tests run in an OpenShift platform rather than in plain Kubernetes.
   189  	OpenShift bool
   190  }
   191  
   192  // SkipVMs changes the skip settings at runtime
   193  func (s *Settings) SkipVMs() {
   194  	s.SkipVM = true
   195  	s.SkipWorkloadClasses = append(s.SkipWorkloadClasses, "vm")
   196  }
   197  
   198  // Skip checks whether a given class is skipped
   199  func (s *Settings) Skip(class string) bool {
   200  	if s.SkipWorkloadClassesAsSet().Contains(class) {
   201  		return true
   202  	}
   203  	if len(s.OnlyWorkloadClasses) > 0 && !s.OnlyWorkloadClassesAsSet().Contains(class) {
   204  		return true
   205  	}
   206  	return false
   207  }
   208  
   209  func (s *Settings) SkipWorkloadClassesAsSet() sets.String {
   210  	return sets.New[string](s.SkipWorkloadClasses...)
   211  }
   212  
   213  func (s *Settings) OnlyWorkloadClassesAsSet() sets.String {
   214  	return sets.New[string](s.OnlyWorkloadClasses...)
   215  }
   216  
   217  // RunDir is the name of the dir to output, for this particular run.
   218  func (s *Settings) RunDir() string {
   219  	u := strings.Replace(s.RunID.String(), "-", "", -1)
   220  	t := strings.Replace(s.TestID, "_", "-", -1)
   221  	// We want at least 6 characters of uuid padding
   222  	padding := maxTestIDLength - len(t)
   223  	if padding < 0 {
   224  		padding = 0
   225  	}
   226  	n := fmt.Sprintf("%s-%s", t, u[0:padding])
   227  
   228  	return path.Join(s.BaseDir, n)
   229  }
   230  
   231  // Clone settings
   232  func (s *Settings) Clone() *Settings {
   233  	cl := *s
   234  	return &cl
   235  }
   236  
   237  // DefaultSettings returns a default settings instance.
   238  func DefaultSettings() *Settings {
   239  	return &Settings{
   240  		RunID:    uuid.New(),
   241  		MaxDumps: 10,
   242  	}
   243  }
   244  
   245  // String implements fmt.Stringer
   246  func (s *Settings) String() string {
   247  	result := ""
   248  
   249  	result += fmt.Sprintf("TestID:            						 %s\n", s.TestID)
   250  	result += fmt.Sprintf("RunID:             						 %s\n", s.RunID.String())
   251  	result += fmt.Sprintf("NoCleanup:         						 %v\n", s.NoCleanup)
   252  	result += fmt.Sprintf("BaseDir:           						 %s\n", s.BaseDir)
   253  	result += fmt.Sprintf("Selector:          						 %v\n", s.Selector)
   254  	result += fmt.Sprintf("FailOnDeprecation: 						 %v\n", s.FailOnDeprecation)
   255  	result += fmt.Sprintf("CIMode:            						 %v\n", s.CIMode)
   256  	result += fmt.Sprintf("Retries:           						 %v\n", s.Retries)
   257  	result += fmt.Sprintf("StableNamespaces:  						 %v\n", s.StableNamespaces)
   258  	result += fmt.Sprintf("Revision:          						 %v\n", s.Revision)
   259  	result += fmt.Sprintf("SkipWorkloads      						 %v\n", s.SkipWorkloadClasses)
   260  	result += fmt.Sprintf("Compatibility:     						 %v\n", s.Compatibility)
   261  	result += fmt.Sprintf("Revisions:         						 %v\n", s.Revisions.String())
   262  	result += fmt.Sprintf("Hub:               						 %s\n", s.Image.Hub)
   263  	result += fmt.Sprintf("Tag:               						 %s\n", s.Image.Tag)
   264  	result += fmt.Sprintf("Variant:           						 %s\n", s.Image.Variant)
   265  	result += fmt.Sprintf("PullPolicy:        						 %s\n", s.Image.PullPolicy)
   266  	result += fmt.Sprintf("PullSecret:        						 %s\n", s.Image.PullSecret)
   267  	result += fmt.Sprintf("MaxDumps:          						 %d\n", s.MaxDumps)
   268  	result += fmt.Sprintf("HelmRepo:          						 %v\n", s.HelmRepo)
   269  	result += fmt.Sprintf("GatewayConformanceStandardOnly: %v\n", s.GatewayConformanceStandardOnly)
   270  	return result
   271  }
   272  
   273  type ArrayFlags []string
   274  
   275  func (i *ArrayFlags) String() string {
   276  	return fmt.Sprint([]string(*i))
   277  }
   278  
   279  func (i *ArrayFlags) Set(value string) error {
   280  	*i = append(*i, value)
   281  	return nil
   282  }