Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions tests/e2e/ambient/ambient_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/istio-ecosystem/sail-operator/pkg/env"
k8sclient "github.com/istio-ecosystem/sail-operator/tests/e2e/util/client"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/common"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/kubectl"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand All @@ -30,10 +31,10 @@ import (
var (
cl client.Client
err error
controlPlaneNamespace = env.Get("CONTROL_PLANE_NS", "istio-system")
controlPlaneNamespace = common.ControlPlaneNamespace
istioName = env.Get("ISTIO_NAME", "default")
istioCniNamespace = env.Get("ISTIOCNI_NAMESPACE", "istio-cni")
ztunnelNamespace = env.Get("ZTUNNEL_NAMESPACE", "ztunnel")
istioCniNamespace = common.IstioCniNamespace
ztunnelNamespace = common.ZtunnelNamespace
istioCniName = env.Get("ISTIOCNI_NAME", "default")
expectedRegistry = env.Get("EXPECTED_REGISTRY", "^docker\\.io|^gcr\\.io")
multicluster = env.GetBool("MULTICLUSTER", false)
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/controlplane/control_plane_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ var (
err error
namespace = common.OperatorNamespace
deploymentName = env.Get("DEPLOYMENT_NAME", "sail-operator")
controlPlaneNamespace = env.Get("CONTROL_PLANE_NS", "istio-system")
controlPlaneNamespace = common.ControlPlaneNamespace
istioName = env.Get("ISTIO_NAME", "default")
istioCniNamespace = env.Get("ISTIOCNI_NAMESPACE", "istio-cni")
istioCniNamespace = common.IstioCniNamespace
istioCniName = env.Get("ISTIOCNI_NAME", "default")
expectedRegistry = env.Get("EXPECTED_REGISTRY", "^docker\\.io|^gcr\\.io")
sampleNamespace = env.Get("SAMPLE_NAMESPACE", "sample")
Expand Down
5 changes: 3 additions & 2 deletions tests/e2e/dualstack/dualstack_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/istio-ecosystem/sail-operator/pkg/env"
k8sclient "github.com/istio-ecosystem/sail-operator/tests/e2e/util/client"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/common"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/kubectl"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand All @@ -30,9 +31,9 @@ import (
var (
cl client.Client
err error
controlPlaneNamespace = env.Get("CONTROL_PLANE_NS", "istio-system")
controlPlaneNamespace = common.ControlPlaneNamespace
istioName = env.Get("ISTIO_NAME", "default")
istioCniNamespace = env.Get("ISTIOCNI_NAMESPACE", "istio-cni")
istioCniNamespace = common.IstioCniNamespace
istioCniName = env.Get("ISTIOCNI_NAME", "default")
expectedRegistry = env.Get("EXPECTED_REGISTRY", "^docker\\.io|^gcr\\.io")
multicluster = env.GetBool("MULTICLUSTER", false)
Expand Down
85 changes: 82 additions & 3 deletions tests/e2e/multicluster/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@
package multicluster

import (
"context"
"fmt"
"strings"
"text/template"
"time"

"github.com/istio-ecosystem/sail-operator/pkg/kube"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/certs"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/common"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/kubectl"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// ClusterDeployment represents a cluster along with its sample app version.
Expand All @@ -33,16 +39,29 @@ type ClusterDeployment struct {
}

// deploySampleApp deploys the sample apps (helloworld and sleep) in the given cluster.
func deploySampleApp(k kubectl.Kubectl, ns string, appVersion string) {
func deploySampleApp(k kubectl.Kubectl, ns, appVersion, profile string) {
Expect(k.WithNamespace(ns).ApplyKustomize("helloworld", "service=helloworld")).To(Succeed(), "Sample service deploy failed on Cluster")
Expect(k.WithNamespace(ns).ApplyKustomize("helloworld", "version="+appVersion)).To(Succeed(), "Sample service deploy failed on Cluster")
Expect(k.WithNamespace(ns).ApplyKustomize("sleep")).To(Succeed(), "Sample sleep deploy failed on Cluster")

// In Ambient mode, services need to be marked as "global" in order to load balance requests among clusters
if profile == "ambient" {
Expect(k.LabelNamespaced("service", ns, "helloworld", "istio.io/global", "true")).To(Succeed(), "Error labeling sample namespace")
}
}

// deploySampleAppToClusters deploys the sample app to all provided clusters.
func deploySampleAppToClusters(ns string, clusters []ClusterDeployment) {
func deploySampleAppToClusters(ns, profile string, clusters []ClusterDeployment) {
for _, cd := range clusters {
deploySampleApp(cd.Kubectl, ns, cd.AppVersion)
k := cd.Kubectl
Expect(k.CreateNamespace(ns)).To(Succeed(), fmt.Sprintf("Namespace failed to be created on Cluster %s", k.ClusterName))
if profile == "ambient" {
Expect(k.Label("namespace", ns, "istio.io/dataplane-mode", "ambient")).To(Succeed(), "Error labeling sample namespace")
} else {
Expect(k.Label("namespace", ns, "istio-injection", "enabled")).To(Succeed(), "Error labeling sample namespace")
}

deploySampleApp(k, ns, cd.AppVersion, profile)
}
}

Expand Down Expand Up @@ -75,3 +94,63 @@ func genTemplate(manifestTmpl string, values any) string {
Expect(tmpl.Execute(&b, values)).To(Succeed())
return b.String()
}

func createIstioNamespaces(k kubectl.Kubectl, network, profile string) {
Expect(k.CreateNamespace(common.ControlPlaneNamespace)).To(Succeed(), "Istio namespace failed to be created")
Expect(k.CreateNamespace(common.IstioCniNamespace)).To(Succeed(), "Istio CNI namespace failed to be created")

if profile == "ambient" {
Expect(k.Label("namespace", common.ControlPlaneNamespace, "topology.istio.io/network", network)).To(Succeed(), "Error labeling istio namespace")
Expect(k.CreateNamespace(common.ZtunnelNamespace)).To(Succeed(), "Ztunnel namespace failed to be created")
}
}

func createIstioResources(k kubectl.Kubectl, version, cluster, network, profile string, values ...string) {
cniSpec := fmt.Sprintf(`
profile: %s`, profile)
common.CreateIstioCNI(k, version, cniSpec)

if profile == "ambient" {
spec := fmt.Sprintf(`
values:
ztunnel:
multiCluster:
clusterName: %s
network: %s`, cluster, network)
common.CreateZTunnel(k, version, spec)
}

spec := fmt.Sprintf(`
profile: %s
values:
global:
meshID: mesh1
multiCluster:
clusterName: %s
network: %s`, profile, cluster, network)
for _, value := range values {
spec += common.Indent(value)
}

if profile == "ambient" {
spec += fmt.Sprintf(`
pilot:
trustedZtunnelNamespace: %s
env:
AMBIENT_ENABLE_MULTI_NETWORK: "true"`, common.ZtunnelNamespace)
}

common.CreateIstio(k, version, spec)
}

func createIntermediateCA(k kubectl.Kubectl, zone, network, artifacts string, cl client.Client) {
Expect(certs.PushIntermediateCA(k, common.ControlPlaneNamespace, zone, network, artifacts, cl)).
To(Succeed(), fmt.Sprintf("Error pushing intermediate CA to %s Cluster", k.ClusterName))
}

func awaitSecretCreation(cluster string, cl client.Client) {
Eventually(func() error {
_, err := common.GetObject(context.Background(), cl, kube.Key("cacerts", common.ControlPlaneNamespace), &corev1.Secret{})
return err
}).ShouldNot(HaveOccurred(), fmt.Sprintf("Secret is not created on %s cluster", cluster))
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ var _ = Describe("Multicluster deployment models", Label("multicluster", "multic

When("default Istio is created in Cluster #1 to handle ingress to External Control Plane", func() {
BeforeAll(func(ctx SpecContext) {
Expect(k1.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created")
Expect(k1.CreateNamespace(istioCniNamespace)).To(Succeed(), "Istio CNI namespace failed to be created")
createIstioNamespaces(k1, "network1", "default")

common.CreateIstioCNI(k1, v.Name)
common.CreateIstio(k1, v.Name, `
Expand Down Expand Up @@ -335,7 +334,7 @@ spec:
// Label the namespace with the istio revision name
Expect(k2.Label("namespace", sampleNamespace, "istio.io/rev", "external-istiod")).To(Succeed(), "Labeling failed on Cluster #2")

deploySampleApp(k2, sampleNamespace, "v1")
deploySampleApp(k2, sampleNamespace, "v1", "default")
Success("Sample app is deployed in Cluster #2")
})

Expand Down
93 changes: 42 additions & 51 deletions tests/e2e/multicluster/multicluster_multiprimary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@
package multicluster

import (
"context"
"fmt"
"time"

v1 "github.com/istio-ecosystem/sail-operator/api/v1"
"github.com/istio-ecosystem/sail-operator/pkg/istioversion"
"github.com/istio-ecosystem/sail-operator/pkg/kube"
. "github.com/istio-ecosystem/sail-operator/pkg/test/util/ginkgo"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/certs"
"github.com/istio-ecosystem/sail-operator/pkg/version"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/cleaner"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/common"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/istioctl"
Expand All @@ -39,10 +38,25 @@ var _ = Describe("Multicluster deployment models", Label("multicluster", "multic
SetDefaultEventuallyTimeout(180 * time.Second)
SetDefaultEventuallyPollingInterval(time.Second)

Context("Sidecar", func() {
generateMultiPrimaryTestCases("default")
})
Context("Ambient", Label("ambient"), func() {
generateMultiPrimaryTestCases("ambient")
})
})

func generateMultiPrimaryTestCases(profile string) {
Describe("Multi-Primary Multi-Network configuration", func() {
// Test the Multi-Primary Multi-Network configuration for each supported Istio version
for _, version := range istioversion.GetLatestPatchVersions() {
Context(fmt.Sprintf("Istio version %s", version.Version), func() {
for _, v := range istioversion.GetLatestPatchVersions() {
// Ambient multi-cluster is supported only since 1.27
if profile == "ambient" && version.Constraint("<1.27").Check(v.Version) {
Log(fmt.Sprintf("Skipping test, because Istio version %s does not support Ambient Multi-Cluster configuration", v.Version))
continue
}

Context(fmt.Sprintf("Istio version %s", v.Version), func() {
clr1 := cleaner.New(clPrimary, "cluster=primary")
clr2 := cleaner.New(clRemote, "cluster=remote")

Expand All @@ -53,38 +67,19 @@ var _ = Describe("Multicluster deployment models", Label("multicluster", "multic

When("Istio and IstioCNI resources are created in both clusters", func() {
BeforeAll(func(ctx SpecContext) {
Expect(k1.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Istio namespace failed to be created")
Expect(k2.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Istio namespace failed to be created")
Expect(k1.CreateNamespace(istioCniNamespace)).To(Succeed(), "Istio CNI namespace failed to be created")
Expect(k2.CreateNamespace(istioCniNamespace)).To(Succeed(), "Istio CNI namespace failed to be created")
createIstioNamespaces(k1, "network1", profile)
createIstioNamespaces(k2, "network2", profile)

// Push the intermediate CA to both clusters
Expect(certs.PushIntermediateCA(k1, controlPlaneNamespace, "east", "network1", artifacts, clPrimary)).To(Succeed())
Expect(certs.PushIntermediateCA(k2, controlPlaneNamespace, "west", "network2", artifacts, clRemote)).To(Succeed())
createIntermediateCA(k1, "east", "network1", artifacts, clPrimary)
createIntermediateCA(k2, "west", "network2", artifacts, clRemote)

// Wait for the secret to be created in both clusters
Eventually(func() error {
_, err := common.GetObject(context.Background(), clPrimary, kube.Key("cacerts", controlPlaneNamespace), &corev1.Secret{})
return err
}).ShouldNot(HaveOccurred(), "Secret is not created on Cluster #1")

Eventually(func() error {
_, err := common.GetObject(context.Background(), clRemote, kube.Key("cacerts", controlPlaneNamespace), &corev1.Secret{})
return err
}).ShouldNot(HaveOccurred(), "Secret is not created on Cluster #1")

common.CreateIstioCNI(k1, version.Name)
common.CreateIstioCNI(k2, version.Name)

spec := `
values:
global:
meshID: mesh1
multiCluster:
clusterName: %s
network: %s`
common.CreateIstio(k1, version.Name, fmt.Sprintf(spec, "cluster1", "network1"))
common.CreateIstio(k2, version.Name, fmt.Sprintf(spec, "cluster2", "network2"))
awaitSecretCreation(k1.ClusterName, clPrimary)
awaitSecretCreation(k2.ClusterName, clRemote)

createIstioResources(k1, v.Name, "cluster1", "network1", profile)
createIstioResources(k2, v.Name, "cluster2", "network2", profile)
})

It("updates both Istio CR status to Ready", func(ctx SpecContext) {
Expand All @@ -99,10 +94,10 @@ values:

It("deploys istiod", func(ctx SpecContext) {
common.AwaitDeployment(ctx, "istiod", k1, clPrimary)
Expect(common.GetVersionFromIstiod()).To(Equal(version.Version), "Unexpected istiod version")
Expect(common.GetVersionFromIstiod()).To(Equal(v.Version), "Unexpected istiod version")

common.AwaitDeployment(ctx, "istiod", k2, clRemote)
Expect(common.GetVersionFromIstiod()).To(Equal(version.Version), "Unexpected istiod version")
Expect(common.GetVersionFromIstiod()).To(Equal(v.Version), "Unexpected istiod version")
})

It("deploys istio-cni-node", func(ctx SpecContext) {
Expand All @@ -113,12 +108,17 @@ values:

When("Gateway is created in both clusters", func() {
BeforeAll(func(ctx SpecContext) {
Expect(k1.WithNamespace(controlPlaneNamespace).Apply(eastGatewayYAML)).To(Succeed(), "Gateway creation failed on Cluster #1")
Expect(k2.WithNamespace(controlPlaneNamespace).Apply(westGatewayYAML)).To(Succeed(), "Gateway creation failed on Cluster #2")

// Expose the Gateway service in both clusters
Expect(k1.WithNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Cluster #1")
Expect(k2.WithNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Cluster #2")
if profile == "ambient" {
common.CreateAmbientGateway(k1, controlPlaneNamespace, "network1")
common.CreateAmbientGateway(k2, controlPlaneNamespace, "network2")
} else {
Expect(k1.WithNamespace(controlPlaneNamespace).Apply(eastGatewayYAML)).To(Succeed(), "Gateway creation failed on Cluster #1")
Expect(k2.WithNamespace(controlPlaneNamespace).Apply(westGatewayYAML)).To(Succeed(), "Gateway creation failed on Cluster #2")

// Expose the Gateway service in both clusters
Expect(k1.WithNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Cluster #1")
Expect(k2.WithNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Cluster #2")
}
})

It("updates both Gateway status to Available", func(ctx SpecContext) {
Expand Down Expand Up @@ -164,16 +164,7 @@ values:

When("sample apps are deployed in both clusters", func() {
BeforeAll(func(ctx SpecContext) {
// Create namespace
Expect(k1.CreateNamespace(sampleNamespace)).To(Succeed(), "Namespace failed to be created on Cluster #1")
Expect(k2.CreateNamespace(sampleNamespace)).To(Succeed(), "Namespace failed to be created on Cluster #2")

// Label the namespace
Expect(k1.Label("namespace", sampleNamespace, "istio-injection", "enabled")).To(Succeed(), "Error labeling sample namespace")
Expect(k2.Label("namespace", sampleNamespace, "istio-injection", "enabled")).To(Succeed(), "Error labeling sample namespace")

// Deploy the sample app in both clusters
deploySampleAppToClusters(sampleNamespace, []ClusterDeployment{
deploySampleAppToClusters(sampleNamespace, profile, []ClusterDeployment{
{Kubectl: k1, AppVersion: "v1"},
{Kubectl: k2, AppVersion: "v2"},
})
Expand Down Expand Up @@ -245,4 +236,4 @@ values:
})
}
})
})
}
Loading