istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tests/integration/pilot/revisioned_upgrade_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 "strings" 23 "testing" 24 "time" 25 26 "github.com/hashicorp/go-multierror" 27 28 "istio.io/istio/pkg/config/protocol" 29 "istio.io/istio/pkg/log" 30 "istio.io/istio/pkg/test/framework" 31 "istio.io/istio/pkg/test/framework/components/echo" 32 "istio.io/istio/pkg/test/framework/components/echo/deployment" 33 "istio.io/istio/pkg/test/framework/components/echo/util/traffic" 34 "istio.io/istio/pkg/test/framework/components/namespace" 35 "istio.io/istio/pkg/test/framework/label" 36 kubetest "istio.io/istio/pkg/test/kube" 37 ) 38 39 const ( 40 callInterval = 200 * time.Millisecond 41 successThreshold = 0.95 42 ) 43 44 // TestRevisionedUpgrade tests a revision-based upgrade from the specified versions to current master 45 func TestRevisionedUpgrade(t *testing.T) { 46 // nolint: staticcheck 47 framework.NewTest(t). 48 RequiresSingleCluster(). 49 RequiresLocalControlPlane(). 50 // Requires installation of CPs from manifests, won't succeed 51 // if existing CPs have different root cert 52 Label(label.CustomSetup). 53 Run(func(t framework.TestContext) { 54 t.Skip("https://github.com/istio/istio/pull/46213") 55 // Kubernetes 1.22 drops support for a number of legacy resources, so we cannot install the old versions 56 if !t.Clusters().Default().MaxKubeVersion(21) { 57 t.Skipf("k8s version not supported for %s (>%s)", t.Name(), "1.21") 58 } 59 versions := []string{NMinusOne, NMinusTwo, NMinusThree, NMinusFour} 60 for _, v := range versions { 61 t.NewSubTest(fmt.Sprintf("%s->master", v)).Run(func(t framework.TestContext) { 62 testUpgradeFromVersion(t, v) 63 }) 64 } 65 }) 66 } 67 68 // testUpgradeFromVersion tests an upgrade from the target version to the master version 69 // provided fromVersion must be present in tests/integration/pilot/testdata/upgrade for the installation to succeed 70 // TODO(monkeyanator) pass this a generic UpgradeFunc allowing for reuse across in-place and revisioned upgrades 71 func testUpgradeFromVersion(t framework.TestContext, fromVersion string) { 72 configs := make(map[string]string) 73 t.CleanupConditionally(func() { 74 for _, config := range configs { 75 _ = t.ConfigIstio().YAML("istio-system", config).Delete() 76 } 77 }) 78 79 // install control plane on the specified version and create namespace pointed to that control plane 80 installRevisionOrFail(t, fromVersion, configs) 81 revision := strings.ReplaceAll(fromVersion, ".", "-") 82 revisionedNamespace := namespace.NewOrFail(t, t, namespace.Config{ 83 Prefix: revision, 84 Inject: true, 85 Revision: revision, 86 }) 87 88 var revisionedInstance echo.Instance 89 builder := deployment.New(t) 90 builder.With(&revisionedInstance, echo.Config{ 91 Service: fmt.Sprintf("svc-%s", revision), 92 Namespace: revisionedNamespace, 93 Ports: []echo.Port{ 94 { 95 Name: "http", 96 Protocol: protocol.HTTP, 97 WorkloadPort: 8080, 98 }, 99 }, 100 }) 101 builder.BuildOrFail(t) 102 103 // Create a traffic generator between A and B. 104 g := traffic.NewGenerator(t, traffic.Config{ 105 Source: apps.A[0], 106 Options: echo.CallOptions{ 107 To: apps.B, 108 Count: 1, 109 Port: echo.Port{ 110 Name: "http", 111 }, 112 }, 113 Interval: callInterval, 114 }).Start() 115 116 if err := enableDefaultInjection(revisionedNamespace); err != nil { 117 t.Fatalf("could not relabel namespace to enable default injection: %v", err) 118 } 119 120 log.Infof("rolling out echo workloads for service %q", revisionedInstance.Config().Service) 121 if err := revisionedInstance.Restart(); err != nil { 122 t.Fatalf("revisioned instance rollout failed with: %v", err) 123 } 124 fetch := kubetest.NewPodMustFetch(t.Clusters().Default(), revisionedInstance.Config().Namespace.Name(), fmt.Sprintf("app=%s", revisionedInstance.Config().Service)) // nolint: lll 125 pods, err := kubetest.CheckPodsAreReady(fetch) 126 if err != nil { 127 t.Fatalf("failed to retrieve upgraded pods: %v", err) 128 } 129 for _, p := range pods { 130 for _, c := range p.Spec.Containers { 131 if strings.Contains(c.Image, fromVersion) { 132 t.Fatalf("expected post-upgrade container image not to include %q, got %q", fromVersion, c.Image) 133 } 134 } 135 } 136 137 // Stop the traffic generator and get the result. 138 g.Stop().CheckSuccessRate(t, successThreshold) 139 } 140 141 // enableDefaultInjection takes a namespaces and relabels it such that it will have a default sidecar injected 142 func enableDefaultInjection(ns namespace.Instance) error { 143 var errs *multierror.Error 144 errs = multierror.Append(errs, ns.SetLabel("istio-injection", "enabled")) 145 errs = multierror.Append(errs, ns.RemoveLabel("istio.io/rev")) 146 return errs.ErrorOrNil() 147 }