istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tests/integration/pilot/multi_version_revision_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 pilot 19 20 import ( 21 "fmt" 22 "path/filepath" 23 "strings" 24 "testing" 25 "time" 26 27 "istio.io/istio/pkg/config/protocol" 28 "istio.io/istio/pkg/test/env" 29 "istio.io/istio/pkg/test/framework" 30 "istio.io/istio/pkg/test/framework/components/echo" 31 "istio.io/istio/pkg/test/framework/components/echo/check" 32 "istio.io/istio/pkg/test/framework/components/echo/deployment" 33 "istio.io/istio/pkg/test/framework/components/namespace" 34 "istio.io/istio/pkg/test/framework/label" 35 "istio.io/istio/pkg/test/framework/resource/config/apply" 36 "istio.io/istio/pkg/test/util/file" 37 "istio.io/istio/pkg/test/util/retry" 38 ) 39 40 const ( 41 NMinusOne = "1.10.0" 42 NMinusTwo = "1.9.5" 43 NMinusThree = "1.8.6" 44 NMinusFour = "1.7.6" 45 NMinusFive = "1.6.11" 46 ) 47 48 var versions = []string{NMinusOne, NMinusTwo, NMinusThree, NMinusFour, NMinusFive} 49 50 type revisionedNamespace struct { 51 revision string 52 namespace namespace.Instance 53 } 54 55 // TestMultiVersionRevision tests traffic between data planes running under differently versioned revisions 56 // should test all possible revisioned namespace pairings to test traffic between all versions 57 func TestMultiVersionRevision(t *testing.T) { 58 // nolint: staticcheck 59 framework.NewTest(t). 60 RequiresSingleCluster(). 61 RequiresLocalControlPlane(). 62 // Requires installation of CPs from manifests, won't succeed 63 // if existing CPs have different root cert 64 Label(label.CustomSetup). 65 Run(func(t framework.TestContext) { 66 t.Skip("https://github.com/istio/istio/pull/46213") 67 skipIfK8sVersionUnsupported(t) 68 69 // keep track of applied configurations and clean up after the test 70 configs := make(map[string]string) 71 t.CleanupConditionally(func() { 72 for _, config := range configs { 73 _ = t.ConfigIstio().YAML("istio-system", config).Delete() 74 } 75 }) 76 77 revisionedNamespaces := []revisionedNamespace{} 78 for _, v := range versions { 79 installRevisionOrFail(t, v, configs) 80 81 // create a namespace pointed to the revisioned control plane we just installed 82 rev := strings.ReplaceAll(v, ".", "-") 83 ns, err := namespace.New(t, namespace.Config{ 84 Prefix: fmt.Sprintf("revision-%s", rev), 85 Inject: true, 86 Revision: rev, 87 }) 88 if err != nil { 89 t.Fatalf("failed to created revisioned namespace: %v", err) 90 } 91 revisionedNamespaces = append(revisionedNamespaces, revisionedNamespace{ 92 revision: rev, 93 namespace: ns, 94 }) 95 } 96 97 // create an echo instance in each revisioned namespace, all these echo 98 // instances will be injected with proxies from their respective versions 99 builder := deployment.New(t) 100 101 for _, ns := range revisionedNamespaces { 102 builder = builder.WithConfig(echo.Config{ 103 Service: fmt.Sprintf("revision-%s", ns.revision), 104 Namespace: ns.namespace, 105 Ports: []echo.Port{ 106 { 107 Name: "http", 108 Protocol: protocol.HTTP, 109 WorkloadPort: 8000, 110 }, 111 { 112 Name: "tcp", 113 Protocol: protocol.TCP, 114 WorkloadPort: 9000, 115 }, 116 { 117 Name: "grpc", 118 Protocol: protocol.GRPC, 119 WorkloadPort: 9090, 120 }, 121 }, 122 }) 123 } 124 instances := builder.BuildOrFail(t) 125 // add an existing pod from apps to the rotation to avoid an extra deployment 126 instances = append(instances, apps.A[0]) 127 128 testAllEchoCalls(t, instances) 129 }) 130 } 131 132 // testAllEchoCalls takes list of revisioned namespaces and generates list of echo calls covering 133 // communication between every pair of namespaces 134 func testAllEchoCalls(t framework.TestContext, echoInstances []echo.Instance) { 135 trafficTypes := []string{"http", "tcp", "grpc"} 136 for _, from := range echoInstances { 137 for _, to := range echoInstances { 138 if from == to { 139 continue 140 } 141 for _, trafficType := range trafficTypes { 142 t.NewSubTest(fmt.Sprintf("%s-%s->%s", trafficType, from.Config().Service, to.Config().Service)). 143 Run(func(t framework.TestContext) { 144 retry.UntilSuccessOrFail(t, func() error { 145 result, err := from.Call(echo.CallOptions{ 146 To: to, 147 Count: 1, 148 Port: echo.Port{ 149 Name: trafficType, 150 }, 151 Retry: echo.Retry{ 152 NoRetry: true, 153 }, 154 }) 155 return check.And( 156 check.NoError(), 157 check.OK()).Check(result, err) 158 }, retry.Delay(time.Millisecond*150)) 159 }) 160 } 161 } 162 } 163 } 164 165 // installRevisionOrFail takes an Istio version and installs a revisioned control plane running that version 166 // provided istio version must be present in tests/integration/pilot/testdata/upgrade for the installation to succeed 167 func installRevisionOrFail(t framework.TestContext, version string, configs map[string]string) { 168 config, err := file.ReadTarFile(filepath.Join(env.IstioSrc, "tests/integration/pilot/testdata/upgrade", 169 fmt.Sprintf("%s-install.yaml.tar", version))) 170 if err != nil { 171 t.Fatalf("could not read installation config: %v", err) 172 } 173 configs[version] = config 174 if err := t.ConfigIstio().YAML(i.Settings().SystemNamespace, config).Apply(apply.NoCleanup); err != nil { 175 t.Fatal(err) 176 } 177 } 178 179 // skipIfK8sVersionUnsupported skips the test if we're running on a k8s version that is not expected to work 180 // with any of the revision versions included in the test (i.e. istio 1.7 not supported on k8s 1.15) 181 func skipIfK8sVersionUnsupported(t framework.TestContext) { 182 if !t.Clusters().Default().MinKubeVersion(16) { 183 t.Skipf("k8s version not supported for %s (<%s)", t.Name(), "1.16") 184 } 185 // Kubernetes 1.22 drops support for a number of legacy resources, so we cannot install the old versions 186 if !t.Clusters().Default().MaxKubeVersion(21) { 187 t.Skipf("k8s version not supported for %s (>%s)", t.Name(), "1.21") 188 } 189 }