istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/framework/components/namespace/namespace.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 namespace
    16  
    17  import (
    18  	"time"
    19  
    20  	"istio.io/istio/pkg/test"
    21  	"istio.io/istio/pkg/test/framework/resource"
    22  	"istio.io/istio/pkg/test/scopes"
    23  )
    24  
    25  // Config contains configuration information about the namespace instance
    26  type Config struct {
    27  	// Prefix to use for autogenerated namespace name
    28  	Prefix string
    29  	// Inject indicates whether to add sidecar injection label to this namespace
    30  	Inject bool
    31  	// Revision is the namespace of custom injector instance
    32  	Revision string
    33  	// Labels to be applied to namespace
    34  	Labels map[string]string
    35  	// SkipDump, if enabled, will disable dumping the namespace. This is useful to avoid duplicate
    36  	// dumping of istio-system.
    37  	SkipDump bool
    38  	// SkipCleanup, if enabled, the namespace will not be deleted during cleanup. Used for istio-system namespace
    39  	SkipCleanup bool
    40  }
    41  
    42  func (c *Config) overwriteRevisionIfEmpty(revision string) {
    43  	// Overwrite the default namespace label (istio-injection=enabled)
    44  	// with istio.io/rev=XXX. If a revision label is already provided,
    45  	// the label will remain as is.
    46  	if c.Revision == "" {
    47  		c.Revision = revision
    48  	}
    49  	// Allow setting revision explicitly to `default` to avoid configuration overwrite
    50  	if c.Revision == "default" {
    51  		c.Revision = ""
    52  	}
    53  }
    54  
    55  // Instance represents an allocated namespace that can be used to create config, or deploy components in.
    56  type Instance interface {
    57  	Name() string
    58  	SetLabel(key, value string) error
    59  	RemoveLabel(key string) error
    60  	Prefix() string
    61  	Labels() (map[string]string, error)
    62  	IsAmbient() bool
    63  	IsInjected() bool
    64  }
    65  
    66  // Claim an existing namespace in all clusters, or create a new one if doesn't exist.
    67  func Claim(ctx resource.Context, cfg Config) (i Instance, err error) {
    68  	cfg.overwriteRevisionIfEmpty(ctx.Settings().Revisions.Default())
    69  	return claimKube(ctx, cfg)
    70  }
    71  
    72  // ClaimOrFail calls Claim and fails test if it returns error
    73  func ClaimOrFail(t test.Failer, ctx resource.Context, name string) Instance {
    74  	t.Helper()
    75  	nsCfg := Config{
    76  		Prefix: name,
    77  		Inject: true,
    78  	}
    79  	i, err := Claim(ctx, nsCfg)
    80  	if err != nil {
    81  		t.Fatalf("namespace.ClaimOrFail:: %v", err)
    82  	}
    83  	return i
    84  }
    85  
    86  // New creates a new Namespace in all clusters.
    87  func New(ctx resource.Context, cfg Config) (i Instance, err error) {
    88  	start := time.Now()
    89  	scopes.Framework.Infof("=== BEGIN: Create namespace %s ===", cfg.Prefix)
    90  	defer func() {
    91  		if err != nil {
    92  			scopes.Framework.Errorf("=== FAILED: Create namespace %s ===", cfg.Prefix)
    93  			scopes.Framework.Error(err)
    94  		} else {
    95  			scopes.Framework.Infof("=== SUCCEEDED: Create namespace %s in %v ===", cfg.Prefix, time.Since(start))
    96  		}
    97  	}()
    98  
    99  	if ctx.Settings().StableNamespaces {
   100  		return Claim(ctx, cfg)
   101  	}
   102  	cfg.overwriteRevisionIfEmpty(ctx.Settings().Revisions.Default())
   103  	return newKube(ctx, cfg)
   104  }
   105  
   106  // NewOrFail calls New and fails test if it returns error
   107  func NewOrFail(t test.Failer, ctx resource.Context, nsConfig Config) Instance {
   108  	t.Helper()
   109  	i, err := New(ctx, nsConfig)
   110  	if err != nil {
   111  		t.Fatalf("namespace.NewOrFail: %v", err)
   112  	}
   113  	return i
   114  }
   115  
   116  // GetAll returns all namespaces that have exist in the context.
   117  func GetAll(ctx resource.Context) ([]Instance, error) {
   118  	var out []Instance
   119  	if err := ctx.GetResource(&out); err != nil {
   120  		return nil, err
   121  	}
   122  	return out, nil
   123  }
   124  
   125  // Setup is a utility function for creating a namespace in a test suite.
   126  func Setup(ns *Instance, cfg Config) resource.SetupFn {
   127  	return func(ctx resource.Context) (err error) {
   128  		*ns, err = New(ctx, cfg)
   129  		return
   130  	}
   131  }
   132  
   133  // Getter for a namespace Instance
   134  type Getter func() Instance
   135  
   136  // Get is a utility method that helps in readability of call sites.
   137  func (g Getter) Get() Instance {
   138  	return g()
   139  }
   140  
   141  // Future creates a Getter for a variable that namespace that will be set at sometime in the future.
   142  // This is helpful for configuring a setup chain for a test suite that operates on global variables.
   143  func Future(ns *Instance) Getter {
   144  	return func() Instance {
   145  		return *ns
   146  	}
   147  }
   148  
   149  func Dump(ctx resource.Context, name string) {
   150  	ns := &kubeNamespace{
   151  		ctx:    ctx,
   152  		prefix: name,
   153  		name:   name,
   154  	}
   155  	ns.Dump(ctx)
   156  }
   157  
   158  // NilGetter is a Getter that always returns nil.
   159  var NilGetter = func() Instance {
   160  	return nil
   161  }