diff --git a/.codecov.yml b/.codecov.yml
index a8e52fbeca..2758a60933 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -19,3 +19,5 @@ ignore:
- 'pkg/client/.*'
- 'vendor/.*'
- '**/mocks/*'
+ - 'hack/gen-crd-spec/main.go'
+ - 'hack/gen-docs/main.go'
diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index 7b7b2c5300..0b7aca1509 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -95,4 +95,4 @@ jobs:
with:
name: e2e-controller-k8s-${{ matrix.kubernetes-minor-version }}.log
path: /tmp/e2e-controller.log
- if: ${{ failure() }}
+ if: ${{ always() }}
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 959ea6e835..4e89aadfdf 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -42,7 +42,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Run golangci-lint
- uses: golangci/golangci-lint-action@v5
+ uses: golangci/golangci-lint-action@v6
with:
version: v1.57.2
args: --timeout 6m
@@ -90,9 +90,12 @@ jobs:
path: coverage.out
- name: Upload code coverage information to codecov.io
- uses: codecov/codecov-action@v4.3.1
+ uses: codecov/codecov-action@v4.5.0
with:
file: coverage.out
+ fail_ci_if_error: false
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
codegen:
name: Verify Codegen
diff --git a/.github/workflows/image-reuse.yaml b/.github/workflows/image-reuse.yaml
index b78d72a061..cd46e06705 100644
--- a/.github/workflows/image-reuse.yaml
+++ b/.github/workflows/image-reuse.yaml
@@ -106,7 +106,7 @@ jobs:
echo 'EOF' >> $GITHUB_ENV
- name: Login to Quay.io
- uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
+ uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
with:
registry: quay.io
username: ${{ secrets.quay_username }}
@@ -114,7 +114,7 @@ jobs:
if: ${{ inputs.quay_image_name && inputs.push }}
- name: Login to GitHub Container Registry
- uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
+ uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
with:
registry: ghcr.io
username: ${{ secrets.ghcr_username }}
@@ -122,7 +122,7 @@ jobs:
if: ${{ inputs.ghcr_image_name && inputs.push }}
- name: Login to dockerhub Container Registry
- uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
+ uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
with:
username: ${{ secrets.docker_username }}
password: ${{ secrets.docker_password }}
@@ -130,7 +130,7 @@ jobs:
- name: Build and push container image
id: image
- uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 #v5.3.0
+ uses: docker/build-push-action@15560696de535e4014efeff63c48f16952e52dd1 #v6.2.0
with:
context: .
platforms: ${{ inputs.platforms }}
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index c9e2ca60b8..ef35402a72 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -107,7 +107,7 @@ jobs:
make manifests IMAGE_TAG=${{ github.ref_name }}
- name: Draft release
- uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 # v0.1.15
+ uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v0.1.15
with:
tag_name: ${{ github.event.inputs.tag }}
draft: true
@@ -212,7 +212,7 @@ jobs:
/tmp/sbom.tar.gz
- name: Upload SBOM and signature assets
- uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 # v0.1.15
+ uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v0.1.15
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 48a46a8bad..263680f07d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,24 @@
+
+## [v1.7.1](https://github.com/argoproj/argo-rollouts/compare/v1.7.0...v1.7.1) (2024-06-22)
+
+### Fix
+
+* docs site version selector broken ([#3590](https://github.com/argoproj/argo-rollouts/issues/3590))
+* don't default datadog aggregator ([#3643](https://github.com/argoproj/argo-rollouts/issues/3643))
+* Add volume for plugin and tmp folder ([#3546](https://github.com/argoproj/argo-rollouts/issues/3546))
+
+
+
+## [v1.7.0](https://github.com/argoproj/argo-rollouts/compare/v1.7.0-rc1...v1.7.0) (2024-06-12)
+
+### Fix
+
+* verify the weight of the alb at the end of the rollout ([#3627](https://github.com/argoproj/argo-rollouts/issues/3627))
+* when Rollout has pingpong and stable/canary service defined, only alb traffic management uses pingpong. ([#3628](https://github.com/argoproj/argo-rollouts/issues/3628))
+* protocol missing in ambassador canary mapping creation. Fixes [#3593](https://github.com/argoproj/argo-rollouts/issues/3593) ([#3603](https://github.com/argoproj/argo-rollouts/issues/3603))
+* rs conflict with fallback to patch ([#3559](https://github.com/argoproj/argo-rollouts/issues/3559))
+* **controller:** Corrects the logic of comparing sha256 has. Fixes [#3519](https://github.com/argoproj/argo-rollouts/issues/3519) ([#3520](https://github.com/argoproj/argo-rollouts/issues/3520))
+
## [v1.7.0-rc1](https://github.com/argoproj/argo-rollouts/compare/v1.6.6...v1.7.0-rc1) (2024-04-03)
diff --git a/Makefile b/Makefile
index fd5736aa15..609cb724d9 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ DEV_IMAGE ?= false
E2E_INSTANCE_ID ?= argo-rollouts-e2e
E2E_TEST_OPTIONS ?=
E2E_PARALLEL ?= 1
-E2E_WAIT_TIMEOUT ?= 120
+E2E_WAIT_TIMEOUT ?= 90
GOPATH ?= $(shell go env GOPATH)
# Global toolchain configuration
diff --git a/docs/assets/versions.js b/docs/assets/versions.js
index 1336443d1a..fe0aeb1d3c 100644
--- a/docs/assets/versions.js
+++ b/docs/assets/versions.js
@@ -1,15 +1,40 @@
-setTimeout(function() {
- const callbackName = 'callback_' + new Date().getTime();
- window[callbackName] = function (response) {
- const div = document.createElement('div');
- div.innerHTML = response.html;
- document.querySelector(".md-header__inner > .md-header__title").appendChild(div);
- const container = div.querySelector('.rst-versions');
- var caret = document.createElement('div');
- caret.innerHTML = ""
- caret.classList.add('dropdown-caret')
- div.querySelector('.rst-current-version').appendChild(caret);
+const targetNode = document.querySelector('.md-header__inner');
+const observerOptions = {
+ childList: true,
+ subtree: true
+};
+
+const observerCallback = function(mutationsList, observer) {
+ for (let mutation of mutationsList) {
+ if (mutation.type === 'childList') {
+ const titleElement = document.querySelector('.md-header__inner > .md-header__title');
+ if (titleElement) {
+ initializeVersionDropdown();
+ observer.disconnect();
+ }
+ }
}
+};
+
+const observer = new MutationObserver(observerCallback);
+observer.observe(targetNode, observerOptions);
+
+function initializeVersionDropdown() {
+ const callbackName = 'callback_' + new Date().getTime();
+ window[callbackName] = function(response) {
+ const div = document.createElement('div');
+ div.innerHTML = response.html;
+ document.querySelector(".md-header__inner > .md-header__title").appendChild(div);
+ const container = div.querySelector('.rst-versions');
+ var caret = document.createElement('div');
+ caret.innerHTML = "";
+ caret.classList.add('dropdown-caret');
+ div.querySelector('.rst-current-version').appendChild(caret);
+
+ div.querySelector('.rst-current-version').addEventListener('click', function() {
+ container.classList.toggle('shift-up');
+ });
+ };
var CSSLink = document.createElement('link');
CSSLink.rel='stylesheet';
@@ -20,6 +45,31 @@ setTimeout(function() {
script.src = 'https://argo-rollouts.readthedocs.io/_/api/v2/footer_html/?'+
'callback=' + callbackName + '&project=argo-rollouts&page=&theme=mkdocs&format=jsonp&docroot=docs&source_suffix=.md&version=' + (window['READTHEDOCS_DATA'] || { version: 'latest' }).version;
document.getElementsByTagName('head')[0].appendChild(script);
-}, 0);
-
+}
+// VERSION WARNINGS
+window.addEventListener("DOMContentLoaded", function() {
+ var currentVersion = window.location.href.match(/\/en\/(release-(?:v\d+|\w+)|latest|stable)\//);
+ var margin = 30;
+ var headerHeight = document.getElementsByClassName("md-header")[0].offsetHeight;
+ if (currentVersion && currentVersion.length > 1) {
+ currentVersion = currentVersion[1];
+ if (currentVersion === "latest") {
+ document.querySelector("div[data-md-component=announce]").innerHTML = "
";
+ var bannerHeight = document.getElementById('announce-msg').offsetHeight + margin;
+ document.querySelector("header.md-header").style.top = bannerHeight + "px";
+ document.querySelector('style').textContent +=
+ "@media screen and (min-width: 76.25em){ .md-sidebar { height: 0; top:" + (bannerHeight + headerHeight) + "px !important; }}";
+ document.querySelector('style').textContent +=
+ "@media screen and (min-width: 60em){ .md-sidebar--secondary { height: 0; top:" + (bannerHeight + headerHeight) + "px !important; }}";
+ } else if (currentVersion !== "stable") {
+ document.querySelector("div[data-md-component=announce]").innerHTML = "";
+ var bannerHeight = document.getElementById('announce-msg').offsetHeight + margin;
+ document.querySelector("header.md-header").style.top = bannerHeight + "px";
+ document.querySelector('style').textContent +=
+ "@media screen and (min-width: 76.25em){ .md-sidebar { height: 0; top:" + (bannerHeight + headerHeight) + "px !important; }}";
+ document.querySelector('style').textContent +=
+ "@media screen and (min-width: 60em){ .md-sidebar--secondary { height: 0; top:" + (bannerHeight + headerHeight) + "px !important; }}";
+ }
+ }
+});
\ No newline at end of file
diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json
index 038ebebf89..b7ca35204f 100644
--- a/docs/features/kustomize/rollout_cr_schema.json
+++ b/docs/features/kustomize/rollout_cr_schema.json
@@ -244,7 +244,6 @@
"datadog": {
"properties": {
"aggregator": {
- "default": "last",
"enum": [
"avg",
"min",
@@ -5082,7 +5081,6 @@
"datadog": {
"properties": {
"aggregator": {
- "default": "last",
"enum": [
"avg",
"min",
@@ -9933,7 +9931,6 @@
"datadog": {
"properties": {
"aggregator": {
- "default": "last",
"enum": [
"avg",
"min",
diff --git a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_dashboard.md b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_dashboard.md
index eb6ee9e6fc..ad99bfb5ca 100644
--- a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_dashboard.md
+++ b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_dashboard.md
@@ -10,6 +10,16 @@ Start UI dashboard
kubectl argo rollouts dashboard [flags]
```
+## Examples
+
+```shell
+# Start UI dashboard
+kubectl argo rollouts dashboard
+
+# Start UI dashboard on a specific port
+kubectl argo rollouts dashboard --port 8080
+```
+
## Options
```
diff --git a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_get_rollout.md b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_get_rollout.md
index 77b04d2217..4654f2f9c5 100644
--- a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_get_rollout.md
+++ b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_get_rollout.md
@@ -30,6 +30,9 @@ kubectl argo rollouts get rollout guestbook
# Watch progress of a rollout
kubectl argo rollouts get rollout guestbook -w
+
+# Watch the rollout, fail if it takes more than 60 seconds
+kubectl argo rollouts get rollout guestbook -w --timeout-seconds 60
```
## Options
diff --git a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_list_experiments.md b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_list_experiments.md
index 4add56c247..39d9f902bb 100644
--- a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_list_experiments.md
+++ b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_list_experiments.md
@@ -26,7 +26,7 @@ kubectl argo rollouts list experiments --watch
## Options
```
- --all-namespaces Include all namespaces
+ -A, --all-namespaces Include all namespaces
-h, --help help for experiments
```
diff --git a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_list_rollouts.md b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_list_rollouts.md
index e861ca20c8..7382d88185 100644
--- a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_list_rollouts.md
+++ b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_list_rollouts.md
@@ -16,6 +16,9 @@ kubectl argo rollouts list rollouts [flags]
# List rollouts
kubectl argo rollouts list rollouts
+# List rollouts with a specific name
+kubectl argo rollouts list rollouts --name my-rollout
+
# List rollouts from all namespaces
kubectl argo rollouts list rollouts --all-namespaces
diff --git a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_set_image.md b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_set_image.md
index 5f89a6a506..a25acaa730 100644
--- a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_set_image.md
+++ b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_set_image.md
@@ -13,8 +13,11 @@ kubectl argo rollouts set image ROLLOUT_NAME CONTAINER=IMAGE [flags]
## Examples
```shell
-# Set rollout image
-kubectl argo rollouts set image my-rollout www=image:v2
+# Set rollout image (containers contains 'initContainer', 'container', 'ephemeralContainer')
+kubectl argo rollouts set image my-rollout containerName=imageName
+
+# Set rollout image for all containers
+kubectl argo rollouts set image my-rollout *=imageName
```
## Options
diff --git a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_status.md b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_status.md
index e1221d4056..4bfff8b586 100644
--- a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_status.md
+++ b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_status.md
@@ -17,6 +17,9 @@ kubectl argo rollouts status ROLLOUT_NAME [flags]
# Watch the rollout until it succeeds
kubectl argo rollouts status guestbook
+# Show the rollout status
+kubectl argo rollouts status guestbook --watch false
+
# Watch the rollout until it succeeds, fail if it takes more than 60 seconds
kubectl argo rollouts status --timeout 60s guestbook
diff --git a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_terminate.md b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_terminate.md
index 4491cca5fe..21881976dc 100644
--- a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_terminate.md
+++ b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_terminate.md
@@ -13,7 +13,7 @@ kubectl argo rollouts terminate RESOURCE_NAME [flags]
## Examples
```shell
-# Terminate an analysisRun
+# Terminate an AnalysisRun
kubectl argo rollouts terminate analysisrun guestbook-877894d5b-4-success-rate.1
# Terminate a failed experiment
diff --git a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_terminate_analysisrun.md b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_terminate_analysisrun.md
index 268b7a0150..3ff552e97a 100644
--- a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_terminate_analysisrun.md
+++ b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_terminate_analysisrun.md
@@ -14,7 +14,7 @@ kubectl argo rollouts terminate analysisrun ANALYSISRUN_NAME [flags]
```shell
# Terminate an AnalysisRun
-kubectl argo rollouts terminate analysis guestbook-877894d5b-4-success-rate.1
+kubectl argo rollouts terminate analysisrun guestbook-877894d5b-4-success-rate.1
```
## Options
diff --git a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_undo.md b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_undo.md
index 0ddf539dc9..e6d95a203b 100644
--- a/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_undo.md
+++ b/docs/generated/kubectl-argo-rollouts/kubectl-argo-rollouts_undo.md
@@ -16,7 +16,7 @@ kubectl argo rollouts undo ROLLOUT_NAME [flags]
# Undo a rollout
kubectl argo rollouts undo guestbook
-# Undo a rollout revision 3
+# Undo a rollout to revision 3
kubectl argo rollouts undo guestbook --to-revision=3
```
diff --git a/go.mod b/go.mod
index 20585676c7..c970f0110c 100644
--- a/go.mod
+++ b/go.mod
@@ -8,11 +8,11 @@ require (
github.com/antonmedv/expr v1.15.5
github.com/argoproj/notifications-engine v0.4.1-0.20240219110818-7a069766e954
github.com/argoproj/pkg v0.13.6
- github.com/aws/aws-sdk-go-v2 v1.26.1
- github.com/aws/aws-sdk-go-v2/config v1.27.11
- github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.38.0
- github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.30.5
- github.com/aws/smithy-go v1.20.2
+ github.com/aws/aws-sdk-go-v2 v1.30.1
+ github.com/aws/aws-sdk-go-v2/config v1.27.23
+ github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.40.1
+ github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.31.3
+ github.com/aws/smithy-go v1.20.3
github.com/blang/semver v3.5.1+incompatible
github.com/bombsimon/logrusr/v4 v4.1.0
github.com/evanphx/json-patch/v5 v5.9.0
@@ -20,7 +20,7 @@ require (
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.4
github.com/grpc-ecosystem/grpc-gateway v1.16.0
- github.com/hashicorp/go-plugin v1.6.0
+ github.com/hashicorp/go-plugin v1.6.1
github.com/influxdata/influxdb-client-go/v2 v2.13.0
github.com/juju/ansiterm v1.0.0
github.com/machinebox/graphql v0.2.2
@@ -35,14 +35,14 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/soheilhy/cmux v0.1.5
github.com/spaceapegames/go-wavefront v1.8.1
- github.com/spf13/cobra v1.8.0
+ github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
github.com/tj/assert v0.0.3
github.com/valyala/fasttemplate v1.2.2
- golang.org/x/oauth2 v0.19.0
- google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de
- google.golang.org/grpc v1.63.2
- google.golang.org/protobuf v1.34.0
+ golang.org/x/oauth2 v0.21.0
+ google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157
+ google.golang.org/grpc v1.65.0
+ google.golang.org/protobuf v1.34.2
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.29.3
k8s.io/apiextensions-apiserver v0.29.3
@@ -61,8 +61,7 @@ require (
)
require (
- cloud.google.com/go/compute v1.24.0 // indirect
- cloud.google.com/go/compute/metadata v0.2.3 // indirect
+ cloud.google.com/go/compute/metadata v0.3.0 // indirect
github.com/PagerDuty/go-pagerduty v1.7.0 // indirect
github.com/bradleyfalzon/ghinstallation/v2 v2.5.0 // indirect
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 // indirect
@@ -83,21 +82,21 @@ require (
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
github.com/aws/aws-sdk-go v1.44.116 // indirect
- github.com/aws/aws-sdk-go-v2/credentials v1.17.11 // indirect
- github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
- github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
- github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
+ github.com/aws/aws-sdk-go-v2/credentials v1.17.23 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.29.7 // indirect
- github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect
- github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect
- github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.1 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
- github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
@@ -118,7 +117,7 @@ require (
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
- github.com/golang/glog v1.2.0 // indirect
+ github.com/golang/glog v1.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/cel-go v0.17.7 // indirect
@@ -202,21 +201,21 @@ require (
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.19.0 // indirect
- golang.org/x/crypto v0.21.0 // indirect
+ golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/mod v0.14.0 // indirect
- golang.org/x/net v0.22.0 // indirect
- golang.org/x/sync v0.6.0 // indirect
- golang.org/x/sys v0.18.0 // indirect
- golang.org/x/term v0.18.0 // indirect
- golang.org/x/text v0.14.0 // indirect
+ golang.org/x/net v0.25.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/term v0.20.0 // indirect
+ golang.org/x/text v0.15.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.16.1 // indirect
gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect
gomodules.xyz/notify v0.1.1 // indirect
google.golang.org/api v0.162.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
diff --git a/go.sum b/go.sum
index 818c7d0638..8fbb1d8576 100644
--- a/go.sum
+++ b/go.sum
@@ -19,11 +19,9 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
-cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40=
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
-cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
-cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
+cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
+cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
@@ -98,38 +96,38 @@ github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2z
github.com/aws/aws-sdk-go v1.44.39/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.116 h1:NpLIhcvLWXJZAEwvPj3TDHeqp7DleK6ZUVYyW01WNHY=
github.com/aws/aws-sdk-go v1.44.116/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
-github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA=
-github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
-github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA=
-github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.11 h1:YuIB1dJNf1Re822rriUOTxopaHHvIq0l/pX3fwO+Tzs=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.11/go.mod h1:AQtFPsDH9bI2O+71anW6EKL+NcD7LG3dpKGMV4SShgo=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc=
+github.com/aws/aws-sdk-go-v2 v1.30.1 h1:4y/5Dvfrhd1MxRDD77SrfsDaj8kUkkljU7XE83NPV+o=
+github.com/aws/aws-sdk-go-v2 v1.30.1/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
+github.com/aws/aws-sdk-go-v2/config v1.27.23 h1:Cr/gJEa9NAS7CDAjbnB7tHYb3aLZI2gVggfmSAasDac=
+github.com/aws/aws-sdk-go-v2/config v1.27.23/go.mod h1:WMMYHqLCFu5LH05mFOF5tsq1PGEMfKbu083VKqLCd0o=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.23 h1:G1CfmLVoO2TdQ8z9dW+JBc/r8+MqyPQhXCafNZcXVZo=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.23/go.mod h1:V/DvSURn6kKgcuKEk4qwSwb/fZ2d++FFARtWSbXnLqY=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 h1:Aznqksmd6Rfv2HQN9cpqIV/lQRMaIpJkLLaJ1ZI76no=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9/go.mod h1:WQr3MY7AxGNxaqAtsDWn+fBxmd4XvLkzeqQ8P1VM0/w=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 h1:5SAoZ4jYpGH4721ZNoS1znQrhOfZinOhc4XuTXx/nVc=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13/go.mod h1:+rdA6ZLpaSeM7tSg/B0IEDinCIBJGmW8rKDFkYpP04g=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 h1:WIijqeaAO7TYFLbhsZmi2rgLEAtWOC1LhxCAVTJlSKw=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13/go.mod h1:i+kbfa76PQbWw/ULoWnp51EYVWH4ENln76fLQE3lXT8=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
-github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.38.0 h1:vAfGwYFCcPDS9Bg7ckfMBer6olJLOHsOAVoKWpPIirs=
-github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.38.0/go.mod h1:U12sr6Lt14X96f16t+rR52+2BdqtydwN7DjEEHRMjO0=
-github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.30.5 h1:/x2u/TOx+n17U+gz98TOw1HKJom0EOqrhL4SjrHr0cQ=
-github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.30.5/go.mod h1:e1McVqsud0JOERidvppLEHnuCdh/X6MRyL5L0LseAUk=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk=
+github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.40.1 h1:8OMF4iAIxBNN5UOob6yNsYM+HomJeNwVN7Sqn2eL2cg=
+github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.40.1/go.mod h1:5BOwwahrrkipxamulWdV15zlwDHyxRXUBtWZX8cjZnA=
+github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.31.3 h1:Avh8YS+sgb2OKRht0wdNwY8tqtsCzVrmc8dG8Wfy9LI=
+github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.31.3/go.mod h1:HbtHaw/hnNPaiqcyYnheILVyn81wOZiX9n2gYF5tPmM=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15 h1:I9zMeF107l0rJrpnHpjEiiTSCKYAIw8mALiXcPsGBiA=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15/go.mod h1:9xWJ3Q/S6Ojusz1UIkfycgD1mGirJfLLKqq3LPT7WN8=
github.com/aws/aws-sdk-go-v2/service/sqs v1.29.7 h1:tRNrFDGRm81e6nTX5Q4CFblea99eAfm0dxXazGpLceU=
github.com/aws/aws-sdk-go-v2/service/sqs v1.29.7/go.mod h1:8GWUDux5Z2h6z2efAtr54RdHXtLm8sq7Rg85ZNY/CZM=
-github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 h1:vN8hEbpRnL7+Hopy9dzmRle1xmDc7o8tmY0klsr175w=
-github.com/aws/aws-sdk-go-v2/service/sso v1.20.5/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak=
-github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU=
-github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw=
-github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
-github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 h1:p1GahKIjyMDZtiKoIn0/jAj/TkMzfzndDv5+zi2Mhgc=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.1/go.mod h1:/vWdhoIoYA5hYoPZ6fm7Sv4d8701PiG5VKe8/pPJL60=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.1 h1:lCEv9f8f+zJ8kcFeAjRZsekLd/x5SAm96Cva+VbUdo8=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.1/go.mod h1:xyFHA4zGxgYkdD73VeezHt3vSKEG9EmFnGwoKlP00u4=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 h1:+woJ607dllHJQtsnJLi52ycuqHMwlW+Wqm2Ppsfp4nQ=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.1/go.mod h1:jiNR3JqT15Dm+QWq2SRgh0x0bCNSRP2L25+CqPNpJlQ=
+github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
+github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -156,8 +154,8 @@ github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqy
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -168,8 +166,8 @@ github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtM
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
-github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
+github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
+github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
@@ -177,7 +175,7 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
@@ -286,8 +284,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
-github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
+github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
+github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -416,8 +414,8 @@ github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/S
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU=
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A=
-github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI=
+github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI=
+github.com/hashicorp/go-plugin v1.6.1/go.mod h1:XPHFku2tFo3o3QKFgSYo+cghcUhw1NA1hZyMK0PWAw0=
github.com/hashicorp/go-retryablehttp v0.5.1/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
@@ -661,8 +659,8 @@ github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
-github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
-github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -785,8 +783,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
-golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
-golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -871,8 +869,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
-golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -880,8 +878,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
-golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
-golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
+golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
+golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -895,8 +893,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -963,8 +961,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -973,8 +971,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
-golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
-golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -987,8 +985,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1114,10 +1112,10 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
-google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0=
-google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
+google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1132,8 +1130,8 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
-google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1147,8 +1145,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4=
-google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
diff --git a/hack/gen-crd-spec/main.go b/hack/gen-crd-spec/main.go
index a3e31d92b8..60c1bde9d7 100644
--- a/hack/gen-crd-spec/main.go
+++ b/hack/gen-crd-spec/main.go
@@ -96,11 +96,12 @@ func NewCustomResourceDefinition() []*extensionsobj.CustomResourceDefinition {
// clean up stuff left by controller-gen
deleteFile("config/webhook/manifests.yaml")
deleteFile("config/webhook")
- deleteFile("config/argoproj.io_analysisruns.yaml")
- deleteFile("config/argoproj.io_analysistemplates.yaml")
- deleteFile("config/argoproj.io_clusteranalysistemplates.yaml")
- deleteFile("config/argoproj.io_experiments.yaml")
- deleteFile("config/argoproj.io_rollouts.yaml")
+ deleteFile("config/crd/argoproj.io_analysisruns.yaml")
+ deleteFile("config/crd/argoproj.io_analysistemplates.yaml")
+ deleteFile("config/crd/argoproj.io_clusteranalysistemplates.yaml")
+ deleteFile("config/crd/argoproj.io_experiments.yaml")
+ deleteFile("config/crd/argoproj.io_rollouts.yaml")
+ deleteFile("config/crd")
deleteFile("config")
crds := []*extensionsobj.CustomResourceDefinition{}
diff --git a/manifests/base/argo-rollouts-deployment.yaml b/manifests/base/argo-rollouts-deployment.yaml
index 046a1a0bba..285617fde4 100644
--- a/manifests/base/argo-rollouts-deployment.yaml
+++ b/manifests/base/argo-rollouts-deployment.yaml
@@ -52,7 +52,20 @@ spec:
readOnlyRootFilesystem: true
seccompProfile:
type: RuntimeDefault
+ resources:
+ limits:
+ ephemeral-storage: 1Gi
+ volumeMounts:
+ - name: plugin-bin
+ mountPath: /home/argo-rollouts/plugin-bin
+ - name: tmp
+ mountPath: /tmp
securityContext:
runAsNonRoot: true
+ volumes:
+ - name: plugin-bin
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
strategy:
type: RollingUpdate
diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml
index c8088911b6..816702aa04 100644
--- a/manifests/crds/analysis-run-crd.yaml
+++ b/manifests/crds/analysis-run-crd.yaml
@@ -179,7 +179,6 @@ spec:
datadog:
properties:
aggregator:
- default: last
enum:
- avg
- min
diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml
index 3cd6ec81a4..3bcf3855ad 100644
--- a/manifests/crds/analysis-template-crd.yaml
+++ b/manifests/crds/analysis-template-crd.yaml
@@ -175,7 +175,6 @@ spec:
datadog:
properties:
aggregator:
- default: last
enum:
- avg
- min
diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml
index ab4d887d23..1f97c14bd8 100644
--- a/manifests/crds/cluster-analysis-template-crd.yaml
+++ b/manifests/crds/cluster-analysis-template-crd.yaml
@@ -175,7 +175,6 @@ spec:
datadog:
properties:
aggregator:
- default: last
enum:
- avg
- min
diff --git a/manifests/install.yaml b/manifests/install.yaml
index dfb8d18768..1b8eec6d69 100755
--- a/manifests/install.yaml
+++ b/manifests/install.yaml
@@ -180,7 +180,6 @@ spec:
datadog:
properties:
aggregator:
- default: last
enum:
- avg
- min
@@ -3470,7 +3469,6 @@ spec:
datadog:
properties:
aggregator:
- default: last
enum:
- avg
- min
@@ -6638,7 +6636,6 @@ spec:
datadog:
properties:
aggregator:
- default: last
enum:
- avg
- min
@@ -16420,6 +16417,7 @@ rules:
- get
- list
- watch
+ - update
- apiGroups:
- ""
resources:
@@ -16757,6 +16755,9 @@ spec:
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 4
+ resources:
+ limits:
+ ephemeral-storage: 1Gi
securityContext:
allowPrivilegeEscalation: false
capabilities:
@@ -16765,6 +16766,16 @@ spec:
readOnlyRootFilesystem: true
seccompProfile:
type: RuntimeDefault
+ volumeMounts:
+ - mountPath: /home/argo-rollouts/plugin-bin
+ name: plugin-bin
+ - mountPath: /tmp
+ name: tmp
securityContext:
runAsNonRoot: true
serviceAccountName: argo-rollouts
+ volumes:
+ - emptyDir: {}
+ name: plugin-bin
+ - emptyDir: {}
+ name: tmp
diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml
index 0a7adf80ed..16ea68f99c 100644
--- a/manifests/namespace-install.yaml
+++ b/manifests/namespace-install.yaml
@@ -75,6 +75,7 @@ rules:
- get
- list
- watch
+ - update
- apiGroups:
- ""
resources:
@@ -413,6 +414,9 @@ spec:
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 4
+ resources:
+ limits:
+ ephemeral-storage: 1Gi
securityContext:
allowPrivilegeEscalation: false
capabilities:
@@ -421,6 +425,16 @@ spec:
readOnlyRootFilesystem: true
seccompProfile:
type: RuntimeDefault
+ volumeMounts:
+ - mountPath: /home/argo-rollouts/plugin-bin
+ name: plugin-bin
+ - mountPath: /tmp
+ name: tmp
securityContext:
runAsNonRoot: true
serviceAccountName: argo-rollouts
+ volumes:
+ - emptyDir: {}
+ name: plugin-bin
+ - emptyDir: {}
+ name: tmp
diff --git a/manifests/role/argo-rollouts-clusterrole.yaml b/manifests/role/argo-rollouts-clusterrole.yaml
index aab253e5ea..b43ed1adef 100644
--- a/manifests/role/argo-rollouts-clusterrole.yaml
+++ b/manifests/role/argo-rollouts-clusterrole.yaml
@@ -67,6 +67,7 @@ rules:
- get
- list
- watch
+ - update
# services patch needed to update selector of canary/stable/active/preview services
# services create needed to create and delete services for experiments
- apiGroups:
diff --git a/metricproviders/datadog/datadog_test.go b/metricproviders/datadog/datadog_test.go
index fe817f385e..ed81977296 100644
--- a/metricproviders/datadog/datadog_test.go
+++ b/metricproviders/datadog/datadog_test.go
@@ -66,12 +66,6 @@ func TestDatadogSpecDefaults(t *testing.T) {
assert.Equal(t, "\"l2norm\"", string(aggregatorEnums[7].Raw), "\"l2norm\" expected, got %s", string(aggregatorEnums[7].Raw))
assert.Equal(t, "\"area\"", string(aggregatorEnums[8].Raw), "\"area\" expected, got %s", string(aggregatorEnums[8].Raw))
})
-
- t.Run("aggregator: Validate default is last", func(t *testing.T) {
- defaultAggregator := string(ddSpec.Properties["aggregator"].Default.Raw)
- assert.Equal(t, "\"last\"", defaultAggregator, "Default aggregator should be \"last\" ")
- })
-
}
func TestValidateIncomingProps(t *testing.T) {
diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json
index b3c10e03f8..3a74f48a24 100755
--- a/pkg/apiclient/rollout/rollout.swagger.json
+++ b/pkg/apiclient/rollout/rollout.swagger.json
@@ -1205,7 +1205,7 @@
},
"aggregator": {
"type": "string",
- "title": "+kubebuilder:default=\"last\"\n+kubebuilder:validation:Enum=avg;min;max;sum;last;percentile;mean;l2norm;area\nAggregator is a type of aggregator to use for metrics-based queries (default: last). Used for v2"
+ "title": "+kubebuilder:validation:Enum=avg;min;max;sum;last;percentile;mean;l2norm;area\nAggregator is a type of aggregator to use for metrics-based queries (default: \"\"). Used for v2"
}
}
},
diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go
index 08ef18071f..3a287ec856 100644
--- a/pkg/apis/rollouts/v1alpha1/analysis_types.go
+++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go
@@ -601,8 +601,7 @@ type DatadogMetric struct {
// +kubebuilder:validation:Enum=v1;v2
// +kubebuilder:default=v1
ApiVersion string `json:"apiVersion,omitempty" protobuf:"bytes,5,opt,name=apiVersion"`
- // +kubebuilder:default="last"
// +kubebuilder:validation:Enum=avg;min;max;sum;last;percentile;mean;l2norm;area
- // Aggregator is a type of aggregator to use for metrics-based queries (default: last). Used for v2
+ // Aggregator is a type of aggregator to use for metrics-based queries (default: ""). Used for v2
Aggregator string `json:"aggregator,omitempty" protobuf:"bytes,6,opt,name=aggregator"`
}
diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto
index 0ea0a7bc2c..eebb4453cc 100644
--- a/pkg/apis/rollouts/v1alpha1/generated.proto
+++ b/pkg/apis/rollouts/v1alpha1/generated.proto
@@ -655,9 +655,8 @@ message DatadogMetric {
// +kubebuilder:default=v1
optional string apiVersion = 5;
- // +kubebuilder:default="last"
// +kubebuilder:validation:Enum=avg;min;max;sum;last;percentile;mean;l2norm;area
- // Aggregator is a type of aggregator to use for metrics-based queries (default: last). Used for v2
+ // Aggregator is a type of aggregator to use for metrics-based queries (default: ""). Used for v2
optional string aggregator = 6;
}
diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go
index 2d4d68ff1e..6c18e64a2b 100644
--- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go
+++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go
@@ -1935,7 +1935,7 @@ func schema_pkg_apis_rollouts_v1alpha1_DatadogMetric(ref common.ReferenceCallbac
},
"aggregator": {
SchemaProps: spec.SchemaProps{
- Description: "Aggregator is a type of aggregator to use for metrics-based queries (default: last). Used for v2",
+ Description: "Aggregator is a type of aggregator to use for metrics-based queries (default: \"\"). Used for v2",
Type: []string{"string"},
Format: "",
},
diff --git a/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go b/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go
index f0c720df72..468d0437c6 100644
--- a/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go
+++ b/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go
@@ -8,12 +8,22 @@ import (
"github.com/spf13/cobra"
)
+var (
+ dashBoardExample = `
+ # Start UI dashboard
+ %[1]s dashboard
+
+ # Start UI dashboard on a specific port
+ %[1]s dashboard --port 8080`
+)
+
func NewCmdDashboard(o *options.ArgoRolloutsOptions) *cobra.Command {
var rootPath string
var port int
var cmd = &cobra.Command{
- Use: "dashboard",
- Short: "Start UI dashboard",
+ Use: "dashboard",
+ Short: "Start UI dashboard",
+ Example: o.Example(dashBoardExample),
RunE: func(c *cobra.Command, args []string) error {
namespace := o.Namespace()
kubeclientset := o.KubeClientset()
diff --git a/pkg/kubectl-argo-rollouts/cmd/get/get_rollout.go b/pkg/kubectl-argo-rollouts/cmd/get/get_rollout.go
index f5b0719509..dd56693a45 100644
--- a/pkg/kubectl-argo-rollouts/cmd/get/get_rollout.go
+++ b/pkg/kubectl-argo-rollouts/cmd/get/get_rollout.go
@@ -25,7 +25,10 @@ const (
%[1]s get rollout guestbook
# Watch progress of a rollout
- %[1]s get rollout guestbook -w`
+ %[1]s get rollout guestbook -w
+
+ # Watch the rollout, fail if it takes more than 60 seconds
+ %[1]s get rollout guestbook -w --timeout-seconds 60`
)
// NewCmdGetRollout returns a new instance of an `rollouts get rollout` command
diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go
index 810abf2c8e..4d8a268994 100644
--- a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go
+++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go
@@ -53,12 +53,7 @@ func NewCmdLint(o *options.ArgoRolloutsOptions) *cobra.Command {
return o.UsageErr(c)
}
- err := lintOptions.lintResource(lintOptions.File)
- if err != nil {
- return err
- }
-
- return nil
+ return lintOptions.lintResource(lintOptions.File)
},
}
cmd.Flags().StringVarP(&lintOptions.File, "filename", "f", "", "File to lint")
diff --git a/pkg/kubectl-argo-rollouts/cmd/list/list_experiments.go b/pkg/kubectl-argo-rollouts/cmd/list/list_experiments.go
index cb83a157fa..962b4d6ce4 100644
--- a/pkg/kubectl-argo-rollouts/cmd/list/list_experiments.go
+++ b/pkg/kubectl-argo-rollouts/cmd/list/list_experiments.go
@@ -62,7 +62,7 @@ func NewCmdListExperiments(o *options.ArgoRolloutsOptions) *cobra.Command {
return nil
},
}
- cmd.Flags().BoolVar(&listOptions.allNamespaces, "all-namespaces", false, "Include all namespaces")
+ cmd.Flags().BoolVarP(&listOptions.allNamespaces, "all-namespaces", "A", false, "Include all namespaces")
return cmd
}
diff --git a/pkg/kubectl-argo-rollouts/cmd/list/list_rollouts.go b/pkg/kubectl-argo-rollouts/cmd/list/list_rollouts.go
index 6746876767..c233776c6d 100644
--- a/pkg/kubectl-argo-rollouts/cmd/list/list_rollouts.go
+++ b/pkg/kubectl-argo-rollouts/cmd/list/list_rollouts.go
@@ -18,6 +18,9 @@ const (
listRolloutsExample = `
# List rollouts
%[1]s list rollouts
+
+ # List rollouts with a specific name
+ %[1]s list rollouts --name my-rollout
# List rollouts from all namespaces
%[1]s list rollouts --all-namespaces
diff --git a/pkg/kubectl-argo-rollouts/cmd/set/set_image.go b/pkg/kubectl-argo-rollouts/cmd/set/set_image.go
index 1a5b5dce24..942db298bc 100644
--- a/pkg/kubectl-argo-rollouts/cmd/set/set_image.go
+++ b/pkg/kubectl-argo-rollouts/cmd/set/set_image.go
@@ -19,8 +19,11 @@ import (
const (
setImageExample = `
- # Set rollout image
- %[1]s set image my-rollout www=image:v2`
+ # Set rollout image (containers contains 'initContainer', 'container', 'ephemeralContainer')
+ %[1]s set image my-rollout containerName=imageName
+
+ # Set rollout image for all containers
+ %[1]s set image my-rollout *=imageName`
)
const (
diff --git a/pkg/kubectl-argo-rollouts/cmd/status/status.go b/pkg/kubectl-argo-rollouts/cmd/status/status.go
index 79d7272d88..33d6652900 100644
--- a/pkg/kubectl-argo-rollouts/cmd/status/status.go
+++ b/pkg/kubectl-argo-rollouts/cmd/status/status.go
@@ -20,6 +20,9 @@ the rollout is healthy upon completion and an error otherwise.`
# Watch the rollout until it succeeds
%[1]s status guestbook
+ # Show the rollout status
+ %[1]s status guestbook --watch false
+
# Watch the rollout until it succeeds, fail if it takes more than 60 seconds
%[1]s status --timeout 60s guestbook
`
diff --git a/pkg/kubectl-argo-rollouts/cmd/terminate/terminate.go b/pkg/kubectl-argo-rollouts/cmd/terminate/terminate.go
index f0dd7e91b1..c4123f0e78 100644
--- a/pkg/kubectl-argo-rollouts/cmd/terminate/terminate.go
+++ b/pkg/kubectl-argo-rollouts/cmd/terminate/terminate.go
@@ -18,7 +18,7 @@ const (
const (
terminateExample = `
- # Terminate an analysisRun
+ # Terminate an AnalysisRun
%[1]s terminate analysisrun guestbook-877894d5b-4-success-rate.1
# Terminate a failed experiment
@@ -26,7 +26,7 @@ const (
terminateAnalysisRunExample = `
# Terminate an AnalysisRun
- %[1]s terminate analysis guestbook-877894d5b-4-success-rate.1`
+ %[1]s terminate analysisrun guestbook-877894d5b-4-success-rate.1`
terminateExperimentExample = `
# Terminate an experiment
diff --git a/pkg/kubectl-argo-rollouts/cmd/undo/undo.go b/pkg/kubectl-argo-rollouts/cmd/undo/undo.go
index d3a78d15f2..be9d0289d7 100644
--- a/pkg/kubectl-argo-rollouts/cmd/undo/undo.go
+++ b/pkg/kubectl-argo-rollouts/cmd/undo/undo.go
@@ -32,7 +32,7 @@ const (
# Undo a rollout
%[1]s undo guestbook
- # Undo a rollout revision 3
+ # Undo a rollout to revision 3
%[1]s undo guestbook --to-revision=3`
)
diff --git a/rollout/analysis.go b/rollout/analysis.go
index 7bb0d47f1f..f23f680ce0 100644
--- a/rollout/analysis.go
+++ b/rollout/analysis.go
@@ -74,8 +74,9 @@ func (c *rolloutContext) reconcileAnalysisRuns() error {
isAborted := c.pauseContext.IsAborted()
rollbackToScaleDownDelay := replicasetutil.HasScaleDownDeadline(c.newRS)
initialDeploy := c.rollout.Status.StableRS == ""
- if isAborted || c.rollout.Status.PromoteFull || rollbackToScaleDownDelay || initialDeploy {
- c.log.Infof("Skipping analysis: isAborted: %v, promoteFull: %v, rollbackToScaleDownDelay: %v, initialDeploy: %v", isAborted, c.rollout.Status.PromoteFull, rollbackToScaleDownDelay, initialDeploy)
+ isRollbackWithinWindow := c.isRollbackWithinWindow()
+ if isAborted || c.rollout.Status.PromoteFull || rollbackToScaleDownDelay || initialDeploy || isRollbackWithinWindow {
+ c.log.Infof("Skipping analysis: isAborted: %v, promoteFull: %v, rollbackToScaleDownDelay: %v, initialDeploy: %v, isRollbackWithinWindow: %v", isAborted, c.rollout.Status.PromoteFull, rollbackToScaleDownDelay, initialDeploy, isRollbackWithinWindow)
allArs := append(c.currentArs.ToArray(), c.otherArs...)
c.SetCurrentAnalysisRuns(c.currentArs)
return c.cancelAnalysisRuns(allArs)
diff --git a/rollout/analysis_test.go b/rollout/analysis_test.go
index 46a741bd63..e12a898c1a 100644
--- a/rollout/analysis_test.go
+++ b/rollout/analysis_test.go
@@ -1918,6 +1918,47 @@ func TestDoNotCreateBackgroundAnalysisRunOnNewCanaryRolloutStableRSEmpty(t *test
f.run(getKey(r1, t))
}
+func TestDoNotCreateBackgroundAnalysisRunWhenWithinRollbackWindow(t *testing.T) {
+ f := newFixture(t)
+ defer f.Close()
+
+ at := analysisTemplate("bar")
+
+ r1 := newCanaryRollout("foo", 1, nil, nil, pointer.Int32Ptr(0), intstr.FromInt(0), intstr.FromInt(1))
+ r1.Spec.Strategy.Canary.Analysis = &v1alpha1.RolloutAnalysisBackground{
+ RolloutAnalysis: v1alpha1.RolloutAnalysis{
+ Templates: []v1alpha1.AnalysisTemplateRef{
+ {
+ TemplateName: at.Name,
+ },
+ },
+ },
+ }
+ r1.Spec.RollbackWindow = &v1alpha1.RollbackWindowSpec{Revisions: 1}
+
+ r2 := bumpVersion(r1)
+ rs1 := newReplicaSetWithStatus(r1, 1, 1)
+ rs2 := newReplicaSetWithStatus(r2, 0, 0)
+
+ rs2.CreationTimestamp = timeutil.MetaTime(time.Now().Add(-1 * time.Hour))
+ rs1.CreationTimestamp = timeutil.MetaNow()
+
+ f.kubeobjects = append(f.kubeobjects, rs1, rs2)
+ f.replicaSetLister = append(f.replicaSetLister, rs1, rs2)
+
+ rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey]
+
+ r2 = updateCanaryRolloutStatus(r2, rs1PodHash, 1, 0, 1, false)
+
+ f.rolloutLister = append(f.rolloutLister, r2)
+ f.analysisTemplateLister = append(f.analysisTemplateLister, at)
+ f.objects = append(f.objects, r2, at)
+
+ f.expectUpdateReplicaSetAction(rs2)
+ f.expectPatchRolloutAction(r2)
+ f.run(getKey(r2, t))
+}
+
func TestCreatePrePromotionAnalysisRun(t *testing.T) {
f := newFixture(t)
defer f.Close()
diff --git a/rollout/canary.go b/rollout/canary.go
index ed27bd0a79..a3033fea02 100644
--- a/rollout/canary.go
+++ b/rollout/canary.go
@@ -112,7 +112,7 @@ func (c *rolloutContext) reconcileCanaryStableReplicaSet() (bool, error) {
}
scaled, _, err := c.scaleReplicaSetAndRecordEvent(c.stableRS, desiredStableRSReplicaCount)
if err != nil {
- return scaled, fmt.Errorf("failed to scaleReplicaSetAndRecordEvent in reconcileCanaryStableReplicaSet:L %w", err)
+ return scaled, fmt.Errorf("failed to scaleReplicaSetAndRecordEvent in reconcileCanaryStableReplicaSet: %w", err)
}
return scaled, err
}
@@ -296,7 +296,7 @@ func (c *rolloutContext) canProceedWithScaleDownAnnotation(oldRSs []*appsv1.Repl
// AWS API calls.
return true, nil
}
- stableSvcName, _ := trafficrouting.GetStableAndCanaryServices(c.rollout)
+ stableSvcName, _ := trafficrouting.GetStableAndCanaryServices(c.rollout, true)
stableSvc, err := c.servicesLister.Services(c.rollout.Namespace).Get(stableSvcName)
if err != nil {
return false, err
diff --git a/rollout/canary_test.go b/rollout/canary_test.go
index 56b05c7177..3d1eec9d14 100644
--- a/rollout/canary_test.go
+++ b/rollout/canary_test.go
@@ -4,10 +4,16 @@ import (
"context"
"encoding/json"
"fmt"
+ "os"
"strconv"
"testing"
"time"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ k8stesting "k8s.io/client-go/testing"
+
"github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/apps/v1"
@@ -2141,3 +2147,106 @@ func TestCanaryReplicaAndSpecChangedTogether(t *testing.T) {
// check the canary one is updated
assert.NotEqual(t, originReplicas, int(*updated.Spec.Replicas))
}
+
+func TestSyncRolloutWithConflictInScaleReplicaSet(t *testing.T) {
+ os.Setenv("ARGO_ROLLOUTS_LOG_RS_DIFF_CONFLICT", "true")
+ defer os.Unsetenv("ARGO_ROLLOUTS_LOG_RS_DIFF_CONFLICT")
+
+ f := newFixture(t)
+ defer f.Close()
+
+ steps := []v1alpha1.CanaryStep{
+ {
+ SetWeight: int32Ptr(10),
+ }, {
+ Pause: &v1alpha1.RolloutPause{
+ Duration: v1alpha1.DurationFromInt(10),
+ },
+ },
+ }
+ r1 := newCanaryRollout("foo", 10, nil, steps, int32Ptr(1), intstr.FromInt(1), intstr.FromInt(0))
+ r1.Spec.Template.Labels["rollout.argoproj.io/foo"] = "bar"
+
+ rs1 := newReplicaSetWithStatus(r1, 10, 10)
+ r1.Spec.Replicas = pointer.Int32(2)
+ f.kubeobjects = append(f.kubeobjects, rs1)
+ f.replicaSetLister = append(f.replicaSetLister, rs1)
+
+ f.rolloutLister = append(f.rolloutLister, r1)
+ f.objects = append(f.objects, r1)
+
+ f.expectPatchRolloutAction(r1)
+ f.expectUpdateReplicaSetAction(rs1) // attempt to scale replicaset but conflict
+ patchIndex := f.expectPatchReplicaSetAction(rs1) // instead of update patch replicaset
+
+ key := fmt.Sprintf("%s/%s", r1.Namespace, r1.Name)
+ c, i, k8sI := f.newController(func() time.Duration { return 30 * time.Minute })
+
+ f.kubeclient.PrependReactor("update", "replicasets", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
+ return true, action.(k8stesting.UpdateAction).GetObject(), errors.NewConflict(schema.GroupResource{
+ Group: "Apps",
+ Resource: "ReplicaSet",
+ }, action.(k8stesting.UpdateAction).GetObject().(*appsv1.ReplicaSet).Name, fmt.Errorf("test error"))
+ })
+
+ f.runController(key, true, false, c, i, k8sI)
+
+ updatedRs := f.getPatchedReplicaSet(patchIndex) // minus one because update did not happen because conflict
+ assert.Equal(t, int32(2), *updatedRs.Spec.Replicas)
+}
+
+func TestSyncRolloutWithConflictInSyncReplicaSetRevision(t *testing.T) {
+ os.Setenv("ARGO_ROLLOUTS_LOG_RS_DIFF_CONFLICT", "true")
+ defer os.Unsetenv("ARGO_ROLLOUTS_LOG_RS_DIFF_CONFLICT")
+
+ f := newFixture(t)
+ defer f.Close()
+
+ steps := []v1alpha1.CanaryStep{
+ {
+ SetWeight: int32Ptr(10),
+ }, {
+ Pause: &v1alpha1.RolloutPause{
+ Duration: v1alpha1.DurationFromInt(10),
+ },
+ },
+ }
+ r1 := newCanaryRollout("foo", 3, nil, steps, int32Ptr(1), intstr.FromInt(1), intstr.FromInt(0))
+ r2 := bumpVersion(r1)
+
+ rs1 := newReplicaSetWithStatus(r1, 3, 3)
+ rs2 := newReplicaSetWithStatus(r2, 3, 3)
+ rs2.Annotations["rollout.argoproj.io/revision"] = "1"
+
+ f.kubeobjects = append(f.kubeobjects, rs1, rs2)
+ f.replicaSetLister = append(f.replicaSetLister, rs1, rs2)
+
+ f.rolloutLister = append(f.rolloutLister, r2)
+ f.objects = append(f.objects, r2)
+
+ key := fmt.Sprintf("%s/%s", r1.Namespace, r1.Name)
+ c, i, k8sI := f.newController(func() time.Duration { return 30 * time.Minute })
+
+ f.kubeclient.PrependReactor("update", "replicasets", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
+ return true, &appsv1.ReplicaSet{}, errors.NewConflict(schema.GroupResource{
+ Group: "Apps",
+ Resource: "ReplicaSet",
+ }, action.(k8stesting.UpdateAction).GetObject().(*appsv1.ReplicaSet).Name, fmt.Errorf("test error"))
+ })
+
+ f.expectPatchRolloutAction(r2)
+ f.expectUpdateReplicaSetAction(rs1) // attempt to update replicaset revision but conflict
+ patchIndex1 := f.expectPatchReplicaSetAction(rs1) // instead of update patch replicaset
+
+ f.expectUpdateReplicaSetAction(rs2) // attempt to scale replicaset but conflict
+ patchIndex2 := f.expectPatchReplicaSetAction(rs2) // instead of update patch replicaset
+
+ f.runController(key, true, false, c, i, k8sI)
+
+ updatedRs1 := f.getPatchedReplicaSet(patchIndex1)
+ assert.Equal(t, "2", updatedRs1.Annotations["rollout.argoproj.io/revision"])
+ assert.Equal(t, int32(3), *updatedRs1.Spec.Replicas)
+
+ updatedRs2 := f.getPatchedReplicaSet(patchIndex2)
+ assert.Equal(t, int32(0), *updatedRs2.Spec.Replicas)
+}
diff --git a/rollout/controller.go b/rollout/controller.go
index 972cea882c..23f7f340dd 100644
--- a/rollout/controller.go
+++ b/rollout/controller.go
@@ -4,11 +4,16 @@ import (
"context"
"encoding/json"
"fmt"
+ "os"
"reflect"
"strconv"
+ "strings"
"sync"
"time"
+ "github.com/argoproj/argo-rollouts/utils/annotations"
+
+ "github.com/argoproj/argo-rollouts/utils/diff"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/argoproj/argo-rollouts/pkg/apis/rollouts"
@@ -16,11 +21,13 @@ import (
log "github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
+ patchtypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/dynamic"
@@ -937,3 +944,92 @@ func remarshalRollout(r *v1alpha1.Rollout) *v1alpha1.Rollout {
}
return &remarshalled
}
+
+// updateReplicaSetWithPatch updates the replicaset using Update and on failure falls back to a patch this function only exists to make sure we always can update
+// replicasets and to not get into an conflict loop updating replicasets. We should really look into a complete refactor of how rollouts handles replicasets such
+// that we do not keep a fully replicaset on the rollout context under newRS and instead switch to a patch only based approach.
+func (c *rolloutContext) updateReplicaSetFallbackToPatch(ctx context.Context, rs *appsv1.ReplicaSet) (*appsv1.ReplicaSet, error) {
+ updatedRS, err := c.kubeclientset.AppsV1().ReplicaSets(rs.Namespace).Update(ctx, rs, metav1.UpdateOptions{})
+ if err != nil {
+ if errors.IsConflict(err) {
+ if os.Getenv("ARGO_ROLLOUTS_LOG_RS_DIFF_CONFLICT") == "true" {
+ rsGet, err := c.replicaSetLister.ReplicaSets(rs.Namespace).Get(rs.Name)
+ if err != nil {
+ return nil, fmt.Errorf("error getting replicaset in updateReplicaSetFallbackToPatch %s: %w", rs.Name, err)
+ }
+ rsGetJson, err := json.Marshal(rsGet)
+ if err != nil {
+ return nil, fmt.Errorf("error marshalling informer replicaset in updateReplicaSetFallbackToPatch %s: %w", rs.Name, err)
+ }
+ rsCopyJson, err := json.Marshal(rs)
+ if err != nil {
+ return nil, fmt.Errorf("error marshalling memory replicaset in updateReplicaSetFallbackToPatch %s: %w", rs.Name, err)
+ }
+ c.log.Infof("Informer RS: %s", rsGetJson)
+ c.log.Infof("Memory RS: %s", rsCopyJson)
+ }
+
+ c.log.Infof("Conflict when updating replicaset %s, falling back to patch", rs.Name)
+
+ patchRS := appsv1.ReplicaSet{}
+ patchRS.Spec.Replicas = rs.Spec.Replicas
+ patchRS.Spec.Template.Labels = rs.Spec.Template.Labels
+ patchRS.Spec.Template.Annotations = rs.Spec.Template.Annotations
+
+ patchRS.Annotations = make(map[string]string)
+ patchRS.Labels = make(map[string]string)
+ patchRS.Spec.Selector = &metav1.LabelSelector{
+ MatchLabels: make(map[string]string),
+ }
+
+ if _, found := rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey]; found {
+ patchRS.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] = rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey]
+ }
+
+ if _, found := rs.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey]; found {
+ patchRS.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = rs.Labels[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey]
+ }
+
+ if _, found := rs.Spec.Selector.MatchLabels[v1alpha1.DefaultRolloutUniqueLabelKey]; found {
+ patchRS.Spec.Selector.MatchLabels[v1alpha1.DefaultRolloutUniqueLabelKey] = rs.Spec.Selector.MatchLabels[v1alpha1.DefaultRolloutUniqueLabelKey]
+ }
+
+ for key, value := range rs.Annotations {
+ if strings.HasPrefix(key, annotations.RolloutLabel) ||
+ strings.HasPrefix(key, "argo-rollouts.argoproj.io") ||
+ strings.HasPrefix(key, "experiment.argoproj.io") {
+ patchRS.Annotations[key] = value
+ }
+ }
+ for key, value := range rs.Labels {
+ if strings.HasPrefix(key, annotations.RolloutLabel) ||
+ strings.HasPrefix(key, "argo-rollouts.argoproj.io") ||
+ strings.HasPrefix(key, "experiment.argoproj.io") {
+ patchRS.Labels[key] = value
+ }
+ }
+
+ patch, _, err := diff.CreateTwoWayMergePatch(appsv1.ReplicaSet{}, patchRS, appsv1.ReplicaSet{})
+ if err != nil {
+ return nil, fmt.Errorf("error creating patch for conflict log in updateReplicaSetFallbackToPatch %s: %w", rs.Name, err)
+ }
+
+ c.log.Infof("Patching replicaset with patch: %s", string(patch))
+ updatedRS, err = c.kubeclientset.AppsV1().ReplicaSets(rs.Namespace).Patch(ctx, rs.Name, patchtypes.StrategicMergePatchType, patch, metav1.PatchOptions{})
+ if err != nil {
+ return nil, fmt.Errorf("error patching replicaset in updateReplicaSetFallbackToPatch %s: %w", rs.Name, err)
+ }
+
+ err = c.replicaSetInformer.GetIndexer().Update(updatedRS)
+ if err != nil {
+ return nil, fmt.Errorf("error updating replicaset informer in updateReplicaSetFallbackToPatch %s: %w", rs.Name, err)
+ }
+
+ return updatedRS, err
+ }
+ }
+ if updatedRS != nil {
+ updatedRS.DeepCopyInto(rs)
+ }
+ return rs, err
+}
diff --git a/rollout/controller_test.go b/rollout/controller_test.go
index 892a2be64f..e38fca79c5 100644
--- a/rollout/controller_test.go
+++ b/rollout/controller_test.go
@@ -792,6 +792,12 @@ func (f *fixture) expectPatchServiceAction(s *corev1.Service, newLabel string) i
return len
}
+func (f *fixture) expectGetReplicaSetAction(r *appsv1.ReplicaSet) int { //nolint:unused
+ len := len(f.kubeactions)
+ f.kubeactions = append(f.kubeactions, core.NewGetAction(schema.GroupVersionResource{Resource: "replicasets"}, r.Namespace, r.Name))
+ return len
+}
+
func (f *fixture) expectCreateReplicaSetAction(r *appsv1.ReplicaSet) int {
len := len(f.kubeactions)
f.kubeactions = append(f.kubeactions, core.NewCreateAction(schema.GroupVersionResource{Resource: "replicasets"}, r.Namespace, r))
@@ -950,6 +956,21 @@ func (f *fixture) getUpdatedReplicaSet(index int) *appsv1.ReplicaSet {
return rs
}
+func (f *fixture) getPatchedReplicaSet(index int) *appsv1.ReplicaSet {
+ action := filterInformerActions(f.kubeclient.Actions())[index]
+ patchAction, ok := action.(core.PatchAction)
+ if !ok {
+ f.t.Fatalf("Expected Patch action, not %s", action.GetVerb())
+ }
+
+ rs := appsv1.ReplicaSet{}
+ err := json.Unmarshal(patchAction.GetPatch(), &rs)
+ if err != nil {
+ panic(err)
+ }
+ return &rs
+}
+
func (f *fixture) verifyPatchedReplicaSet(index int, scaleDownDelaySeconds int32) {
action := filterInformerActions(f.kubeclient.Actions())[index]
patchAction, ok := action.(core.PatchAction)
diff --git a/rollout/ephemeralmetadata.go b/rollout/ephemeralmetadata.go
index 60b745ed29..4f502a78ab 100644
--- a/rollout/ephemeralmetadata.go
+++ b/rollout/ephemeralmetadata.go
@@ -82,14 +82,12 @@ func (c *rolloutContext) syncEphemeralMetadata(ctx context.Context, rs *appsv1.R
}
// 2. Update ReplicaSet so that any new pods it creates will have the metadata
- rs, err = c.kubeclientset.AppsV1().ReplicaSets(modifiedRS.Namespace).Update(ctx, modifiedRS, metav1.UpdateOptions{})
+ rs, err = c.updateReplicaSetFallbackToPatch(ctx, modifiedRS)
if err != nil {
- return fmt.Errorf("error updating replicaset in syncEphemeralMetadata: %w", err)
- }
- err = c.replicaSetInformer.GetIndexer().Update(rs)
- if err != nil {
- return fmt.Errorf("error updating replicaset informer in syncEphemeralMetadata: %w", err)
+ c.log.Infof("failed to sync ephemeral metadata %v to ReplicaSet %s: %v", podMetadata, rs.Name, err)
+ return fmt.Errorf("failed to sync ephemeral metadata: %w", err)
}
+
c.log.Infof("synced ephemeral metadata %v to ReplicaSet %s", podMetadata, rs.Name)
return nil
}
diff --git a/rollout/service.go b/rollout/service.go
index 69739b9315..c0904ffd23 100644
--- a/rollout/service.go
+++ b/rollout/service.go
@@ -243,7 +243,7 @@ func (c *rolloutContext) getPreviewAndActiveServices() (*corev1.Service, *corev1
func (c *rolloutContext) reconcilePingAndPongService() error {
if trafficrouting.IsPingPongEnabled(c.rollout) && !rolloututils.IsFullyPromoted(c.rollout) {
- _, canaryService := trafficrouting.GetStableAndCanaryServices(c.rollout)
+ _, canaryService := trafficrouting.GetStableAndCanaryServices(c.rollout, true)
return c.ensureSVCTargets(canaryService, c.newRS, false)
}
return nil
diff --git a/rollout/sync.go b/rollout/sync.go
index 875949ee55..6d656e2d5a 100644
--- a/rollout/sync.go
+++ b/rollout/sync.go
@@ -83,17 +83,13 @@ func (c *rolloutContext) syncReplicaSetRevision() (*appsv1.ReplicaSet, error) {
affinityNeedsUpdate := replicasetutil.IfInjectedAntiAffinityRuleNeedsUpdate(rsCopy.Spec.Template.Spec.Affinity, *c.rollout)
if annotationsUpdated || minReadySecondsNeedsUpdate || affinityNeedsUpdate {
+
rsCopy.Spec.MinReadySeconds = c.rollout.Spec.MinReadySeconds
rsCopy.Spec.Template.Spec.Affinity = replicasetutil.GenerateReplicaSetAffinity(*c.rollout)
- rs, err := c.kubeclientset.AppsV1().ReplicaSets(rsCopy.ObjectMeta.Namespace).Update(ctx, rsCopy, metav1.UpdateOptions{})
- if err != nil {
- c.log.WithError(err).Error("Error: updating replicaset revision")
- return nil, fmt.Errorf("error updating replicaset revision: %v", err)
- }
- c.log.Infof("Synced revision on ReplicaSet '%s' to '%s'", rs.Name, newRevision)
- err = c.replicaSetInformer.GetIndexer().Update(rs)
+
+ rs, err := c.updateReplicaSetFallbackToPatch(ctx, rsCopy)
if err != nil {
- return nil, fmt.Errorf("error updating replicaset informer in syncReplicaSetRevision: %w", err)
+ return nil, fmt.Errorf("failed to update replicaset revision on %s: %w", rsCopy.Name, err)
}
return rs, nil
}
@@ -113,7 +109,7 @@ func (c *rolloutContext) syncReplicaSetRevision() (*appsv1.ReplicaSet, error) {
conditions.SetRolloutCondition(&c.rollout.Status, *condition)
updatedRollout, err := c.argoprojclientset.ArgoprojV1alpha1().Rollouts(c.rollout.Namespace).UpdateStatus(ctx, c.rollout, metav1.UpdateOptions{})
if err != nil {
- c.log.WithError(err).Error("Error: updating rollout revision")
+ c.log.WithError(err).Error("Error: updating rollout status in syncReplicaSetRevision")
return nil, err
}
c.rollout = updatedRollout
@@ -245,7 +241,7 @@ func (c *rolloutContext) createDesiredReplicaSet() (*appsv1.ReplicaSet, error) {
cond := conditions.NewRolloutCondition(v1alpha1.RolloutProgressing, corev1.ConditionFalse, conditions.FailedRSCreateReason, msg)
patchErr := c.patchCondition(c.rollout, newStatus, cond)
if patchErr != nil {
- c.log.Warnf("Error Patching Rollout: %s", patchErr.Error())
+ c.log.Warnf("Error Patching Rollout Conditions: %s", patchErr.Error())
}
return nil, err
default:
@@ -370,25 +366,21 @@ func (c *rolloutContext) scaleReplicaSet(rs *appsv1.ReplicaSet, newScale int32,
rolloutReplicas := defaults.GetReplicasOrDefault(rollout.Spec.Replicas)
annotationsNeedUpdate := annotations.ReplicasAnnotationsNeedUpdate(rs, rolloutReplicas)
- scaled := false
var err error
+ scaled := false
if sizeNeedsUpdate || annotationsNeedUpdate {
rsCopy := rs.DeepCopy()
oldScale := defaults.GetReplicasOrDefault(rs.Spec.Replicas)
*(rsCopy.Spec.Replicas) = newScale
annotations.SetReplicasAnnotations(rsCopy, rolloutReplicas)
if fullScaleDown && !c.shouldDelayScaleDownOnAbort() {
+ // This bypasses the normal call to removeScaleDownDelay and then depends on the removal via an update in updateReplicaSetFallbackToPatch
delete(rsCopy.Annotations, v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey)
}
- rs, err = c.kubeclientset.AppsV1().ReplicaSets(rsCopy.Namespace).Update(ctx, rsCopy, metav1.UpdateOptions{})
- if err != nil {
- return scaled, rs, fmt.Errorf("error updating replicaset %s: %w", rsCopy.Name, err)
- }
- err = c.replicaSetInformer.GetIndexer().Update(rs)
+ rs, err = c.updateReplicaSetFallbackToPatch(ctx, rsCopy)
if err != nil {
- err = fmt.Errorf("error updating replicaset informer in scaleReplicaSet: %w", err)
- return scaled, rs, err
+ return scaled, rs, fmt.Errorf("failed to updateReplicaSetFallbackToPatch in scaleReplicaSet: %w", err)
}
if sizeNeedsUpdate {
diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go
index f8b01951a4..e992277a57 100644
--- a/rollout/trafficrouting.go
+++ b/rollout/trafficrouting.go
@@ -288,6 +288,12 @@ func (c *rolloutContext) reconcileTrafficRouting() error {
} else {
c.log.Infof("Desired weight (stepIdx: %s) %d not yet verified", indexString, desiredWeight)
c.enqueueRolloutAfter(c.rollout, defaults.GetRolloutVerifyRetryInterval())
+ // At the end of the rollout we need to verify the weight is correct, and return an error if not because we don't want the rest of the
+ // reconcile process to continue. We don't need to do this if we are in the middle of the rollout because the rest of the reconcile
+ // process won't scale down the old replicasets yet due to being in the middle of some steps.
+ if desiredWeight == weightutil.MaxTrafficWeight(c.rollout) && len(c.rollout.Spec.Strategy.Canary.Steps) >= int(*c.rollout.Status.CurrentStepIndex) {
+ return fmt.Errorf("end of rollout, desired weight %d not yet verified", desiredWeight)
+ }
}
}
}
diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go
index 8e81b113c7..0a053857d6 100644
--- a/rollout/trafficrouting/alb/alb.go
+++ b/rollout/trafficrouting/alb/alb.go
@@ -202,7 +202,7 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations ..
return nil, nil
}
- if !rolloututil.ShouldVerifyWeight(r.cfg.Rollout) {
+ if !rolloututil.ShouldVerifyWeight(r.cfg.Rollout, desiredWeight) {
// If we should not verify weight but the ALB status has not been set yet due to a Rollout resource just being
// installed in the cluster we want to actually run the rest of the function, so we do not return if
// r.cfg.Rollout.Status.ALB is nil. However, if we should not verify, and we have already updated the status once
@@ -242,7 +242,7 @@ func (r *Reconciler) VerifyWeightPerIngress(desiredWeight int32, ingresses []str
}
resourceIDToDest := map[string]v1alpha1.WeightDestination{}
- stableService, canaryService := trafficrouting.GetStableAndCanaryServices(rollout)
+ stableService, canaryService := trafficrouting.GetStableAndCanaryServices(rollout, true)
canaryResourceID := aws.BuildTargetGroupResourceID(rollout.Namespace, ingress.GetName(), canaryService, rollout.Spec.Strategy.Canary.TrafficRouting.ALB.ServicePort)
stableResourceID := aws.BuildTargetGroupResourceID(rollout.Namespace, ingress.GetName(), stableService, rollout.Spec.Strategy.Canary.TrafficRouting.ALB.ServicePort)
@@ -347,7 +347,7 @@ func updateTargetGroupStatus(status *v1alpha1.ALBStatus, tg *aws.TargetGroupMeta
}
func getForwardActionString(r *v1alpha1.Rollout, port int32, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (string, error) {
- stableService, canaryService := trafficrouting.GetStableAndCanaryServices(r)
+ stableService, canaryService := trafficrouting.GetStableAndCanaryServices(r, true)
portStr := strconv.Itoa(int(port))
stableWeight := int32(100)
targetGroups := make([]ingressutil.ALBTargetGroup, 0)
@@ -479,7 +479,7 @@ func removeValue(array []string, key string) []string {
}
func getTrafficForwardActionString(r *v1alpha1.Rollout, port int32) (string, error) {
- _, canaryService := trafficrouting.GetStableAndCanaryServices(r)
+ _, canaryService := trafficrouting.GetStableAndCanaryServices(r, true)
portStr := strconv.Itoa(int(port))
weight := int64(100)
targetGroups := make([]ingressutil.ALBTargetGroup, 0)
diff --git a/rollout/trafficrouting/alb/alb_test.go b/rollout/trafficrouting/alb/alb_test.go
index fb131849d4..faa798e524 100644
--- a/rollout/trafficrouting/alb/alb_test.go
+++ b/rollout/trafficrouting/alb/alb_test.go
@@ -918,6 +918,7 @@ func TestVerifyWeight(t *testing.T) {
{
var status v1alpha1.RolloutStatus
r, fakeClient := newFakeReconciler(&status)
+
fakeClient.loadBalancers = []*elbv2types.LoadBalancer{
{
LoadBalancerName: pointer.StringPtr("lb-abc123-name"),
@@ -955,6 +956,48 @@ func TestVerifyWeight(t *testing.T) {
assert.Equal(t, *status.ALB, *fakeClient.getAlbStatus("ingress"))
}
+ // LoadBalancer found, at max weight, end of rollout
+ {
+ var status v1alpha1.RolloutStatus
+ status.CurrentStepIndex = pointer.Int32Ptr(2)
+ r, fakeClient := newFakeReconciler(&status)
+ fakeClient.loadBalancers = []*elbv2types.LoadBalancer{
+ {
+ LoadBalancerName: pointer.StringPtr("lb-abc123-name"),
+ LoadBalancerArn: pointer.StringPtr("arn:aws:elasticloadbalancing:us-east-2:123456789012:loadbalancer/app/lb-abc123-name/1234567890123456"),
+ DNSName: pointer.StringPtr("verify-weight-test-abc-123.us-west-2.elb.amazonaws.com"),
+ },
+ }
+ fakeClient.targetGroups = []aws.TargetGroupMeta{
+ {
+ TargetGroup: elbv2types.TargetGroup{
+ TargetGroupName: pointer.StringPtr("canary-tg-abc123-name"),
+ TargetGroupArn: pointer.StringPtr("arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/canary-tg-abc123-name/1234567890123456"),
+ },
+ Weight: pointer.Int32Ptr(100),
+ Tags: map[string]string{
+ aws.AWSLoadBalancerV2TagKeyResourceID: "default/ingress-canary-svc:443",
+ },
+ },
+ {
+ TargetGroup: elbv2types.TargetGroup{
+ TargetGroupName: pointer.StringPtr("stable-tg-abc123-name"),
+ TargetGroupArn: pointer.StringPtr("arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/stable-tg-abc123-name/1234567890123456"),
+ },
+ Weight: pointer.Int32Ptr(0),
+ Tags: map[string]string{
+ aws.AWSLoadBalancerV2TagKeyResourceID: "default/ingress-stable-svc:443",
+ },
+ },
+ }
+
+ weightVerified, err := r.VerifyWeight(100)
+ assert.NoError(t, err)
+ assert.True(t, *weightVerified)
+ assert.Equal(t, status.ALBs[0], *status.ALB)
+ assert.Equal(t, *status.ALB, *fakeClient.getAlbStatus("ingress"))
+ }
+
// LoadBalancer found, but ARNs are unparsable
{
var status v1alpha1.RolloutStatus
diff --git a/rollout/trafficrouting/ambassador/ambassador.go b/rollout/trafficrouting/ambassador/ambassador.go
index 5c50f38f26..ceb389c81a 100644
--- a/rollout/trafficrouting/ambassador/ambassador.go
+++ b/rollout/trafficrouting/ambassador/ambassador.go
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
- "strconv"
"strings"
"sync"
"time"
@@ -218,7 +217,8 @@ func (r *Reconciler) createCanaryMapping(ctx context.Context,
}
canarySvc := r.Rollout.Spec.Strategy.Canary.CanaryService
- canaryMapping := buildCanaryMapping(baseMapping, canarySvc, desiredWeight)
+ stableService := r.Rollout.Spec.Strategy.Canary.StableService
+ canaryMapping := buildCanaryMapping(baseMapping, canarySvc, stableService, desiredWeight)
_, err = client.Create(ctx, canaryMapping, metav1.CreateOptions{})
if err != nil {
msg := fmt.Sprintf("Error creating canary mapping: %s", err)
@@ -227,9 +227,9 @@ func (r *Reconciler) createCanaryMapping(ctx context.Context,
return err
}
-func buildCanaryMapping(baseMapping *unstructured.Unstructured, canarySvc string, desiredWeight int32) *unstructured.Unstructured {
+func buildCanaryMapping(baseMapping *unstructured.Unstructured, canarySvc string, stableService string, desiredWeight int32) *unstructured.Unstructured {
canaryMapping := baseMapping.DeepCopy()
- svc := buildCanaryService(baseMapping, canarySvc)
+ svc := buildCanaryService(baseMapping, canarySvc, stableService)
unstructured.RemoveNestedField(canaryMapping.Object, "metadata")
cMappingName := buildCanaryMappingName(baseMapping.GetName())
canaryMapping.SetName(cMappingName)
@@ -239,19 +239,9 @@ func buildCanaryMapping(baseMapping *unstructured.Unstructured, canarySvc string
return canaryMapping
}
-func buildCanaryService(baseMapping *unstructured.Unstructured, canarySvc string) string {
+func buildCanaryService(baseMapping *unstructured.Unstructured, canarySvc string, stableService string) string {
curSvc := GetMappingService(baseMapping)
- parts := strings.Split(curSvc, ":")
- if len(parts) < 2 {
- return canarySvc
- }
- // Check if the last part is a valid int that can be used as the port
- port := parts[len(parts)-1]
- if _, err := strconv.Atoi(port); err != nil {
- return canarySvc
-
- }
- return fmt.Sprintf("%s:%s", canarySvc, port)
+ return strings.Replace(curSvc, stableService, canarySvc, 1)
}
func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) {
diff --git a/rollout/trafficrouting/ambassador/ambassador_test.go b/rollout/trafficrouting/ambassador/ambassador_test.go
index 66d193b83a..ee1ac347e3 100644
--- a/rollout/trafficrouting/ambassador/ambassador_test.go
+++ b/rollout/trafficrouting/ambassador/ambassador_test.go
@@ -31,7 +31,7 @@ metadata:
spec:
prefix: /myapp/
rewrite: /myapp/
- service: myapp:8080`
+ service: main-service:8080`
baseMappingNoPort = `
apiVersion: getambassador.io/v2
@@ -42,7 +42,7 @@ metadata:
spec:
prefix: /myapp/
rewrite: /myapp/
- service: myapp`
+ service: main-service`
baseMappingWithWeight = `
apiVersion: getambassador.io/v2
@@ -53,7 +53,7 @@ metadata:
spec:
prefix: /myapp/
rewrite: /myapp/
- service: myapp:8080
+ service: main-service:8080
weight: 20`
baseV3Mapping = `
@@ -66,7 +66,7 @@ spec:
hostname: 'example.com'
prefix: /myapp/
rewrite: /myapp/
- service: myapp:8080`
+ service: main-service:8080`
canaryMapping = `
apiVersion: getambassador.io/v2
@@ -77,7 +77,7 @@ metadata:
spec:
prefix: /myapp/
rewrite: /myapp/
- service: myapp:8080
+ service: main-service:8080
weight: 20`
canaryMappingWithZeroWeight = `
@@ -89,7 +89,7 @@ metadata:
spec:
prefix: /myapp/
rewrite: /myapp/
- service: myapp:8080
+ service: main-service:8080
weight: 0`
)
diff --git a/rollout/trafficrouting/istio/istio.go b/rollout/trafficrouting/istio/istio.go
index 5308d59a42..bb9a15eb5e 100644
--- a/rollout/trafficrouting/istio/istio.go
+++ b/rollout/trafficrouting/istio/istio.go
@@ -125,7 +125,7 @@ func (patches virtualServicePatches) patchVirtualService(httpRoutes []any, tlsRo
}
func (r *Reconciler) generateVirtualServicePatches(rolloutVsvcRouteNames []string, httpRoutes []VirtualServiceHTTPRoute, rolloutVsvcTLSRoutes []v1alpha1.TLSRoute, tlsRoutes []VirtualServiceTLSRoute, rolloutVsvcTCPRoutes []v1alpha1.TCPRoute, tcpRoutes []VirtualServiceTCPRoute, desiredWeight int64, additionalDestinations ...v1alpha1.WeightDestination) virtualServicePatches {
- stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r.rollout)
+ stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r.rollout, false)
canarySubset := ""
stableSubset := ""
if r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule != nil {
@@ -718,7 +718,7 @@ func (r *Reconciler) reconcileVirtualServiceHeaderRoutes(virtualService v1alpha1
return err
}
- _, canarySvc := trafficrouting.GetStableAndCanaryServices(r.rollout)
+ _, canarySvc := trafficrouting.GetStableAndCanaryServices(r.rollout, false)
if destRuleHost != "" {
canarySvc = destRuleHost
}
@@ -1023,7 +1023,7 @@ func searchTcpRoute(tcpRoute v1alpha1.TCPRoute, istioTcpRoutes []VirtualServiceT
// ValidateHTTPRoutes ensures that all the routes in the rollout exist
func ValidateHTTPRoutes(r *v1alpha1.Rollout, routeNames []string, httpRoutes []VirtualServiceHTTPRoute) error {
- stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r)
+ stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r, false)
routeIndexesToPatch, err := getHttpRouteIndexesToPatch(routeNames, httpRoutes)
if err != nil {
@@ -1060,7 +1060,7 @@ func ValidateHTTPRoutes(r *v1alpha1.Rollout, routeNames []string, httpRoutes []V
// ValidateTlsRoutes ensures that all the routes in the rollout exist and they only have two destinations
func ValidateTlsRoutes(r *v1alpha1.Rollout, vsvcTLSRoutes []v1alpha1.TLSRoute, tlsRoutes []VirtualServiceTLSRoute) error {
- stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r)
+ stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r, false)
routeIndexesToPatch, err := getTlsRouteIndexesToPatch(vsvcTLSRoutes, tlsRoutes)
if err != nil {
@@ -1081,7 +1081,7 @@ func ValidateTlsRoutes(r *v1alpha1.Rollout, vsvcTLSRoutes []v1alpha1.TLSRoute, t
// ValidateTcpRoutes ensures that all the routes in the rollout exist and they only have two destinations
func ValidateTcpRoutes(r *v1alpha1.Rollout, vsvcTCPRoutes []v1alpha1.TCPRoute, tcpRoutes []VirtualServiceTCPRoute) error {
- stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r)
+ stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r, false)
routeIndexesToPatch, err := getTcpRouteIndexesToPatch(vsvcTCPRoutes, tcpRoutes)
if err != nil {
@@ -1189,7 +1189,7 @@ func (r *Reconciler) reconcileVirtualServiceMirrorRoutes(virtualService v1alpha1
if err != nil {
return fmt.Errorf("[reconcileVirtualServiceMirrorRoutes] failed to get destination rule host: %w", err)
}
- _, canarySvc := trafficrouting.GetStableAndCanaryServices(r.rollout)
+ _, canarySvc := trafficrouting.GetStableAndCanaryServices(r.rollout, false)
if destRuleHost != "" {
canarySvc = destRuleHost
}
diff --git a/rollout/trafficrouting/service_helper.go b/rollout/trafficrouting/service_helper.go
index 15d03cad53..8bae069fe7 100644
--- a/rollout/trafficrouting/service_helper.go
+++ b/rollout/trafficrouting/service_helper.go
@@ -7,17 +7,26 @@ import (
// GetStableAndCanaryServices return a service names for current stable and canary services.
// If ping-pong feature enabled then the current ping or pong service will be returned. Which is a stable is defined
// based on a rollout status field Status.Canary.StablePingPong
-func GetStableAndCanaryServices(ro *v1alpha1.Rollout) (string, string) {
- if IsPingPongEnabled(ro) {
+
+// isPingpongPreferred is needed when Rollout uses both pingpong service and stable/canary service
+// for ALB trafficRouting, isPingpongPreferred is true. It uses pingpong service as priority
+// for other trafficRouting, isPingpongPrefrered is false. It uses stable/canary service
+// This is to ensure it is compatible with previous release.
+
+func GetStableAndCanaryServices(ro *v1alpha1.Rollout, isPingpongPreferred bool) (string, string) {
+ pingPongNotPreferredOtherServiceNotDefined := !isPingpongPreferred && ro.Spec.Strategy.Canary.StableService == "" && ro.Spec.Strategy.Canary.CanaryService == ""
+ if IsPingPongEnabled(ro) &&
+ (isPingpongPreferred || pingPongNotPreferredOtherServiceNotDefined) {
canary := ro.Spec.Strategy.Canary
if IsStablePing(ro) {
return canary.PingPong.PingService, canary.PingPong.PongService
} else {
return canary.PingPong.PongService, canary.PingPong.PingService
}
- } else {
- return ro.Spec.Strategy.Canary.StableService, ro.Spec.Strategy.Canary.CanaryService
}
+
+ return ro.Spec.Strategy.Canary.StableService, ro.Spec.Strategy.Canary.CanaryService
+
}
// IsStablePing return true if the 'ping' service is pointing to the stable replica set.
diff --git a/rollout/trafficrouting/service_helper_test.go b/rollout/trafficrouting/service_helper_test.go
new file mode 100644
index 0000000000..cc0634eb6f
--- /dev/null
+++ b/rollout/trafficrouting/service_helper_test.go
@@ -0,0 +1,82 @@
+package trafficrouting
+
+import (
+ "testing"
+
+ "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
+ "github.com/stretchr/testify/assert"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+const PING_SVC = "ping-service"
+const PONG_SVC = "pong-service"
+
+func fakeRollout(stableSvc, canarySvc string, pingPong *v1alpha1.PingPongSpec, stableIng string, port int32) *v1alpha1.Rollout {
+ return &v1alpha1.Rollout{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "rollout",
+ Namespace: metav1.NamespaceDefault,
+ },
+ Spec: v1alpha1.RolloutSpec{
+ Strategy: v1alpha1.RolloutStrategy{
+ Canary: &v1alpha1.CanaryStrategy{
+ StableService: stableSvc,
+ CanaryService: canarySvc,
+ PingPong: pingPong,
+ TrafficRouting: &v1alpha1.RolloutTrafficRouting{
+ ALB: &v1alpha1.ALBTrafficRouting{
+ Ingress: stableIng,
+ ServicePort: port,
+ },
+ Istio: &v1alpha1.IstioTrafficRouting{
+ VirtualService: &v1alpha1.IstioVirtualService{
+ Name: "istio-vsvc",
+ },
+ DestinationRule: &v1alpha1.IstioDestinationRule{
+ Name: "istio-destrule",
+ CanarySubsetName: "canary",
+ StableSubsetName: "stable",
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func TestGetStableAndCanaryServices(t *testing.T) {
+ // Rollout has no pingPong
+ rollout := fakeRollout("stable-service", "canary-service", nil, "stable-ingress", 443)
+
+ stableService, canaryService := GetStableAndCanaryServices(rollout, true)
+ assert.Equal(t, "stable-service", stableService)
+ assert.Equal(t, "canary-service", canaryService)
+
+ stableService, canaryService = GetStableAndCanaryServices(rollout, false)
+ assert.Equal(t, "stable-service", stableService)
+ assert.Equal(t, "canary-service", canaryService)
+
+ // Rollout has pingPong and stable/canary
+ pp := &v1alpha1.PingPongSpec{PingService: PING_SVC, PongService: PONG_SVC}
+ rollout = fakeRollout("stable-service", "canary-service", pp, "stable-ingress", 443)
+
+ stableService, canaryService = GetStableAndCanaryServices(rollout, true)
+ assert.Equal(t, PONG_SVC, stableService)
+ assert.Equal(t, PING_SVC, canaryService)
+
+ stableService, canaryService = GetStableAndCanaryServices(rollout, false)
+ assert.Equal(t, "stable-service", stableService)
+ assert.Equal(t, "canary-service", canaryService)
+
+ // Rollout has pingPong, no stable/canary
+ rollout = fakeRollout("", "", pp, "stable-ingress", 443)
+
+ stableService, canaryService = GetStableAndCanaryServices(rollout, true)
+ assert.Equal(t, PONG_SVC, stableService)
+ assert.Equal(t, PING_SVC, canaryService)
+
+ stableService, canaryService = GetStableAndCanaryServices(rollout, false)
+ assert.Equal(t, PONG_SVC, stableService)
+ assert.Equal(t, PING_SVC, canaryService)
+}
diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go
index f7dd459964..f358a18f64 100644
--- a/rollout/trafficrouting_test.go
+++ b/rollout/trafficrouting_test.go
@@ -130,6 +130,53 @@ func TestReconcileTrafficRoutingVerifyWeightFalse(t *testing.T) {
assert.True(t, enqueued)
}
+func TestReconcileTrafficRoutingVerifyWeightEndOfRollout(t *testing.T) {
+ f := newFixture(t)
+ defer f.Close()
+
+ steps := []v1alpha1.CanaryStep{
+ {
+ SetWeight: pointer.Int32Ptr(10),
+ },
+ {
+ Pause: &v1alpha1.RolloutPause{},
+ },
+ }
+ r1 := newCanaryRollout("foo", 10, nil, steps, pointer.Int32Ptr(2), intstr.FromInt(1), intstr.FromInt(0))
+ r2 := bumpVersion(r1)
+ r2.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{}
+ r2.Spec.Strategy.Canary.CanaryService = "canary"
+ r2.Spec.Strategy.Canary.StableService = "stable"
+
+ rs1 := newReplicaSetWithStatus(r1, 10, 10)
+ rs2 := newReplicaSetWithStatus(r2, 10, 10)
+
+ rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey]
+ rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey]
+ canarySelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash}
+ stableSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash}
+ canarySvc := newService("canary", 80, canarySelector, r2)
+ stableSvc := newService("stable", 80, stableSelector, r2)
+
+ f.kubeobjects = append(f.kubeobjects, rs1, rs2, canarySvc, stableSvc)
+ f.replicaSetLister = append(f.replicaSetLister, rs1, rs2)
+
+ r2 = updateCanaryRolloutStatus(r2, rs1PodHash, 10, 0, 10, false)
+ f.rolloutLister = append(f.rolloutLister, r2)
+ f.objects = append(f.objects, r2)
+
+ f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler()
+ f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+ f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error {
+ // make sure SetWeight was called with correct value
+ assert.Equal(t, int32(100), desiredWeight)
+ return nil
+ })
+ f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil)
+ f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(false), nil)
+ f.runExpectError(getKey(r2, t), true)
+}
+
func TestRolloutUseDesiredWeight(t *testing.T) {
f := newFixture(t)
defer f.Close()
diff --git a/test/e2e/aws_test.go b/test/e2e/aws_test.go
index f8b0553fe2..fcbb1a2ef5 100644
--- a/test/e2e/aws_test.go
+++ b/test/e2e/aws_test.go
@@ -94,6 +94,71 @@ func (s *AWSSuite) TestALBPingPongUpdate() {
Assert(assertWeights(s, "ping-service", "pong-service", 100, 0))
}
+// Rollout uses both alb and mesh for trafficRouting.
+// also uses both pingpong service and stable/canary services
+// Expecting: * alb is using pingpong
+// - mesh is using stable/canary
+func (s *AWSSuite) TestALBMesh_PingPong_StableCanary_Update() {
+ s.Given().
+ RolloutObjects("@functional/albmesh-pingpong-stablecanary-rollout.yaml").
+ When().ApplyManifests().WaitForRolloutStatus("Healthy").
+ Then().
+ Assert(assertWeights(s, "ping-service", "pong-service", 100, 0)).
+ Assert(func(t *fixtures.Then) {
+ vsvc := t.GetVirtualService()
+ assert.Equal(s.T(), int64(100), vsvc.Spec.HTTP[0].Route[0].Weight)
+ assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[1].Weight)
+ assert.Equal(s.T(), "stable-service", vsvc.Spec.HTTP[0].Route[0].Destination.Host)
+ assert.Equal(s.T(), "canary-service", vsvc.Spec.HTTP[0].Route[1].Destination.Host)
+ }).
+ // Update 1. Test the weight switch from ping => pong
+ When().UpdateSpec().
+ WaitForRolloutCanaryStepIndex(1).Sleep(1 * time.Second).Then().
+ Assert(assertWeights(s, "ping-service", "pong-service", 75, 25)).
+ Assert(func(t *fixtures.Then) {
+ vsvc := t.GetVirtualService()
+ assert.Equal(s.T(), int64(75), vsvc.Spec.HTTP[0].Route[0].Weight)
+ assert.Equal(s.T(), int64(25), vsvc.Spec.HTTP[0].Route[1].Weight)
+ assert.Equal(s.T(), "stable-service", vsvc.Spec.HTTP[0].Route[0].Destination.Host)
+ assert.Equal(s.T(), "canary-service", vsvc.Spec.HTTP[0].Route[1].Destination.Host)
+ }).
+ When().PromoteRollout().
+ WaitForRolloutStatus("Healthy").
+ Sleep(1 * time.Second).
+ Then().
+ Assert(assertWeights(s, "ping-service", "pong-service", 0, 100)).
+ Assert(func(t *fixtures.Then) {
+ vsvc := t.GetVirtualService()
+ assert.Equal(s.T(), int64(100), vsvc.Spec.HTTP[0].Route[0].Weight)
+ assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[1].Weight)
+ assert.Equal(s.T(), "stable-service", vsvc.Spec.HTTP[0].Route[0].Destination.Host)
+ assert.Equal(s.T(), "canary-service", vsvc.Spec.HTTP[0].Route[1].Destination.Host)
+ }).
+ // Update 2. Test the weight switch from pong => ping
+ When().UpdateSpec().
+ WaitForRolloutCanaryStepIndex(1).Sleep(1 * time.Second).Then().
+ Assert(assertWeights(s, "ping-service", "pong-service", 25, 75)).
+ Assert(func(t *fixtures.Then) {
+ vsvc := t.GetVirtualService()
+ assert.Equal(s.T(), int64(75), vsvc.Spec.HTTP[0].Route[0].Weight)
+ assert.Equal(s.T(), int64(25), vsvc.Spec.HTTP[0].Route[1].Weight)
+ assert.Equal(s.T(), "stable-service", vsvc.Spec.HTTP[0].Route[0].Destination.Host)
+ assert.Equal(s.T(), "canary-service", vsvc.Spec.HTTP[0].Route[1].Destination.Host)
+ }).
+ When().PromoteRollout().
+ WaitForRolloutStatus("Healthy").
+ Sleep(1 * time.Second).
+ Then().
+ Assert(assertWeights(s, "ping-service", "pong-service", 100, 0)).
+ Assert(func(t *fixtures.Then) {
+ vsvc := t.GetVirtualService()
+ assert.Equal(s.T(), int64(100), vsvc.Spec.HTTP[0].Route[0].Weight)
+ assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[1].Weight)
+ assert.Equal(s.T(), "stable-service", vsvc.Spec.HTTP[0].Route[0].Destination.Host)
+ assert.Equal(s.T(), "canary-service", vsvc.Spec.HTTP[0].Route[1].Destination.Host)
+ })
+}
+
func (s *AWSSuite) TestALBPingPongUpdateMultiIngress() {
s.Given().
RolloutObjects("@functional/alb-pingpong-multi-ingress-rollout.yaml").
@@ -239,6 +304,7 @@ func (s *AWSSuite) TestALBExperimentStepMultiIngress() {
}
func (s *AWSSuite) TestALBExperimentStepNoSetWeight() {
+ //TODO: this test is flaky
s.Given().
RolloutObjects("@alb/rollout-alb-experiment-no-setweight.yaml").
When().
@@ -272,6 +338,7 @@ func (s *AWSSuite) TestALBExperimentStepNoSetWeight() {
}
func (s *AWSSuite) TestALBExperimentStepNoSetWeightMultiIngress() {
+ //TODO: this test is flaky
s.Given().
RolloutObjects("@alb/rollout-alb-multi-ingress-experiment-no-setweight.yaml").
When().
diff --git a/test/e2e/canary_test.go b/test/e2e/canary_test.go
index 2c68ec8bd7..8656aa5c4d 100644
--- a/test/e2e/canary_test.go
+++ b/test/e2e/canary_test.go
@@ -149,7 +149,10 @@ spec:
spec:
containers:
- name: updatescaling
- command: [/bad-command]`).
+ resources:
+ requests:
+ memory: 16Mi
+ cpu: 2m`).
WaitForRolloutReplicas(7).
Then().
ExpectCanaryStablePodCount(4, 3).
@@ -658,6 +661,7 @@ func (s *CanarySuite) TestCanaryDynamicStableScale() {
When().
MarkPodsReady("1", 1). // mark last remaining stable pod as ready (4/4 stable are ready)
WaitForRevisionPodCount("2", 0).
+ Sleep(2*time.Second). //WaitForRevisionPodCount does not wait for terminating pods and so ExpectServiceSelector fails sleep a bit for the terminating pods to be deleted
Then().
// Expect that the canary service selector is now set to stable because of dynamic stable scale is over and we have all pods up on stable rs
ExpectServiceSelector("dynamic-stable-scale-canary", map[string]string{"app": "dynamic-stable-scale", "rollouts-pod-template-hash": "868d98995b"}, false).
diff --git a/test/e2e/functional/albmesh-pingpong-stablecanary-rollout.yaml b/test/e2e/functional/albmesh-pingpong-stablecanary-rollout.yaml
new file mode 100644
index 0000000000..0476b1076e
--- /dev/null
+++ b/test/e2e/functional/albmesh-pingpong-stablecanary-rollout.yaml
@@ -0,0 +1,139 @@
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: ping-service
+spec:
+ type: NodePort
+ ports:
+ - port: 80
+ targetPort: http
+ protocol: TCP
+ name: http
+ selector:
+ app: alb-canary
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: pong-service
+spec:
+ type: NodePort
+ ports:
+ - port: 80
+ targetPort: http
+ protocol: TCP
+ name: http
+ selector:
+ app: alb-canary
+---
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: stable-service
+spec:
+ type: NodePort
+ ports:
+ - port: 80
+ targetPort: http
+ protocol: TCP
+ name: http
+ selector:
+ app: alb-canary
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: canary-service
+spec:
+ type: NodePort
+ ports:
+ - port: 80
+ targetPort: http
+ protocol: TCP
+ name: http
+ selector:
+ app: alb-canary
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: alb-canary-ingress
+ annotations:
+ kubernetes.io/ingress.class: alb
+spec:
+ rules:
+ - http:
+ paths:
+ - path: /*
+ backend:
+ service:
+ name: alb-rollout-root
+ port:
+ name: use-annotation
+ pathType: ImplementationSpecific
+---
+apiVersion: argoproj.io/v1alpha1
+kind: Rollout
+metadata:
+ name: alb-canary
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ app: alb-canary
+ template:
+ metadata:
+ labels:
+ app: alb-canary
+ spec:
+ containers:
+ - name: alb-canary
+ image: "argoproj/rollouts-demo:red"
+ ports:
+ - name: http
+ containerPort: 80
+ protocol: TCP
+ resources:
+ requests:
+ memory: 16Mi
+ cpu: 5m
+ strategy:
+ canary:
+ scaleDownDelaySeconds: 2
+ canaryService: canary-service
+ stableService: stable-service
+ pingPong:
+ pingService: ping-service
+ pongService: pong-service
+ trafficRouting:
+ alb:
+ ingress: alb-canary-ingress
+ rootService: alb-rollout-root
+ servicePort: 80
+ istio:
+ virtualService:
+ name: istio-host-split-vsvc
+ routes:
+ - primary
+ steps:
+ - setWeight: 25
+ - pause: {}
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: istio-host-split-vsvc
+spec:
+ hosts:
+ - istio-host-split
+ http:
+ - name: primary
+ route:
+ - destination:
+ host: stable-service
+ weight: 100
+ - destination:
+ host: canary-service
+ weight: 0
diff --git a/test/e2e/functional/analysistemplate-sleep-job.yaml b/test/e2e/functional/analysistemplate-sleep-job.yaml
index 86faa2c877..4fdd369dee 100644
--- a/test/e2e/functional/analysistemplate-sleep-job.yaml
+++ b/test/e2e/functional/analysistemplate-sleep-job.yaml
@@ -6,7 +6,7 @@ metadata:
spec:
args:
- name: duration
- value: 0s
+ value: "0"
- name: exit-code
value: "0"
- name: count
diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go
index 930c7d0c61..668c75bb0c 100644
--- a/test/e2e/functional_test.go
+++ b/test/e2e/functional_test.go
@@ -166,13 +166,14 @@ spec:
UpdateSpec().
WaitForRolloutStatus("Paused"). // At step 1 (pause: {duration: 24h})
PromoteRollout().
- Sleep(2*time.Second).
+ Sleep(3*time.Second).
+ WaitForInlineAnalysisRunPhase("Running").
Then().
+ ExpectRolloutStatus("Progressing"). // At step 2 (analysis: sleep-job - 24h)
+ ExpectAnalysisRunCount(1).
ExpectRollout("status.currentStepIndex == 1", func(r *v1alpha1.Rollout) bool {
return *r.Status.CurrentStepIndex == 1
}).
- ExpectRolloutStatus("Progressing"). // At step 2 (analysis: sleep-job - 24h)
- ExpectAnalysisRunCount(1).
When().
PromoteRollout().
Sleep(2 * time.Second).
@@ -205,6 +206,9 @@ spec:
prePromotionAnalysis:
templates:
- templateName: sleep-job
+ args:
+ - name: duration
+ value: "10"
postPromotionAnalysis:
templates:
- templateName: sleep-job
@@ -228,7 +232,8 @@ spec:
ApplyManifests().
WaitForRolloutStatus("Healthy").
UpdateSpec().
- Sleep(3 * time.Second).
+ Sleep(5 * time.Second).
+ WaitForPrePromotionAnalysisRunPhase("Running").
PromoteRolloutFull().
WaitForRolloutStatus("Healthy").
Then().
diff --git a/test/fixtures/e2e_suite.go b/test/fixtures/e2e_suite.go
index a774afcf94..e78ae1aa68 100644
--- a/test/fixtures/e2e_suite.go
+++ b/test/fixtures/e2e_suite.go
@@ -54,7 +54,7 @@ const (
)
var (
- E2EWaitTimeout time.Duration = time.Second * 120
+ E2EWaitTimeout time.Duration = time.Second * 90
E2EPodDelay = 0
E2EALBIngressAnnotations map[string]string
@@ -143,8 +143,8 @@ func (s *E2ESuite) SetupSuite() {
restConfig, err := config.ClientConfig()
s.CheckError(err)
s.Common.kubernetesHost = restConfig.Host
- restConfig.Burst = defaults.DefaultBurst * 2
- restConfig.QPS = defaults.DefaultQPS * 2
+ restConfig.Burst = defaults.DefaultBurst * 10
+ restConfig.QPS = defaults.DefaultQPS * 10
s.namespace, _, err = config.Namespace()
s.CheckError(err)
s.kubeClient, err = kubernetes.NewForConfig(restConfig)
diff --git a/ui/yarn.lock b/ui/yarn.lock
index 2ef9058665..628cb5963f 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -10217,16 +10217,7 @@ loader-runner@^4.2.0:
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
-loader-utils@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0"
- integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==
- dependencies:
- big.js "^5.2.2"
- emojis-list "^3.0.0"
- json5 "^2.1.2"
-
-loader-utils@^2.0.4:
+loader-utils@^2.0.0, loader-utils@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c"
integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==
diff --git a/utils/annotations/annotations.go b/utils/annotations/annotations.go
index 121c6c0803..067492bc2b 100644
--- a/utils/annotations/annotations.go
+++ b/utils/annotations/annotations.go
@@ -28,6 +28,8 @@ const (
DesiredReplicasAnnotation = RolloutLabel + "/desired-replicas"
// WorkloadGenerationAnnotation is the generation of the referenced workload
WorkloadGenerationAnnotation = RolloutLabel + "/workload-generation"
+ // NotificationEngineAnnotation the annotation notification engine uses to determine if it should notify
+ NotificationEngineAnnotation = "notified.notifications.argoproj.io"
)
// GetDesiredReplicasAnnotation returns the number of desired replicas
@@ -219,6 +221,7 @@ var annotationsToSkip = map[string]bool{
RevisionAnnotation: true,
RevisionHistoryAnnotation: true,
DesiredReplicasAnnotation: true,
+ NotificationEngineAnnotation: true,
}
// skipCopyAnnotation returns true if we should skip copying the annotation with the given annotation key
diff --git a/utils/controller/controller.go b/utils/controller/controller.go
index 2530e1d5fa..b5c1fc875b 100644
--- a/utils/controller/controller.go
+++ b/utils/controller/controller.go
@@ -6,6 +6,8 @@ import (
"runtime/debug"
"time"
+ "k8s.io/apimachinery/pkg/api/errors"
+
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -157,6 +159,11 @@ func processNextWorkItem(ctx context.Context, workqueue workqueue.RateLimitingIn
if err := runSyncHandler(); err != nil {
logCtx.Errorf("%s syncHandler error: %v", objType, err)
metricsServer.IncError(namespace, name, objType)
+
+ if errors.IsNotFound(err) {
+ workqueue.Forget(obj)
+ return nil
+ }
// Put the item back on
// the workqueue to handle any transient errors.
workqueue.AddRateLimited(key)
diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go
old mode 100755
new mode 100644
index cf41e6baa5..f8fd8fe869
--- a/utils/replicaset/canary.go
+++ b/utils/replicaset/canary.go
@@ -4,6 +4,8 @@ import (
"encoding/json"
"math"
+ "github.com/argoproj/argo-rollouts/utils/annotations"
+
log "github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -15,7 +17,7 @@ import (
const (
// EphemeralMetadataAnnotation denotes pod metadata which is ephemerally injected to canary/stable pods
- EphemeralMetadataAnnotation = "rollout.argoproj.io/ephemeral-metadata"
+ EphemeralMetadataAnnotation = annotations.RolloutLabel + "/ephemeral-metadata"
)
func allDesiredAreAvailable(rs *appsv1.ReplicaSet, desired int32) bool {
diff --git a/utils/rollout/rolloututil.go b/utils/rollout/rolloututil.go
index 0b7df7ff38..5411f3f58c 100644
--- a/utils/rollout/rolloututil.go
+++ b/utils/rollout/rolloututil.go
@@ -4,6 +4,8 @@ import (
"fmt"
"strconv"
+ "github.com/argoproj/argo-rollouts/utils/weightutil"
+
replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset"
"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
@@ -184,13 +186,13 @@ func CanaryStepString(c v1alpha1.CanaryStep) string {
// ShouldVerifyWeight We use this to test if we should verify weights because weight verification could involve
// API calls to the cloud provider which could incur rate limiting
-func ShouldVerifyWeight(ro *v1alpha1.Rollout) bool {
+func ShouldVerifyWeight(ro *v1alpha1.Rollout, desiredWeight int32) bool {
currentStep, _ := replicasetutil.GetCurrentCanaryStep(ro)
// If we are in the middle of an update at a setWeight step, also perform weight verification.
// Note that we don't do this every reconciliation because weight verification typically involves
// API calls to the cloud provider which could incur rate limitingq
- shouldVerifyWeight := ro.Status.StableRS != "" &&
- !IsFullyPromoted(ro) &&
- currentStep != nil && currentStep.SetWeight != nil
+ shouldVerifyWeight := (ro.Status.StableRS != "" && !IsFullyPromoted(ro) && currentStep != nil && currentStep.SetWeight != nil) ||
+ (ro.Status.StableRS != "" && !IsFullyPromoted(ro) && currentStep == nil && desiredWeight == weightutil.MaxTrafficWeight(ro)) // We are at end of rollout
+
return shouldVerifyWeight
}
diff --git a/utils/rollout/rolloututil_test.go b/utils/rollout/rolloututil_test.go
index 37c1810f00..d88f080f64 100644
--- a/utils/rollout/rolloututil_test.go
+++ b/utils/rollout/rolloututil_test.go
@@ -422,15 +422,21 @@ func TestShouldVerifyWeight(t *testing.T) {
ro.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{
SetWeight: pointer.Int32Ptr(20),
}}
- assert.Equal(t, true, ShouldVerifyWeight(ro))
+ assert.Equal(t, true, ShouldVerifyWeight(ro, 20))
ro.Status.StableRS = ""
- assert.Equal(t, false, ShouldVerifyWeight(ro))
+ assert.Equal(t, false, ShouldVerifyWeight(ro, 20))
ro.Status.StableRS = "34feab23f"
ro.Status.CurrentStepIndex = nil
ro.Spec.Strategy.Canary.Steps = nil
- assert.Equal(t, false, ShouldVerifyWeight(ro))
+ assert.Equal(t, false, ShouldVerifyWeight(ro, 20))
+
+ // Test when the weight is 100, because we are at end of rollout
+ ro.Status.StableRS = "34feab23f"
+ ro.Status.CurrentStepIndex = nil
+ ro.Spec.Strategy.Canary.Steps = nil
+ assert.Equal(t, true, ShouldVerifyWeight(ro, 100))
}
func Test_isGenerationObserved(t *testing.T) {