istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tests/integration/ambient/main_test.go (about)

     1  //go:build integ
     2  // +build integ
     3  
     4  // Copyright Istio Authors
     5  //
     6  // Licensed under the Apache License, Version 2.0 (the "License");
     7  // you may not use this file except in compliance with the License.
     8  // You may obtain a copy of the License at
     9  //
    10  //     http://www.apache.org/licenses/LICENSE-2.0
    11  //
    12  // Unless required by applicable law or agreed to in writing, software
    13  // distributed under the License is distributed on an "AS IS" BASIS,
    14  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  package ambient
    19  
    20  import (
    21  	"context"
    22  	"strings"
    23  	"testing"
    24  
    25  	kerrors "k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  
    28  	"istio.io/istio/pkg/config/constants"
    29  	"istio.io/istio/pkg/test/framework"
    30  	"istio.io/istio/pkg/test/framework/components/ambient"
    31  	"istio.io/istio/pkg/test/framework/components/echo"
    32  	cdeployment "istio.io/istio/pkg/test/framework/components/echo/common/deployment"
    33  	"istio.io/istio/pkg/test/framework/components/echo/common/ports"
    34  	"istio.io/istio/pkg/test/framework/components/echo/deployment"
    35  	"istio.io/istio/pkg/test/framework/components/echo/match"
    36  	"istio.io/istio/pkg/test/framework/components/istio"
    37  	"istio.io/istio/pkg/test/framework/components/namespace"
    38  	"istio.io/istio/pkg/test/framework/components/prometheus"
    39  	"istio.io/istio/pkg/test/framework/label"
    40  	"istio.io/istio/pkg/test/framework/resource"
    41  	"istio.io/istio/pkg/test/framework/resource/config/apply"
    42  	"istio.io/istio/pkg/test/scopes"
    43  	"istio.io/istio/tests/integration/security/util/cert"
    44  )
    45  
    46  var (
    47  	i istio.Instance
    48  
    49  	// Below are various preconfigured echo deployments. Whenever possible, tests should utilize these
    50  	// to avoid excessive creation/tear down of deployments. In general, a test should only deploy echo if
    51  	// its doing something unique to that specific test.
    52  	apps = &EchoDeployments{}
    53  
    54  	// used to validate telemetry in-cluster
    55  	prom prometheus.Instance
    56  )
    57  
    58  type EchoDeployments struct {
    59  	// Namespace echo apps will be deployed
    60  	Namespace         namespace.Instance
    61  	ExternalNamespace namespace.Instance
    62  
    63  	// AllWaypoint is a waypoint for all types
    64  	AllWaypoint echo.Instances
    65  	// WorkloadAddressedWaypoint is a workload only waypoint
    66  	WorkloadAddressedWaypoint echo.Instances
    67  	// ServiceAddressedWaypoint is a serviceonly waypoint
    68  	ServiceAddressedWaypoint echo.Instances
    69  	// Captured echo service
    70  	Captured echo.Instances
    71  	// Uncaptured echo Service
    72  	Uncaptured echo.Instances
    73  	// SidecarWaypoint is a sidecar with a waypoint
    74  	SidecarWaypoint echo.Instances
    75  	// SidecarCaptured echo services with sidecar and ambient capture
    76  	SidecarCaptured echo.Instances
    77  	// SidecarUncaptured echo services with sidecar and no ambient capture
    78  	SidecarUncaptured echo.Instances
    79  
    80  	// All echo services
    81  	All echo.Instances
    82  	// Echo services that are in the mesh
    83  	Mesh echo.Instances
    84  	// Echo services that are not in mesh
    85  	MeshExternal echo.Instances
    86  
    87  	MockExternal echo.Instances
    88  
    89  	// WaypointProxies by
    90  	WaypointProxies map[string]ambient.WaypointProxy
    91  }
    92  
    93  // TestMain defines the entrypoint for pilot tests using a standard Istio installation.
    94  // If a test requires a custom install it should go into its own package, otherwise it should go
    95  // here to reuse a single install across tests.
    96  func TestMain(m *testing.M) {
    97  	// nolint: staticcheck
    98  	framework.
    99  		NewSuite(m).
   100  		RequireMinVersion(24).
   101  		Label(label.IPv4). // https://github.com/istio/istio/issues/41008
   102  		Setup(func(t resource.Context) error {
   103  			t.Settings().Ambient = true
   104  			return nil
   105  		}).
   106  		Setup(istio.Setup(&i, func(ctx resource.Context, cfg *istio.Config) {
   107  			// can't deploy VMs without eastwest gateway
   108  			ctx.Settings().SkipVMs()
   109  			cfg.EnableCNI = true
   110  			cfg.DeployEastWestGW = false
   111  			cfg.ControlPlaneValues = `
   112  values:
   113    cni:
   114      # The CNI repair feature is disabled for these tests because this is a controlled environment,
   115      # and it is important to catch issues that might otherwise be automatically fixed.
   116      # Refer to issue #49207 for more context.
   117      repair:
   118        enabled: false
   119    ztunnel:
   120      terminationGracePeriodSeconds: 5
   121      env:
   122        SECRET_TTL: 5m
   123  `
   124  		}, cert.CreateCASecretAlt)).
   125  		Setup(func(t resource.Context) error {
   126  			gatewayConformanceInputs.Client = t.Clusters().Default()
   127  			gatewayConformanceInputs.Cleanup = !t.Settings().NoCleanup
   128  
   129  			return nil
   130  		}).
   131  		Setup(func(t resource.Context) error {
   132  			return SetupApps(t, i, apps)
   133  		}).
   134  		Run()
   135  }
   136  
   137  const (
   138  	WorkloadAddressedWaypoint = "workload-addressed-waypoint"
   139  	ServiceAddressedWaypoint  = "service-addressed-waypoint"
   140  	Captured                  = "captured"
   141  	Uncaptured                = "uncaptured"
   142  	SidecarWaypoint           = "sidecar-waypoint"
   143  	SidecarCaptured           = "sidecar-captured"
   144  	SidecarUncaptured         = "sidecar-uncaptured"
   145  )
   146  
   147  var inMesh = match.Matcher(func(instance echo.Instance) bool {
   148  	names := []string{"waypoint", "captured", "sidecar"}
   149  	for _, name := range names {
   150  		if strings.Contains(instance.Config().Service, name) {
   151  			return true
   152  		}
   153  	}
   154  	return false
   155  })
   156  
   157  func SetupApps(t resource.Context, i istio.Instance, apps *EchoDeployments) error {
   158  	var err error
   159  	apps.Namespace, err = namespace.New(t, namespace.Config{
   160  		Prefix: "echo",
   161  		Inject: false,
   162  		Labels: map[string]string{
   163  			constants.DataplaneModeLabel: "ambient",
   164  		},
   165  	})
   166  	if err != nil {
   167  		return err
   168  	}
   169  	apps.ExternalNamespace, err = namespace.New(t, namespace.Config{
   170  		Prefix: "external",
   171  		Inject: false,
   172  	})
   173  	if err != nil {
   174  		return err
   175  	}
   176  
   177  	prom, err = prometheus.New(t, prometheus.Config{})
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	// Headless services don't work with targetPort, set to same port
   183  	headlessPorts := make([]echo.Port, len(ports.All()))
   184  	for i, p := range ports.All() {
   185  		p.ServicePort = p.WorkloadPort
   186  		headlessPorts[i] = p
   187  	}
   188  	builder := deployment.New(t).
   189  		WithClusters(t.Clusters()...).
   190  		WithConfig(echo.Config{
   191  			Service:               WorkloadAddressedWaypoint,
   192  			Namespace:             apps.Namespace,
   193  			Ports:                 ports.All(),
   194  			ServiceAccount:        true,
   195  			WorkloadWaypointProxy: "waypoint",
   196  			Subsets: []echo.SubsetConfig{
   197  				{
   198  					Replicas: 1,
   199  					Version:  "v1",
   200  					Labels: map[string]string{
   201  						"app":                             WorkloadAddressedWaypoint,
   202  						"version":                         "v1",
   203  						constants.AmbientUseWaypointLabel: "waypoint",
   204  					},
   205  				},
   206  				{
   207  					Replicas: 1,
   208  					Version:  "v2",
   209  					Labels: map[string]string{
   210  						"app":                             WorkloadAddressedWaypoint,
   211  						"version":                         "v2",
   212  						constants.AmbientUseWaypointLabel: "waypoint",
   213  					},
   214  				},
   215  			},
   216  		}).
   217  		WithConfig(echo.Config{
   218  			Service:              ServiceAddressedWaypoint,
   219  			Namespace:            apps.Namespace,
   220  			Ports:                ports.All(),
   221  			ServiceLabels:        map[string]string{constants.AmbientUseWaypointLabel: "waypoint"},
   222  			ServiceAccount:       true,
   223  			ServiceWaypointProxy: "waypoint",
   224  			Subsets: []echo.SubsetConfig{
   225  				{
   226  					Replicas: 1,
   227  					Version:  "v1",
   228  					Labels: map[string]string{
   229  						"app":     ServiceAddressedWaypoint,
   230  						"version": "v1",
   231  					},
   232  				},
   233  				{
   234  					Replicas: 1,
   235  					Version:  "v2",
   236  					Labels: map[string]string{
   237  						"app":     ServiceAddressedWaypoint,
   238  						"version": "v2",
   239  					},
   240  				},
   241  			},
   242  		}).
   243  		WithConfig(echo.Config{
   244  			Service:        Captured,
   245  			Namespace:      apps.Namespace,
   246  			Ports:          ports.All(),
   247  			ServiceAccount: true,
   248  			Subsets: []echo.SubsetConfig{
   249  				{
   250  					Replicas: 1,
   251  					Version:  "v1",
   252  				},
   253  				{
   254  					Replicas: 1,
   255  					Version:  "v2",
   256  				},
   257  			},
   258  		}).
   259  		WithConfig(echo.Config{
   260  			Service:        Uncaptured,
   261  			Namespace:      apps.Namespace,
   262  			Ports:          ports.All(),
   263  			ServiceAccount: true,
   264  			Subsets: []echo.SubsetConfig{
   265  				{
   266  					Replicas: 1,
   267  					Version:  "v1",
   268  					Labels:   map[string]string{constants.DataplaneModeLabel: constants.DataplaneModeNone},
   269  				},
   270  				{
   271  					Replicas: 1,
   272  					Version:  "v2",
   273  					Labels:   map[string]string{constants.DataplaneModeLabel: constants.DataplaneModeNone},
   274  				},
   275  			},
   276  		})
   277  
   278  	_, whErr := t.Clusters().Default().
   279  		Kube().AdmissionregistrationV1().MutatingWebhookConfigurations().
   280  		Get(context.Background(), "istio-sidecar-injector", metav1.GetOptions{})
   281  	if whErr != nil && !kerrors.IsNotFound(whErr) {
   282  		return whErr
   283  	}
   284  	// Only setup sidecar tests if webhook is installed
   285  	if whErr == nil {
   286  		// TODO(https://github.com/istio/istio/issues/43244) support sidecars that are captured
   287  		//builder = builder.WithConfig(echo.Config{
   288  		//	Service:   SidecarWaypoint,
   289  		//	Namespace: apps.Namespace,
   290  		//	Ports:     ports.All(),
   291  		//	Subsets: []echo.SubsetConfig{
   292  		//		{
   293  		//			Replicas: 1,
   294  		//			Version:  "v1",
   295  		//			Labels: map[string]string{
   296  		//				"ambient-type":            "workload",
   297  		//				"sidecar.istio.io/inject": "true",
   298  		//			},
   299  		//		},
   300  		//		{
   301  		//			Replicas: 1,
   302  		//			Version:  "v2",
   303  		//			Labels: map[string]string{
   304  		//				"ambient-type":            "workload",
   305  		//				"sidecar.istio.io/inject": "true",
   306  		//			},
   307  		//		},
   308  		//	},
   309  		//})
   310  		//	builder = builder.WithConfig(echo.Config{
   311  		//		Service:   SidecarCaptured,
   312  		//		Namespace: apps.Namespace,
   313  		//		Ports:     ports.All(),
   314  		//		Subsets: []echo.SubsetConfig{
   315  		//			{
   316  		//				Replicas: 1,
   317  		//				Version:  "v1",
   318  		//				Labels: map[string]string{
   319  		//					"ambient-type":            "workload",
   320  		//					"sidecar.istio.io/inject": "true",
   321  		//				},
   322  		//			},
   323  		//			{
   324  		//				Replicas: 1,
   325  		//				Version:  "v2",
   326  		//				Labels: map[string]string{
   327  		//					"ambient-type":            "workload",
   328  		//					"sidecar.istio.io/inject": "true",
   329  		//				},
   330  		//			},
   331  		//		},
   332  		//	})
   333  		builder = builder.WithConfig(echo.Config{
   334  			Service:        SidecarUncaptured,
   335  			Namespace:      apps.Namespace,
   336  			Ports:          ports.All(),
   337  			ServiceAccount: true,
   338  			Subsets: []echo.SubsetConfig{
   339  				{
   340  					Replicas: 1,
   341  					Version:  "v1",
   342  					Labels: map[string]string{
   343  						"sidecar.istio.io/inject":    "true",
   344  						constants.DataplaneModeLabel: constants.DataplaneModeNone,
   345  					},
   346  				},
   347  				{
   348  					Replicas: 1,
   349  					Version:  "v2",
   350  					Labels: map[string]string{
   351  						"sidecar.istio.io/inject":    "true",
   352  						constants.DataplaneModeLabel: constants.DataplaneModeNone,
   353  					},
   354  				},
   355  			},
   356  		})
   357  	}
   358  
   359  	external := cdeployment.External{Namespace: apps.ExternalNamespace}
   360  	external.Build(t, builder)
   361  
   362  	echos, err := builder.Build()
   363  	if err != nil {
   364  		return err
   365  	}
   366  	for _, b := range echos {
   367  		scopes.Framework.Infof("built %v", b.Config().Service)
   368  	}
   369  
   370  	external.LoadValues(echos)
   371  	apps.MockExternal = external.All
   372  
   373  	// All does not include external
   374  	echos = match.Not(match.ServiceName(echo.NamespacedName{Name: cdeployment.ExternalSvc, Namespace: apps.ExternalNamespace})).GetMatches(echos)
   375  	apps.MockExternal = external.All
   376  	apps.All = echos
   377  	apps.WorkloadAddressedWaypoint = match.ServiceName(echo.NamespacedName{Name: WorkloadAddressedWaypoint, Namespace: apps.Namespace}).GetMatches(echos)
   378  	apps.ServiceAddressedWaypoint = match.ServiceName(echo.NamespacedName{Name: ServiceAddressedWaypoint, Namespace: apps.Namespace}).GetMatches(echos)
   379  	apps.AllWaypoint = apps.AllWaypoint.Append(apps.WorkloadAddressedWaypoint)
   380  	apps.AllWaypoint = apps.AllWaypoint.Append(apps.ServiceAddressedWaypoint)
   381  	apps.Uncaptured = match.ServiceName(echo.NamespacedName{Name: Uncaptured, Namespace: apps.Namespace}).GetMatches(echos)
   382  	apps.Captured = match.ServiceName(echo.NamespacedName{Name: Captured, Namespace: apps.Namespace}).GetMatches(echos)
   383  	apps.SidecarWaypoint = match.ServiceName(echo.NamespacedName{Name: SidecarWaypoint, Namespace: apps.Namespace}).GetMatches(echos)
   384  	apps.SidecarUncaptured = match.ServiceName(echo.NamespacedName{Name: SidecarUncaptured, Namespace: apps.Namespace}).GetMatches(echos)
   385  	apps.SidecarCaptured = match.ServiceName(echo.NamespacedName{Name: SidecarCaptured, Namespace: apps.Namespace}).GetMatches(echos)
   386  	apps.Mesh = inMesh.GetMatches(echos)
   387  	apps.MeshExternal = match.Not(inMesh).GetMatches(echos)
   388  
   389  	// TODO(https://github.com/istio/istio/issues/51083) remove manually allocate
   390  	if err := cdeployment.DeployExternalServiceEntry(t.ConfigIstio(), apps.Namespace, apps.ExternalNamespace, true).
   391  		Apply(apply.CleanupConditionally); err != nil {
   392  		return err
   393  	}
   394  
   395  	if apps.WaypointProxies == nil {
   396  		apps.WaypointProxies = make(map[string]ambient.WaypointProxy)
   397  	}
   398  
   399  	for _, echo := range echos {
   400  		svcwp := echo.Config().ServiceWaypointProxy
   401  		wlwp := echo.Config().WorkloadWaypointProxy
   402  		if svcwp != "" {
   403  			if _, found := apps.WaypointProxies[svcwp]; !found {
   404  				apps.WaypointProxies[svcwp], err = ambient.NewWaypointProxy(t, apps.Namespace, svcwp)
   405  				if err != nil {
   406  					return err
   407  				}
   408  			}
   409  		}
   410  		if wlwp != "" {
   411  			if _, found := apps.WaypointProxies[wlwp]; !found {
   412  				apps.WaypointProxies[wlwp], err = ambient.NewWaypointProxy(t, apps.Namespace, wlwp)
   413  				if err != nil {
   414  					return err
   415  				}
   416  			}
   417  		}
   418  
   419  	}
   420  
   421  	return nil
   422  }