From abf7bf01320c62c3232d12b715da2b6e1d746d89 Mon Sep 17 00:00:00 2001 From: cskh Date: Fri, 2 Jul 2021 16:02:01 -0400 Subject: [PATCH 01/90] fix: default replica before resolving workloadRef (#1304) Signed-off-by: Hui Kang --- rollout/controller.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/rollout/controller.go b/rollout/controller.go index 479c69bd4a..d9e09c9510 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -360,14 +360,6 @@ func (c *Controller) syncHandler(key string) error { return nil } - // In order to work with HPA, the rollout.Spec.Replica field cannot be nil. As a result, the controller will update - // the rollout to have the replicas field set to the default value. see https://github.com/argoproj/argo-rollouts/issues/119 - if rollout.Spec.Replicas == nil { - logCtx.Info("Defaulting .spec.replica to 1") - r.Spec.Replicas = pointer.Int32Ptr(defaults.DefaultReplicas) - _, err := c.argoprojclientset.ArgoprojV1alpha1().Rollouts(r.Namespace).Update(ctx, r, metav1.UpdateOptions{}) - return err - } defer func() { duration := time.Since(startTime) c.metricsServer.IncRolloutReconcile(r, duration) @@ -385,6 +377,15 @@ func (c *Controller) syncHandler(key string) error { return resolveErr } + // In order to work with HPA, the rollout.Spec.Replica field cannot be nil. As a result, the controller will update + // the rollout to have the replicas field set to the default value. see https://github.com/argoproj/argo-rollouts/issues/119 + if rollout.Spec.Replicas == nil { + logCtx.Info("Defaulting .spec.replica to 1") + r.Spec.Replicas = pointer.Int32Ptr(defaults.DefaultReplicas) + _, err := c.argoprojclientset.ArgoprojV1alpha1().Rollouts(r.Namespace).Update(ctx, r, metav1.UpdateOptions{}) + return err + } + err = roCtx.reconcile() if roCtx.newRollout != nil { c.writeBackToInformer(roCtx.newRollout) From 6de1184aa1d018952db55237e1c4373914261ad1 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Thu, 22 Jul 2021 15:05:15 -0700 Subject: [PATCH 02/90] fix: unsolicited rollout after upgrade from v0.10->v1.0 when pod was using service account (#1367) Signed-off-by: Jesse Suen --- utils/replicaset/replicaset.go | 9 +++++ utils/replicaset/replicaset_test.go | 52 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/utils/replicaset/replicaset.go b/utils/replicaset/replicaset.go index a2689fef94..10eb33cf04 100644 --- a/utils/replicaset/replicaset.go +++ b/utils/replicaset/replicaset.go @@ -493,6 +493,15 @@ func PodTemplateEqualIgnoreHash(live, desired *corev1.PodTemplateSpec) bool { } corev1defaults.SetObjectDefaults_PodTemplate(&podTemplate) desired = &podTemplate.Template + + // Do not allow the deprecated spec.serviceAccount to factor into the equality check. In live + // ReplicaSet pod template, this field will be populated, but in the desired pod template + // it will be missing (even after defaulting), causing us to believe there is a diff + // (when there really wasn't), and hence causing an unsolicited update to be triggered. + // See: https://github.com/argoproj/argo-rollouts/issues/1356 + desired.Spec.DeprecatedServiceAccount = "" + live.Spec.DeprecatedServiceAccount = "" + return apiequality.Semantic.DeepEqual(live, desired) } diff --git a/utils/replicaset/replicaset_test.go b/utils/replicaset/replicaset_test.go index 7bad09958e..de103ffe6a 100644 --- a/utils/replicaset/replicaset_test.go +++ b/utils/replicaset/replicaset_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/ghodss/yaml" "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -1167,3 +1168,54 @@ func TestGetPodsOwnedByReplicaSet(t *testing.T) { assert.Len(t, pods, 1) assert.Equal(t, "guestbook-abc123", pods[0].Name) } + +// TestPodTemplateEqualIgnoreHashWithServiceAccount catches a corner case where the K8s ComputeHash +// function changed from underneath us, and we fell back to deep equality checking, which then +// incorrectly detected a diff because of a deprecated field being present in the live but not desired. +func TestPodTemplateEqualIgnoreHashWithServiceAccount(t *testing.T) { + var desired corev1.PodTemplateSpec + desiredTemplate := ` +metadata: + labels: + app: serviceaccount-ro +spec: + containers: + - image: nginx:1.19-alpine + name: app + serviceAccountName: default +` + err := yaml.Unmarshal([]byte(desiredTemplate), &desired) + assert.NoError(t, err) + + // liveTemplate was captured from a ReplicaSet generated from the above desired template using + // Argo Rollouts v0.10. The rollouts-pod-template-hash value will not match newer hashing + // versions, causing PodTemplateEqualIgnoreHash to fall back to a deep equality check and + // pod template defaulting. + liveTemplate := ` +metadata: + creationTimestamp: null + labels: + app: serviceaccount-ro + rollouts-pod-template-hash: 8684587d99 +spec: + containers: + - image: nginx:1.19-alpine + imagePullPolicy: IfNotPresent + name: app + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + serviceAccount: default + serviceAccountName: default + terminationGracePeriodSeconds: 30 +` + var live corev1.PodTemplateSpec + err = yaml.Unmarshal([]byte(liveTemplate), &live) + assert.NoError(t, err) + + assert.True(t, PodTemplateEqualIgnoreHash(&live, &desired)) +} From 8b53b2c2d4e613ba5ff7f763c391ef22ee7b06f5 Mon Sep 17 00:00:00 2001 From: csamant-salesforce <80490530+csamant-salesforce@users.noreply.github.com> Date: Mon, 26 Jul 2021 10:34:14 -0700 Subject: [PATCH 03/90] fix: Abort rollout doesn't remove all canary pods for setCanaryScale (#1352) Signed-off-by: Chinmoy Samant --- ...-rollout-abort-delete-all-canary-pods.yaml | 90 +++++++++++++++++++ test/e2e/istio_test.go | 29 ++++++ utils/replicaset/canary.go | 4 + 3 files changed, 123 insertions(+) create mode 100644 test/e2e/istio/istio-rollout-abort-delete-all-canary-pods.yaml diff --git a/test/e2e/istio/istio-rollout-abort-delete-all-canary-pods.yaml b/test/e2e/istio/istio-rollout-abort-delete-all-canary-pods.yaml new file mode 100644 index 0000000000..29e0dee1aa --- /dev/null +++ b/test/e2e/istio/istio-rollout-abort-delete-all-canary-pods.yaml @@ -0,0 +1,90 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + replicas: 5 + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + istio: + virtualService: + name: istio-host-split-vsvc + routes: + - primary + steps: + - setCanaryScale: + replicas: 2 + - setWeight: 20 + - pause: {} + - setCanaryScale: + replicas: 4 + - setWeight: 40 + - pause: {} + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: nginx:1.19-alpine + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m diff --git a/test/e2e/istio_test.go b/test/e2e/istio_test.go index 967abbbb03..2a01158be7 100644 --- a/test/e2e/istio_test.go +++ b/test/e2e/istio_test.go @@ -197,3 +197,32 @@ func (s *IstioSuite) TestIstioSubsetSplitSingleRoute() { }). ExpectRevisionPodCount("1", 1) // don't scale down old replicaset since it will be within scaleDownDelay } + +func (s *IstioSuite) TestIstioAbortUpdateDeleteAllCanaryPods() { + s.Given(). + RolloutObjects("@istio/istio-rollout-abort-delete-all-canary-pods.yaml"). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + Then(). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Then(). + ExpectRevisionPodCount("2", 2). + When(). + PromoteRollout(). + WaitForRolloutStatus("Paused"). + Then(). + When(). + PromoteRollout(). + WaitForRolloutStatus("Paused"). + Then(). + ExpectRevisionPodCount("2", 4). + When(). + AbortRollout(). + WaitForRolloutStatus("Degraded"). + Then(). + ExpectRevisionPodCount("2", 0). + ExpectRevisionPodCount("1", 5) +} diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index 701c842a26..69ce4ca2cf 100644 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -331,6 +331,10 @@ func GetCurrentSetWeight(rollout *v1alpha1.Rollout) int32 { // TrafficRouting is required to be set for SetCanaryScale to be applicable. // If MatchTrafficWeight is set after a previous SetCanaryScale step, it will likewise be ignored. func UseSetCanaryScale(rollout *v1alpha1.Rollout) *v1alpha1.SetCanaryScale { + // Return nil when rollout is aborted + if rollout.Status.Abort { + return nil + } currentStep, currentStepIndex := GetCurrentCanaryStep(rollout) if currentStep == nil { return nil From 4622ae4a54d8e783f98ca03ef87be885ade849f4 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Thu, 29 Jul 2021 14:44:41 -0700 Subject: [PATCH 04/90] fix: nil pointer dereference when reconciling paused blue-green rollout (#1378) Signed-off-by: Jesse Suen --- rollout/bluegreen.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/rollout/bluegreen.go b/rollout/bluegreen.go index 4fb7b2beba..2e2143d560 100644 --- a/rollout/bluegreen.go +++ b/rollout/bluegreen.go @@ -163,22 +163,24 @@ func (c *rolloutContext) reconcileBlueGreenPause(activeSvc, previewSvc *corev1.S return } pauseCond := getPauseCondition(c.rollout, v1alpha1.PauseReasonBlueGreenPause) - if pauseCond == nil && !c.rollout.Status.ControllerPause { - if pauseCond == nil { - c.log.Info("pausing") - } - c.pauseContext.AddPauseCondition(v1alpha1.PauseReasonBlueGreenPause) - return - } - - if !c.pauseContext.CompletedBlueGreenPause() { - c.log.Info("pause incomplete") - if c.rollout.Spec.Strategy.BlueGreen.AutoPromotionSeconds > 0 { - c.checkEnqueueRolloutDuringWait(pauseCond.StartTime, c.rollout.Spec.Strategy.BlueGreen.AutoPromotionSeconds) + if pauseCond != nil { + // We are currently paused. Check if we completed our pause duration + if !c.pauseContext.CompletedBlueGreenPause() { + c.log.Info("pause incomplete") + if c.rollout.Spec.Strategy.BlueGreen.AutoPromotionSeconds > 0 { + c.checkEnqueueRolloutDuringWait(pauseCond.StartTime, c.rollout.Spec.Strategy.BlueGreen.AutoPromotionSeconds) + } + } else { + c.log.Infof("pause completed") + c.pauseContext.RemovePauseCondition(v1alpha1.PauseReasonBlueGreenPause) } } else { - c.log.Infof("pause completed") - c.pauseContext.RemovePauseCondition(v1alpha1.PauseReasonBlueGreenPause) + // no pause condition exists. If Status.ControllerPause is true, the user manually resumed + // the rollout. e.g. `kubectl argo rollouts promote ROLLOUT` + if !c.rollout.Status.ControllerPause { + c.log.Info("pausing") + c.pauseContext.AddPauseCondition(v1alpha1.PauseReasonBlueGreenPause) + } } } From c63b6c1f5134a9f19caae37765f1a8a145f62d7d Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Fri, 30 Jul 2021 16:25:37 -0700 Subject: [PATCH 05/90] fix: Promote full did not work against BlueGreen with previewReplicaCount (#1384) Signed-off-by: Jesse Suen --- test/e2e/bluegreen_test.go | 100 ++++++++++++++++++++++++++++ test/e2e/functional_test.go | 51 -------------- test/fixtures/when.go | 1 + utils/replicaset/replicaset.go | 18 +++-- utils/replicaset/replicaset_test.go | 8 +++ 5 files changed, 123 insertions(+), 55 deletions(-) diff --git a/test/e2e/bluegreen_test.go b/test/e2e/bluegreen_test.go index 9c91c6c0ef..cc3061987a 100644 --- a/test/e2e/bluegreen_test.go +++ b/test/e2e/bluegreen_test.go @@ -278,3 +278,103 @@ spec: Then(). ExpectActiveRevision("2") } + +// TestBlueGreenPreviewReplicaCount verifies the previewReplicaCount feature +func (s *BlueGreenSuite) TestBlueGreenPreviewReplicaCount() { + s.Given(). + RolloutObjects(newService("bluegreen-preview-replicas-active")). + RolloutObjects(newService("bluegreen-preview-replicas-preview")). + RolloutObjects(` +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: bluegreen-preview-replicas +spec: + replicas: 2 + strategy: + blueGreen: + activeService: bluegreen-preview-replicas-active + previewService: bluegreen-preview-replicas-preview + previewReplicaCount: 1 + scaleDownDelaySeconds: 5 + autoPromotionEnabled: false + selector: + matchLabels: + app: bluegreen-preview-replicas + template: + metadata: + labels: + app: bluegreen-preview-replicas + spec: + containers: + - name: bluegreen-preview-replicas + image: nginx:1.19-alpine + resources: + requests: + memory: 16Mi + cpu: 1m +`). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Then(). + ExpectRevisionPodCount("2", 1). + ExpectRevisionPodCount("1", 2). + ExpectReplicaCounts(2, 3, 1, 2, 2). // desired, current, updated, ready, available + When(). + PromoteRollout(). + WaitForRolloutStatus("Healthy"). + Then(). + ExpectReplicaCounts(2, 4, 2, 2, 2) +} + +// TestBlueGreenPreviewReplicaCountPromoteFull verifies promote full works with previewReplicaCount +func (s *FunctionalSuite) TestBlueGreenPreviewReplicaCountPromoteFull() { + s.Given(). + RolloutObjects(newService("bluegreen-preview-replicas-active")). + RolloutObjects(` +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: bluegreen-preview-replicas-promote-full +spec: + replicas: 2 + progressDeadlineSeconds: 1 # use a very short value to cause Degraded condition frequently + strategy: + blueGreen: + activeService: bluegreen-preview-replicas-active + previewReplicaCount: 1 + autoPromotionEnabled: false + selector: + matchLabels: + app: bluegreen-preview-replicas-promote-full + template: + metadata: + labels: + app: bluegreen-preview-replicas-promote-full + spec: + containers: + - name: bluegreen-preview-replicas-promote-full + image: nginx:1.19-alpine + resources: + requests: + memory: 16Mi + cpu: 1m +`). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Sleep(2*time.Second). // sleep for longer than progressDeadlineSeconds + Then(). + ExpectRolloutStatus("Paused"). // the fact that we are paused for longer than progressDeadlineSeconds, should not cause Degraded + ExpectReplicaCounts(2, 3, 1, 2, 2). // desired, current, updated, ready, available + When(). + PromoteRolloutFull(). + WaitForRolloutStatus("Healthy"). + Then(). + ExpectReplicaCounts(2, 4, 2, 2, 2) +} diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index b32e5353a1..0cd740089b 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -706,57 +706,6 @@ func (s *FunctionalSuite) TestBlueGreenUpdate() { }) } -// TestBlueGreenPreviewReplicaCount verifies the previewReplicaCount feature -func (s *FunctionalSuite) TestBlueGreenPreviewReplicaCount() { - s.Given(). - RolloutObjects(newService("bluegreen-preview-replicas-active")). - RolloutObjects(newService("bluegreen-preview-replicas-preview")). - RolloutObjects(` -apiVersion: argoproj.io/v1alpha1 -kind: Rollout -metadata: - name: bluegreen-preview-replicas -spec: - replicas: 2 - strategy: - blueGreen: - activeService: bluegreen-preview-replicas-active - previewService: bluegreen-preview-replicas-preview - previewReplicaCount: 1 - scaleDownDelaySeconds: 5 - autoPromotionEnabled: false - selector: - matchLabels: - app: bluegreen-preview-replicas - template: - metadata: - labels: - app: bluegreen-preview-replicas - spec: - containers: - - name: bluegreen-preview-replicas - image: nginx:1.19-alpine - resources: - requests: - memory: 16Mi - cpu: 1m -`). - When(). - ApplyManifests(). - WaitForRolloutStatus("Healthy"). - UpdateSpec(). - WaitForRolloutStatus("Paused"). - Then(). - ExpectRevisionPodCount("2", 1). - ExpectRevisionPodCount("1", 2). - ExpectReplicaCounts(2, 3, 1, 2, 2). // desired, current, updated, ready, available - When(). - PromoteRollout(). - WaitForRolloutStatus("Healthy"). - Then(). - ExpectReplicaCounts(2, 4, 2, 2, 2) -} - // TestBlueGreenToCanary tests behavior when migrating from bluegreen to canary func (s *FunctionalSuite) TestBlueGreenToCanary() { s.Given(). diff --git a/test/fixtures/when.go b/test/fixtures/when.go index b8a2a4d022..3843aed283 100644 --- a/test/fixtures/when.go +++ b/test/fixtures/when.go @@ -189,6 +189,7 @@ func (w *When) ScaleRollout(scale int) *When { } func (w *When) Sleep(d time.Duration) *When { + w.log.Infof("Sleeping %s", d) time.Sleep(d) return w } diff --git a/utils/replicaset/replicaset.go b/utils/replicaset/replicaset.go index 10eb33cf04..cd552ab609 100644 --- a/utils/replicaset/replicaset.go +++ b/utils/replicaset/replicaset.go @@ -233,22 +233,32 @@ func FindOldReplicaSets(rollout *v1alpha1.Rollout, rsList []*appsv1.ReplicaSet) // 2) Max number of pods allowed is reached: deployment's replicas + maxSurge == all RSs' replicas func NewRSNewReplicas(rollout *v1alpha1.Rollout, allRSs []*appsv1.ReplicaSet, newRS *appsv1.ReplicaSet) (int32, error) { if rollout.Spec.Strategy.BlueGreen != nil { + desiredReplicas := defaults.GetReplicasOrDefault(rollout.Spec.Replicas) if rollout.Spec.Strategy.BlueGreen.PreviewReplicaCount != nil { activeRS, _ := GetReplicaSetByTemplateHash(allRSs, rollout.Status.BlueGreen.ActiveSelector) if activeRS == nil || activeRS.Name == newRS.Name { - return defaults.GetReplicasOrDefault(rollout.Spec.Replicas), nil + // the active RS is our desired RS. we are already past the blue-green promote step + return desiredReplicas, nil + } + if rollout.Status.PromoteFull { + // we are doing a full promotion. ignore previewReplicaCount + return desiredReplicas, nil } if newRS.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] != rollout.Status.CurrentPodHash { + // the desired RS is not equal to our previously recorded current RS. + // This must be a new update, so return previewReplicaCount return *rollout.Spec.Strategy.BlueGreen.PreviewReplicaCount, nil } isNotPaused := !rollout.Spec.Paused && len(rollout.Status.PauseConditions) == 0 if isNotPaused && rollout.Status.BlueGreen.ScaleUpPreviewCheckPoint { - return defaults.GetReplicasOrDefault(rollout.Spec.Replicas), nil + // We are not paused, but we are already past our preview scale up checkpoint. + // If we get here, we were resumed after the pause, but haven't yet flipped the + // active service switch to the desired RS. + return desiredReplicas, nil } return *rollout.Spec.Strategy.BlueGreen.PreviewReplicaCount, nil } - - return defaults.GetReplicasOrDefault(rollout.Spec.Replicas), nil + return desiredReplicas, nil } if rollout.Spec.Strategy.Canary != nil { stableRS := GetStableRS(rollout, newRS, allRSs) diff --git a/utils/replicaset/replicaset_test.go b/utils/replicaset/replicaset_test.go index de103ffe6a..e69d8a79ca 100644 --- a/utils/replicaset/replicaset_test.go +++ b/utils/replicaset/replicaset_test.go @@ -225,6 +225,7 @@ func TestNewRSNewReplicasWitPreviewReplicaCount(t *testing.T) { overrideCurrentPodHash string scaleUpPreviewCheckpoint bool expectReplicaCount int32 + promoteFull bool }{ { name: "No active rs is set", @@ -253,6 +254,12 @@ func TestNewRSNewReplicasWitPreviewReplicaCount(t *testing.T) { activeSelector: "bar", expectReplicaCount: previewReplicaCount, }, + { + name: "Ignore preview replica count during promote full", + activeSelector: "bar", + expectReplicaCount: replicaCount, + promoteFull: true, + }, } for i := range tests { test := tests[i] @@ -272,6 +279,7 @@ func TestNewRSNewReplicasWitPreviewReplicaCount(t *testing.T) { ActiveSelector: test.activeSelector, }, CurrentPodHash: "foo", + PromoteFull: test.promoteFull, }, } if test.overrideCurrentPodHash != "" { From f899402a0c3adea69fbf2e657c3d0ee67464efc0 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Mon, 2 Aug 2021 16:37:36 -0700 Subject: [PATCH 06/90] chore: github release action was using incorect docker cache (#1387) Signed-off-by: Jesse Suen --- .github/workflows/release.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d80a2b406b..f146ba475c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -17,6 +17,10 @@ jobs: with: ref: ${{ github.event.inputs.tag }} + - name: Get SHA + id: get-sha + run: echo "::set-output name=sha::$(git log -1 --format='%H')" + - name: Set up QEMU uses: docker/setup-qemu-action@v1 @@ -27,9 +31,7 @@ jobs: uses: actions/cache@v2 with: path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- + key: ${{ runner.os }}-buildx-${{ steps.get-sha.outputs.sha }} - name: Print Disk Usage run: | From c2e351ba5d8800f2a46372dfa558fb2fae49add5 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Mon, 2 Aug 2021 19:38:09 -0700 Subject: [PATCH 07/90] chore: release workflow docker build context should use local path and not git context (#1388) Signed-off-by: Jesse Suen --- .github/workflows/release.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f146ba475c..0583bf14eb 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -47,6 +47,8 @@ jobs: ghcr.io/argoproj/argo-rollouts tags: | type=semver,pattern={{version}},prefix=v,value=${{ github.event.inputs.tag }} + flavor: | + latest=false - name: Docker meta (plugin) id: plugin-meta @@ -57,6 +59,8 @@ jobs: ghcr.io/argoproj/kubectl-argo-rollouts tags: | type=semver,pattern={{version}},prefix=v,value=${{ github.event.inputs.tag }} + flavor: | + latest=false - name: Login to GitHub Container Registry if: github.event_name != 'pull_request' @@ -77,6 +81,7 @@ jobs: - name: Build and push (controller-image) uses: docker/build-push-action@v2 with: + context: . platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.controller-meta.outputs.tags }} @@ -86,6 +91,7 @@ jobs: - name: Build and push (plugin-image) uses: docker/build-push-action@v2 with: + context: . target: kubectl-argo-rollouts platforms: linux/amd64,linux/arm64 push: true From 6d84b7e721f5882535341cdef8a430557a712b4b Mon Sep 17 00:00:00 2001 From: harikrongali <81331774+harikrongali@users.noreply.github.com> Date: Mon, 23 Aug 2021 13:12:07 -0700 Subject: [PATCH 08/90] fix: canary scaledown event could violate maxUnavailable (#1429) Signed-off-by: hari rongali --- test/e2e/canary_test.go | 58 +++++++++++++++++++- utils/replicaset/canary.go | 93 +++++++++++++++++++++++++-------- utils/replicaset/canary_test.go | 16 ++++++ 3 files changed, 143 insertions(+), 24 deletions(-) diff --git a/test/e2e/canary_test.go b/test/e2e/canary_test.go index 9c0158f4e3..490480ac42 100644 --- a/test/e2e/canary_test.go +++ b/test/e2e/canary_test.go @@ -112,6 +112,58 @@ func (s *CanarySuite) TestRolloutScalingWhenPaused() { ExpectCanaryStablePodCount(1, 3) } + +// TestRolloutWithMaxSurgeScalingDuringUpdate verifies behavior when scaling a rollout up/down in middle of update and with maxSurge 100% +func (s *CanarySuite) TestRolloutWithMaxSurgeScalingDuringUpdate() { + s.Given(). + HealthyRollout(` +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: updatescaling +spec: + replicas: 4 + strategy: + canary: + maxSurge: 100% + selector: + matchLabels: + app: updatescaling + template: + metadata: + labels: + app: updatescaling + spec: + containers: + - name: updatescaling + image: nginx:1.19-alpine + resources: + requests: + memory: 16Mi + cpu: 1m`). + When(). + PatchSpec(` +spec: + template: + spec: + containers: + - name: updatescaling + command: [/bad-command]`). + WaitForRolloutReplicas(7). + Then(). + ExpectCanaryStablePodCount(4, 3). + When(). + ScaleRollout(8). + WaitForRolloutReplicas(11). + Then(). + ExpectCanaryStablePodCount(8, 3). + When(). + ScaleRollout(4). + WaitForRolloutReplicas(7). + Then(). + ExpectCanaryStablePodCount(4, 3) +} + // TestRolloutScalingDuringUpdate verifies behavior when scaling a rollout up/down in middle of update func (s *CanarySuite) TestRolloutScalingDuringUpdate() { s.Given(). @@ -160,8 +212,10 @@ spec: // See: https://github.com/argoproj/argo-rollouts/issues/738 ExpectCanaryStablePodCount(6, 4). When(). - ScaleRollout(4) - // WaitForRolloutReplicas(4) // this doesn't work yet (bug) + ScaleRollout(4). + WaitForRolloutReplicas(6). + Then(). + ExpectCanaryStablePodCount(2, 4) } // TestReduceWeightAndHonorMaxUnavailable verifies we honor maxUnavailable when decreasing weight or aborting diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index 69ce4ca2cf..d73c9f5e19 100644 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -175,12 +175,12 @@ func CalculateReplicaCountsForCanary(rollout *v1alpha1.Rollout, newRS *appsv1.Re } minAvailableReplicaCount := rolloutSpecReplica - MaxUnavailable(rollout) + // isIncreasing indicates if we are supposed to be increasing our canary replica count. // If so, we can ignore pod availability of the stableRS. Otherwise, if we are reducing our // weight (e.g. we are aborting), then we can ignore pod availability of the canaryRS. isIncreasing := newRS == nil || desiredNewRSReplicaCount >= *newRS.Spec.Replicas replicasToScaleDown := GetReplicasForScaleDown(newRS, !isIncreasing) + GetReplicasForScaleDown(stableRS, isIncreasing) - if replicasToScaleDown <= minAvailableReplicaCount { // Cannot scale down stableRS or newRS without going below min available replica count return newRSReplicaCount, stableRSReplicaCount @@ -188,31 +188,80 @@ func CalculateReplicaCountsForCanary(rollout *v1alpha1.Rollout, newRS *appsv1.Re scaleDownCount := replicasToScaleDown - minAvailableReplicaCount - if newRS != nil && *newRS.Spec.Replicas > desiredNewRSReplicaCount { - // if the controller doesn't have to use every replica to achieve the desired count, it only scales down to the - // desired count. - if *newRS.Spec.Replicas-scaleDownCount < desiredNewRSReplicaCount { - newRSReplicaCount = desiredNewRSReplicaCount - // Calculating how many replicas were used to scale down to the desired count - scaleDownCount = scaleDownCount - (*newRS.Spec.Replicas - desiredNewRSReplicaCount) - } else { - // The controller is using every replica it can to get closer to desired state. - newRSReplicaCount = *newRS.Spec.Replicas - scaleDownCount - scaleDownCount = 0 - } + if !isIncreasing { + // Skip scalingDown Stable replicaSet when Canary availability is not taken into calculation for scaleDown + newRSReplicaCount = calculateScaleDownReplicaCount(newRS, desiredNewRSReplicaCount, scaleDownCount, newRSReplicaCount) + newRSReplicaCount, stableRSReplicaCount = adjustReplicaWithinLimits(newRS, stableRS, newRSReplicaCount, stableRSReplicaCount, maxReplicaCountAllowed, minAvailableReplicaCount) + } else { + // Skip scalingDown canary replicaSet when StableSet availability is not taken into calculation for scaleDown + stableRSReplicaCount = calculateScaleDownReplicaCount(stableRS, desiredStableRSReplicaCount, scaleDownCount, stableRSReplicaCount) + stableRSReplicaCount, newRSReplicaCount = adjustReplicaWithinLimits(stableRS, newRS, stableRSReplicaCount, newRSReplicaCount, maxReplicaCountAllowed, minAvailableReplicaCount) } + return newRSReplicaCount, stableRSReplicaCount +} - if scaleStableRS && *stableRS.Spec.Replicas > desiredStableRSReplicaCount { - // This follows the same logic as scaling down the newRS except with the stableRS and it does not need to - // set the scaleDownCount again since it's not used again - if *stableRS.Spec.Replicas-scaleDownCount < desiredStableRSReplicaCount { - stableRSReplicaCount = desiredStableRSReplicaCount - } else { - stableRSReplicaCount = *stableRS.Spec.Replicas - scaleDownCount - } +// calculateScaleDownReplicaCount calculates drainRSReplicaCount +// drainRSReplicaCount can be either stableRS count or canaryRS count +// drainRSReplicaCount corresponds to RS whose availability is not considered in calculating replicasToScaleDown +func calculateScaleDownReplicaCount(drainRS *appsv1.ReplicaSet, desireRSReplicaCount int32, scaleDownCount int32, drainRSReplicaCount int32) int32 { + if drainRS != nil && *drainRS.Spec.Replicas > desireRSReplicaCount { + // if the controller doesn't have to use every replica to achieve the desired count, + // it can scales down to the desired count or get closer to desired state. + drainRSReplicaCount = maxValue(desireRSReplicaCount, *drainRS.Spec.Replicas-scaleDownCount) } + return drainRSReplicaCount +} - return newRSReplicaCount, stableRSReplicaCount +// adjustReplicaWithinLimits adjusts replicaCounters to be within maxSurge & maxUnavailable limits +// drainRSReplicaCount corresponds to RS whose availability is not considered in calculating replicasToScaleDown +// adjustRSReplicaCount corresponds to RS whose availability is to taken account while adjusting maxUnavailable limit +func adjustReplicaWithinLimits(drainRS *appsv1.ReplicaSet, adjustRS *appsv1.ReplicaSet, drainRSReplicaCount int32, adjustRSReplicaCount int32, maxReplicaCountAllowed int32, minAvailableReplicaCount int32) (int32, int32) { + extraAvailableAdjustRS := int32(0) + totalAvailableReplicas := int32(0) + // calculates current limit over the allowed value + overTheLimitVal := maxValue(0, adjustRSReplicaCount+drainRSReplicaCount-maxReplicaCountAllowed) + if drainRS != nil { + totalAvailableReplicas = totalAvailableReplicas + minValue(drainRS.Status.AvailableReplicas, drainRSReplicaCount) + } + if adjustRS != nil { + // 1. adjust adjustRSReplicaCount to be within maxSurge + adjustRSReplicaCount = adjustRSReplicaCount - overTheLimitVal + // 2. Calculate availability corresponding to adjusted count + totalAvailableReplicas = totalAvailableReplicas + minValue(adjustRS.Status.AvailableReplicas, adjustRSReplicaCount) + // 3. Calculate decrease in availability of adjustRS because of (1) + extraAvailableAdjustRS = maxValue(0, adjustRS.Status.AvailableReplicas-adjustRSReplicaCount) + + // 4. Now calculate how far count is from maxUnavailable limit + moreToNeedAvailableReplicas := maxValue(0, minAvailableReplicaCount-totalAvailableReplicas) + // 5. From (3), we got the count for decrease in availability because of (1), + // take the min of (3) & (4) and add it back to adjustRS + // remaining of moreToNeedAvailableReplicas can be ignored as it is part of drainRS, + // there is no case of deviating from maxUnavailable limit from drainRS as in the event of said case, + // scaleDown calculation wont even occur as we are checking + // replicasToScaleDown <= minAvailableReplicaCount in caller function + adjustRSReplicaCount = adjustRSReplicaCount + minValue(extraAvailableAdjustRS, moreToNeedAvailableReplicas) + // 6. Calculate final overTheLimit because of adjustment + overTheLimitVal = maxValue(0, adjustRSReplicaCount+drainRSReplicaCount-maxReplicaCountAllowed) + // 7. we can safely subtract from drainRS and other cases like deviation from maxUnavailable limit + // wont occur as said in (5) + drainRSReplicaCount = drainRSReplicaCount - overTheLimitVal + } + + return drainRSReplicaCount, adjustRSReplicaCount +} + +func minValue(countA int32, countB int32) int32 { + if countA > countB { + return countB + } + return countA +} + +func maxValue(countA int32, countB int32) int32 { + if countA < countB { + return countB + } + return countA } // BeforeStartingStep checks if canary rollout is at the starting step diff --git a/utils/replicaset/canary_test.go b/utils/replicaset/canary_test.go index ac4a548865..c82ba28836 100644 --- a/utils/replicaset/canary_test.go +++ b/utils/replicaset/canary_test.go @@ -336,6 +336,22 @@ func TestCalculateReplicaCountsForCanary(t *testing.T) { expectedStableReplicaCount: 7, expectedCanaryReplicaCount: 3, }, + { + name: "Scale down stable and canary available", + rolloutSpecReplicas: 10, + setWeight: 100, + maxSurge: intstr.FromInt(1), + maxUnavailable: intstr.FromInt(0), + + stableSpecReplica: 10, + stableAvailableReplica: 2, + + canarySpecReplica: 10, + canaryAvailableReplica: 8, + + expectedStableReplicaCount: 2, + expectedCanaryReplicaCount: 9, + }, { name: "Do not scale down newRS or stable when older RS count >= scaleDownCount", rolloutSpecReplicas: 10, From 1e52def1a61d96ac03336cb71d2d0d806c8ca717 Mon Sep 17 00:00:00 2001 From: harikrongali <81331774+harikrongali@users.noreply.github.com> Date: Tue, 17 Aug 2021 01:18:45 -0700 Subject: [PATCH 09/90] fix: analysis runs to wait for all metrics to complete (#1407) Signed-off-by: hari rongali --- analysis/analysis.go | 8 ++++ test/e2e/analysis_test.go | 23 ++++++++++ .../analysistemplate-multiple-job.yaml | 43 +++++++++++++++++++ .../analysistemplate-sleep-job.yaml | 2 +- .../rollout-inline-multiple-analysis.yaml | 28 ++++++++++++ test/fixtures/then.go | 20 +++++++++ 6 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 test/e2e/functional/analysistemplate-multiple-job.yaml create mode 100644 test/e2e/functional/rollout-inline-multiple-analysis.yaml diff --git a/analysis/analysis.go b/analysis/analysis.go index 265406ef60..ab2d6b9741 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -396,6 +396,14 @@ func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun) (v1alpha1.Analys } } } + } else { + // metric hasn't started running. possible cases where some of the metrics starts with delay + everythingCompleted = false + if terminating { + // we have yet to take a single measurement, but have already been instructed to stop + log.Infof("metric assessed %s: run terminated", v1alpha1.AnalysisPhaseSuccessful) + return v1alpha1.AnalysisPhaseSuccessful, worstMessage + } } } if !everythingCompleted { diff --git a/test/e2e/analysis_test.go b/test/e2e/analysis_test.go index 42e3e2135e..23adfe4de3 100644 --- a/test/e2e/analysis_test.go +++ b/test/e2e/analysis_test.go @@ -25,6 +25,7 @@ func (s *AnalysisSuite) SetupSuite() { // shared analysis templates for suite s.ApplyManifests("@functional/analysistemplate-web-background.yaml") s.ApplyManifests("@functional/analysistemplate-sleep-job.yaml") + s.ApplyManifests("@functional/analysistemplate-multiple-job.yaml") } // convenience to generate a new service with a given name @@ -84,6 +85,28 @@ func (s *AnalysisSuite) TestCanaryInlineAnalysis() { ExpectAnalysisRunCount(3) } +func (s *AnalysisSuite) TestCanaryInlineMultipleAnalysis() { + s.Given(). + RolloutObjects("@functional/rollout-inline-multiple-analysis.yaml"). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + Then(). + ExpectAnalysisRunCount(0). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + PromoteRollout(). + Sleep(5 * time.Second). + Then(). + ExpectAnalysisRunCount(1). + ExpectInlineAnalysisRunPhase("Running"). + When(). + WaitForInlineAnalysisRunPhase("Successful"). + WaitForRolloutStatus("Healthy"). + Then(). + ExpectAnalysisRunCount(1) +} // TestBlueGreenAnalysis tests blue-green with pre/post analysis and then fast-tracked rollback func (s *AnalysisSuite) TestBlueGreenAnalysis() { original := ` diff --git a/test/e2e/functional/analysistemplate-multiple-job.yaml b/test/e2e/functional/analysistemplate-multiple-job.yaml new file mode 100644 index 0000000000..fabfeef6a2 --- /dev/null +++ b/test/e2e/functional/analysistemplate-multiple-job.yaml @@ -0,0 +1,43 @@ +# AnalysisTemplate which sleeps for a specified duration and exits with a specified exit-code +kind: AnalysisTemplate +apiVersion: argoproj.io/v1alpha1 +metadata: + name: multiple-job +spec: + args: + - name: duration + value: 0s + - name: exit-code + value: "0" + - name: count + value: "1" + metrics: + - name: sleep-job + initialDelay: 10s + count: 1 + provider: + job: + spec: + template: + spec: + containers: + - name: sleep-job + image: nginx:1.19-alpine + command: [sh, -c, -x] + args: ["sleep {{args.duration}} && exit {{args.exit-code}}"] + restartPolicy: Never + backoffLimit: 0 + - name: sleep-job-rep + count: 1 + provider: + job: + spec: + template: + spec: + containers: + - name: sleep-job + image: nginx:1.19-alpine + command: [sh, -c, -x] + args: ["sleep {{args.duration}} && exit {{args.exit-code}}"] + restartPolicy: Never + backoffLimit: 0 \ No newline at end of file diff --git a/test/e2e/functional/analysistemplate-sleep-job.yaml b/test/e2e/functional/analysistemplate-sleep-job.yaml index 462dda8d7a..39b242af99 100644 --- a/test/e2e/functional/analysistemplate-sleep-job.yaml +++ b/test/e2e/functional/analysistemplate-sleep-job.yaml @@ -25,4 +25,4 @@ spec: command: [sh, -c, -x] args: ["sleep {{args.duration}} && exit {{args.exit-code}}"] restartPolicy: Never - backoffLimit: 0 + backoffLimit: 0 \ No newline at end of file diff --git a/test/e2e/functional/rollout-inline-multiple-analysis.yaml b/test/e2e/functional/rollout-inline-multiple-analysis.yaml new file mode 100644 index 0000000000..521424f1c3 --- /dev/null +++ b/test/e2e/functional/rollout-inline-multiple-analysis.yaml @@ -0,0 +1,28 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-inline-analysis +spec: + strategy: + canary: + steps: + - setWeight: 10 + - pause: {} + - analysis: + templates: + - templateName: multiple-job + selector: + matchLabels: + app: rollout-inline-analysis + template: + metadata: + labels: + app: rollout-inline-analysis + spec: + containers: + - name: rollouts-demo + image: nginx:1.19-alpine + resources: + requests: + memory: 16Mi + cpu: 5m diff --git a/test/fixtures/then.go b/test/fixtures/then.go index 7e51dbb010..8b0f5e127c 100644 --- a/test/fixtures/then.go +++ b/test/fixtures/then.go @@ -194,6 +194,26 @@ func (t *Then) ExpectBackgroundAnalysisRunPhase(phase string) *Then { ) } +func (t *Then) ExpectInlineAnalysisRun(expectation string, expectFunc AnalysisRunExpectation) *Then { + t.t.Helper() + bgArun := t.GetInlineAnalysisRun() + if !expectFunc(bgArun) { + t.log.Errorf("Inline AnalysisRun expectation '%s' failed", expectation) + t.t.FailNow() + } + t.log.Infof("Inline AnalysisRun expectation '%s' met", expectation) + return t +} + +func (t *Then) ExpectInlineAnalysisRunPhase(phase string) *Then { + t.t.Helper() + return t.ExpectInlineAnalysisRun(fmt.Sprintf("inline analysis phase == %s", phase), + func(run *rov1.AnalysisRun) bool { + return string(run.Status.Phase) == phase + }, + ) +} + // ExpectStableRevision verifies the ReplicaSet with the specified revision is marked stable func (t *Then) ExpectStableRevision(revision string) *Then { t.t.Helper() From 4022cb8ed2408e4aa2c8acf29730bc3b2100e625 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Fri, 6 Aug 2021 03:15:18 -0700 Subject: [PATCH 10/90] fix: retarget blue-green previewService before scaling up preview ReplicaSet (#1368) Signed-off-by: Jesse Suen --- docs/features/bluegreen.md | 29 ++++++++++++++++++++--------- rollout/analysis_test.go | 3 +++ rollout/bluegreen.go | 11 ++++++----- rollout/bluegreen_test.go | 1 + rollout/canary_test.go | 13 +++++++++++-- rollout/ephemeralmetadata_test.go | 5 ++++- rollout/experiment_test.go | 1 + rollout/sync.go | 14 +++----------- rollout/sync_test.go | 7 +++++-- test/e2e/functional_test.go | 12 ++++++++---- utils/conditions/conditions.go | 2 +- 11 files changed, 63 insertions(+), 35 deletions(-) diff --git a/docs/features/bluegreen.md b/docs/features/bluegreen.md index 95e2ce4241..afb2d2f158 100644 --- a/docs/features/bluegreen.md +++ b/docs/features/bluegreen.md @@ -68,6 +68,25 @@ spec: scaleDownDelayRevisionLimit: *int32 ``` +## Sequence of Events + +The following describes the sequence of events that happen during a blue-green update. + +1. Beginning at a fully promoted, steady-state, a revision 1 ReplicaSet is pointed to by both the `activeService` and `previewService`. +1. A user initiates an update by modifying the pod template (`spec.template.spec`). +1. The revision 2 ReplicaSet is created with size 0. +1. The preview service is modified to point to the revision 2 ReplicaSet. The `activeService` remains pointing to revision 1. +1. The revision 2 ReplicaSet is scaled to either `spec.replicas` or `previewReplicaCount` if set. +1. Once revision 2 ReplicaSet Pods are fully available, `prePromotionAnalysis` begins. +1. Upon success of `prePromotionAnalysis`, the blue/green pauses if `autoPromotionEnabled` is false, or `autoPromotionSeconds` is non-zero. +1. The rollout is resumed either manually by a user, or automatically by surpassing `autoPromotionSeconds`. +1. The revision 2 ReplicaSet is scaled to the `spec.replicas`, if the `previewReplicaCount` feature was used. +1. The rollout "promotes" the revision 2 ReplicaSet by updating the `activeService` to point to it. At this point, there are no services pointing to revision 1 +1. `postPromotionAnalysis` analysis begins +1. Once `postPromotionAnalysis` completes successfully, the update is successful and the revision 2 ReplicaSet is marked as stable. The rollout is considered fully-promoted. +1. After waiting `scaleDownDelaySeconds` (default 30 seconds), the revision 1 ReplicaSet is scaled down + + ### autoPromotionEnabled The AutoPromotionEnabled will make the rollout automatically promote the new ReplicaSet to the active service once the new ReplicaSet is healthy. This field is defaulted to true if it is not specified. @@ -111,15 +130,6 @@ This feature is used to provide an endpoint that can be used to test a new versi Defaults to an empty string -Here is a timeline of how the active and preview services work (if you use a preview service): - -1. During the Initial deployment there is only one ReplicaSet. Both active and preview services point to it. This is the **old** version of the application. -1. A change happens in the Rollout resource. A new ReplicaSet is created. This is the **new** version of the application. The preview service is modified to point to the new ReplicaSet. The active service still points to the old version. -1. The blue/green deployment is "promoted". Both active and preview services are pointing to the new version. The old version is still there but no service is pointing at it. -1. Once the the blue/green deployment is scaled down (see the `scaleDownDelaySeconds` field) the old ReplicaSet is has 0 replicas and we are back to the initial state. Both active and preview services point to the new version (which is the only one present anyway) - - - ### previewReplicaCount The PreviewReplicaCount field will indicate the number of replicas that the new version of an application should run. Once the application is ready to promote to the active service, the controller will scale the new ReplicaSet to the value of the `spec.replicas`. The rollout will not switch over the active service to the new ReplicaSet until it matches the `spec.replicas` count. @@ -136,3 +146,4 @@ Defaults to 30 The ScaleDownDelayRevisionLimit limits the number of old active ReplicaSets to keep scaled up while they wait for the scaleDownDelay to pass after being removed from the active service. If omitted, all ReplicaSets will be retained for the specified scaleDownDelay + diff --git a/rollout/analysis_test.go b/rollout/analysis_test.go index 8e665ed2f7..e32aa5e982 100644 --- a/rollout/analysis_test.go +++ b/rollout/analysis_test.go @@ -1517,6 +1517,7 @@ func TestDoNotCreateBackgroundAnalysisRunOnNewCanaryRollout(t *testing.T) { f.expectCreateReplicaSetAction(rs1) f.expectUpdateRolloutStatusAction(r1) // update conditions + f.expectUpdateReplicaSetAction(rs1) // scale replica set f.expectPatchRolloutAction(r1) f.run(getKey(r1, t)) } @@ -1551,6 +1552,7 @@ func TestDoNotCreateBackgroundAnalysisRunOnNewCanaryRolloutStableRSEmpty(t *test f.expectCreateReplicaSetAction(rs1) f.expectUpdateRolloutStatusAction(r1) // update conditions + f.expectUpdateReplicaSetAction(rs1) // scale replica set f.expectPatchRolloutAction(r1) f.run(getKey(r1, t)) } @@ -1686,6 +1688,7 @@ func TestDoNotCreatePrePromotionAnalysisRunOnNewRollout(t *testing.T) { f.expectCreateReplicaSetAction(rs) f.expectUpdateRolloutStatusAction(r) + f.expectUpdateReplicaSetAction(rs) // scale RS f.expectPatchRolloutAction(r) f.run(getKey(r, t)) } diff --git a/rollout/bluegreen.go b/rollout/bluegreen.go index 2e2143d560..b9ffbedcf9 100644 --- a/rollout/bluegreen.go +++ b/rollout/bluegreen.go @@ -26,6 +26,12 @@ func (c *rolloutContext) rolloutBlueGreen() error { return err } + // This must happen right after the new replicaset is created + err = c.reconcilePreviewService(previewSvc) + if err != nil { + return err + } + if replicasetutil.CheckPodSpecChange(c.rollout, c.newRS) { return c.syncRolloutStatusBlueGreen(previewSvc, activeSvc) } @@ -40,11 +46,6 @@ func (c *rolloutContext) rolloutBlueGreen() error { return err } - err = c.reconcilePreviewService(previewSvc) - if err != nil { - return err - } - c.reconcileBlueGreenPause(activeSvc, previewSvc) err = c.reconcileActiveService(activeSvc) diff --git a/rollout/bluegreen_test.go b/rollout/bluegreen_test.go index ad37c8c073..a3d3f47199 100644 --- a/rollout/bluegreen_test.go +++ b/rollout/bluegreen_test.go @@ -54,6 +54,7 @@ func TestBlueGreenCreatesReplicaSet(t *testing.T) { f.expectCreateReplicaSetAction(rs) servicePatchIndex := f.expectPatchServiceAction(previewSvc, rsPodHash) + f.expectUpdateReplicaSetAction(rs) // scale up RS updatedRolloutIndex := f.expectUpdateRolloutStatusAction(r) expectedPatchWithoutSubs := `{ "status":{ diff --git a/rollout/canary_test.go b/rollout/canary_test.go index ace03f0ea9..bb7d4cae23 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -77,15 +77,19 @@ func TestCanaryRolloutBumpVersion(t *testing.T) { f.replicaSetLister = append(f.replicaSetLister, rs1) createdRSIndex := f.expectCreateReplicaSetAction(rs2) + updatedRSIndex := f.expectUpdateReplicaSetAction(rs2) // scale up RS updatedRolloutRevisionIndex := f.expectUpdateRolloutAction(r2) // update rollout revision updatedRolloutConditionsIndex := f.expectUpdateRolloutStatusAction(r2) // update rollout conditions f.expectPatchRolloutAction(r2) f.run(getKey(r2, t)) createdRS := f.getCreatedReplicaSet(createdRSIndex) - assert.Equal(t, int32(1), *createdRS.Spec.Replicas) + assert.Equal(t, int32(0), *createdRS.Spec.Replicas) assert.Equal(t, "2", createdRS.Annotations[annotations.RevisionAnnotation]) + updatedRS := f.getUpdatedReplicaSet(updatedRSIndex) + assert.Equal(t, int32(1), *updatedRS.Spec.Replicas) + updatedRollout := f.getUpdatedRollout(updatedRolloutRevisionIndex) assert.Equal(t, "2", updatedRollout.Annotations[annotations.RevisionAnnotation]) @@ -475,6 +479,7 @@ func TestCanaryRolloutCreateFirstReplicasetNoSteps(t *testing.T) { rs := newReplicaSet(r, 1) f.expectCreateReplicaSetAction(rs) + f.expectUpdateReplicaSetAction(rs) // scale up rs updatedRolloutIndex := f.expectUpdateRolloutStatusAction(r) patchIndex := f.expectPatchRolloutAction(r) f.run(getKey(r, t)) @@ -514,6 +519,7 @@ func TestCanaryRolloutCreateFirstReplicasetWithSteps(t *testing.T) { rs := newReplicaSet(r, 1) f.expectCreateReplicaSetAction(rs) + f.expectUpdateReplicaSetAction(rs) // scale up rs updatedRolloutIndex := f.expectUpdateRolloutStatusAction(r) patchIndex := f.expectPatchRolloutAction(r) f.run(getKey(r, t)) @@ -559,12 +565,15 @@ func TestCanaryRolloutCreateNewReplicaWithCorrectWeight(t *testing.T) { f.replicaSetLister = append(f.replicaSetLister, rs1) createdRSIndex := f.expectCreateReplicaSetAction(rs2) + updatedRSIndex := f.expectUpdateReplicaSetAction(rs2) updatedRolloutIndex := f.expectUpdateRolloutStatusAction(r2) f.expectPatchRolloutAction(r2) f.run(getKey(r2, t)) createdRS := f.getCreatedReplicaSet(createdRSIndex) - assert.Equal(t, int32(1), *createdRS.Spec.Replicas) + assert.Equal(t, int32(0), *createdRS.Spec.Replicas) + updatedRS := f.getUpdatedReplicaSet(updatedRSIndex) + assert.Equal(t, int32(1), *updatedRS.Spec.Replicas) updatedRollout := f.getUpdatedRollout(updatedRolloutIndex) progressingCondition := conditions.GetRolloutCondition(updatedRollout.Status, v1alpha1.RolloutProgressing) diff --git a/rollout/ephemeralmetadata_test.go b/rollout/ephemeralmetadata_test.go index 7e9d4b850d..a68e4f39d2 100644 --- a/rollout/ephemeralmetadata_test.go +++ b/rollout/ephemeralmetadata_test.go @@ -37,6 +37,7 @@ func TestSyncCanaryEphemeralMetadataInitialRevision(t *testing.T) { f.expectUpdateRolloutStatusAction(r1) idx := f.expectCreateReplicaSetAction(rs1) + f.expectUpdateReplicaSetAction(rs1) _ = f.expectPatchRolloutAction(r1) f.run(getKey(r1, t)) createdRS1 := f.getCreatedReplicaSet(idx) @@ -75,8 +76,9 @@ func TestSyncBlueGreenEphemeralMetadataInitialRevision(t *testing.T) { f.expectUpdateRolloutStatusAction(r1) idx := f.expectCreateReplicaSetAction(rs1) - _ = f.expectPatchRolloutAction(r1) + f.expectPatchRolloutAction(r1) f.expectPatchServiceAction(previewSvc, rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey]) + f.expectUpdateReplicaSetAction(rs1) // scale replicaset f.run(getKey(r1, t)) createdRS1 := f.getCreatedReplicaSet(idx) expectedLabels := map[string]string{ @@ -209,6 +211,7 @@ func TestSyncBlueGreenEphemeralMetadataSecondRevision(t *testing.T) { f.expectUpdateRolloutStatusAction(r2) // Update Rollout conditions rs2idx := f.expectCreateReplicaSetAction(rs2) // Create revision 2 ReplicaSet f.expectPatchServiceAction(previewSvc, rs2PodHash) // Update preview service to point at revision 2 replicaset + f.expectUpdateReplicaSetAction(rs2) // scale revision 2 ReplicaSet up f.expectListPodAction(r1.Namespace) // list pods to patch ephemeral data on revision 1 ReplicaSets pods` podIdx := f.expectUpdatePodAction(&pod) // Update pod with ephemeral data rs1idx := f.expectUpdateReplicaSetAction(rs1) // update stable replicaset with stable metadata diff --git a/rollout/experiment_test.go b/rollout/experiment_test.go index 32159734fb..18277d3640 100644 --- a/rollout/experiment_test.go +++ b/rollout/experiment_test.go @@ -519,6 +519,7 @@ func TestRolloutDoNotCreateExperimentWithoutStableRS(t *testing.T) { f.expectCreateReplicaSetAction(rs2) f.expectUpdateRolloutAction(r2) // update revision f.expectUpdateRolloutStatusAction(r2) // update progressing condition + f.expectUpdateReplicaSetAction(rs2) // scale replicaset f.expectPatchRolloutAction(r1) f.run(getKey(r2, t)) } diff --git a/rollout/sync.go b/rollout/sync.go index f93ea2700a..fe9e5854e2 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -159,13 +159,7 @@ func (c *rolloutContext) createDesiredReplicaSet() (*appsv1.ReplicaSet, error) { Template: newRSTemplate, }, } - allRSs := append(c.allRSs, newRS) - newReplicasCount, err := replicasetutil.NewRSNewReplicas(c.rollout, allRSs, newRS) - if err != nil { - return nil, err - } - - newRS.Spec.Replicas = pointer.Int32Ptr(newReplicasCount) + newRS.Spec.Replicas = pointer.Int32Ptr(0) // Set new replica set's annotation annotations.SetNewReplicaSetAnnotations(c.rollout, newRS, newRevision, false) @@ -250,12 +244,10 @@ func (c *rolloutContext) createDesiredReplicaSet() (*appsv1.ReplicaSet, error) { return nil, err } - if !alreadyExists && newReplicasCount > 0 { + if !alreadyExists { revision, _ := replicasetutil.Revision(createdRS) - c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: conditions.NewReplicaSetReason}, conditions.NewReplicaSetDetailedMessage, createdRS.Name, revision, newReplicasCount) - } + c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: conditions.NewReplicaSetReason}, conditions.NewReplicaSetDetailedMessage, createdRS.Name, revision) - if !alreadyExists { msg := fmt.Sprintf(conditions.NewReplicaSetMessage, createdRS.Name) condition := conditions.NewRolloutCondition(v1alpha1.RolloutProgressing, corev1.ConditionTrue, conditions.NewReplicaSetReason, msg) conditions.SetRolloutCondition(&c.rollout.Status, *condition) diff --git a/rollout/sync_test.go b/rollout/sync_test.go index b88a6ffc13..3a85a5414e 100644 --- a/rollout/sync_test.go +++ b/rollout/sync_test.go @@ -256,14 +256,17 @@ func TestCanaryPromoteFull(t *testing.T) { f.kubeobjects = append(f.kubeobjects, rs1) f.replicaSetLister = append(f.replicaSetLister, rs1) - createdRS2Index := f.expectCreateReplicaSetAction(rs2) // create new ReplicaSet (surge to 10) + createdRS2Index := f.expectCreateReplicaSetAction(rs2) // create new ReplicaSet (size 0) f.expectUpdateRolloutAction(r2) // update rollout revision f.expectUpdateRolloutStatusAction(r2) // update rollout conditions + updatedRS2Index := f.expectUpdateReplicaSetAction(rs2) // scale new ReplicaSet to 10 patchedRolloutIndex := f.expectPatchRolloutAction(r2) f.run(getKey(r2, t)) createdRS2 := f.getCreatedReplicaSet(createdRS2Index) - assert.Equal(t, int32(10), *createdRS2.Spec.Replicas) // verify we ignored steps + assert.Equal(t, int32(0), *createdRS2.Spec.Replicas) + updatedRS2 := f.getUpdatedReplicaSet(updatedRS2Index) + assert.Equal(t, int32(10), *updatedRS2.Spec.Replicas) // verify we ignored steps and fully scaled it patchedRollout := f.getPatchedRolloutAsObject(patchedRolloutIndex) assert.Equal(t, int32(2), *patchedRollout.Status.CurrentStepIndex) // verify we updated to last step diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 0cd740089b..8aec24e40c 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -90,10 +90,12 @@ spec: ExpectRevisionPodCount("2", 1). ExpectRolloutEvents([]string{ "RolloutUpdated", // Rollout updated to revision 1 - "NewReplicaSetCreated", // Created ReplicaSet abort-retry-promote-698fbfb9dc (revision 1) with size 1 + "NewReplicaSetCreated", // Created ReplicaSet abort-retry-promote-698fbfb9dc (revision 1) + "ScalingReplicaSet", // Scaled up ReplicaSet abort-retry-promote-698fbfb9dc (revision 1) from 0 to 1 "RolloutCompleted", // Rollout completed update to revision 1 (698fbfb9dc): Initial deploy "RolloutUpdated", // Rollout updated to revision 2 - "NewReplicaSetCreated", // Created ReplicaSet abort-retry-promote-75dcb5ddd6 (revision 2) with size 1 + "NewReplicaSetCreated", // Created ReplicaSet abort-retry-promote-75dcb5ddd6 (revision 2) + "ScalingReplicaSet", // Scaled up ReplicaSet abort-retry-promote-75dcb5ddd6 (revision 2) from 0 to 1 "RolloutStepCompleted", // Rollout step 1/2 completed (setWeight: 50) "RolloutPaused", // Rollout is paused (CanaryPauseStep) "ScalingReplicaSet", // Scaled down ReplicaSet abort-retry-promote-75dcb5ddd6 (revision 2) from 1 to 0 @@ -696,11 +698,13 @@ func (s *FunctionalSuite) TestBlueGreenUpdate() { ExpectReplicaCounts(3, 6, 3, 3, 3). ExpectRolloutEvents([]string{ "RolloutUpdated", // Rollout updated to revision 1 - "NewReplicaSetCreated", // Created ReplicaSet bluegreen-7dcd8f8869 (revision 1) with size 3 + "NewReplicaSetCreated", // Created ReplicaSet bluegreen-7dcd8f8869 (revision 1) + "ScalingReplicaSet", // Scaled up ReplicaSet bluegreen-7dcd8f8869 (revision 1) from 0 to 3 "RolloutCompleted", // Rollout completed update to revision 1 (7dcd8f8869): Initial deploy "SwitchService", // Switched selector for service 'bluegreen' from '' to '7dcd8f8869' "RolloutUpdated", // Rollout updated to revision 2 - "NewReplicaSetCreated", // Created ReplicaSet bluegreen-5498785cd6 (revision 2) with size 3 + "NewReplicaSetCreated", // Created ReplicaSet bluegreen-5498785cd6 (revision 2) + "ScalingReplicaSet", // Scaled up ReplicaSet bluegreen-5498785cd6 (revision 2) from 0 to 3 "SwitchService", // Switched selector for service 'bluegreen' from '7dcd8f8869' to '6c779b88b6' "RolloutCompleted", // Rollout completed update to revision 2 (6c779b88b6): Completed blue-green update }) diff --git a/utils/conditions/conditions.go b/utils/conditions/conditions.go index c65d8f4734..5826db3f89 100644 --- a/utils/conditions/conditions.go +++ b/utils/conditions/conditions.go @@ -52,7 +52,7 @@ const ( //NewReplicaSetMessage is added in a rollout when it creates a new replicas set. NewReplicaSetMessage = "Created new replica set %q" // NewReplicaSetDetailedMessage is a more detailed format message - NewReplicaSetDetailedMessage = "Created ReplicaSet %s (revision %d) with size %d" + NewReplicaSetDetailedMessage = "Created ReplicaSet %s (revision %d)" // FoundNewRSReason is added in a rollout when it adopts an existing replica set. FoundNewRSReason = "FoundNewReplicaSet" From 58994c97f53b957aa469447f00690a7a7be2d289 Mon Sep 17 00:00:00 2001 From: Kareena Hirani Date: Wed, 25 Aug 2021 12:41:21 -0700 Subject: [PATCH 11/90] fix: Analysis argument validation (#1412) * fix: Analysis argument validation Signed-off-by: khhirani --- analysis/analysis.go | 81 +++++++++++++------ analysis/analysis_test.go | 64 +++++++-------- test/e2e/analysis_test.go | 60 +++++++++++++- .../analysistemplate-web-background.yaml | 5 +- .../rollout-bg-analysis-withArgs.yaml | 74 +++++++++++++++++ .../functional/rollout-secret-withArgs.yaml | 78 ++++++++++++++++++ test/e2e/functional/rollout-secret.yaml | 13 ++- 7 files changed, 315 insertions(+), 60 deletions(-) create mode 100644 test/e2e/functional/rollout-bg-analysis-withArgs.yaml create mode 100644 test/e2e/functional/rollout-secret-withArgs.yaml diff --git a/analysis/analysis.go b/analysis/analysis.go index ab2d6b9741..73aadb5eca 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -7,6 +7,8 @@ import ( "sync" "time" + "k8s.io/utils/pointer" + log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -43,20 +45,31 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph if run.Status.MetricResults == nil { run.Status.MetricResults = make([]v1alpha1.MetricResult, 0) - err := analysisutil.ValidateMetrics(run.Spec.Metrics) - if err != nil { - message := fmt.Sprintf("analysis spec invalid: %v", err) - log.Warn(message) - run.Status.Phase = v1alpha1.AnalysisPhaseError - run.Status.Message = message - c.recordAnalysisRunCompletionEvent(run) - return run - } } - tasks := generateMetricTasks(run) + resolvedMetrics, err := getResolvedMetricsWithoutSecrets(run.Spec.Metrics, run.Spec.Args) + if err != nil { + message := fmt.Sprintf("unable to resolve metric arguments: %v", err) + log.Warn(message) + run.Status.Phase = v1alpha1.AnalysisPhaseError + run.Status.Message = message + c.recordAnalysisRunCompletionEvent(run) + return run + } + + err = analysisutil.ValidateMetrics(resolvedMetrics) + if err != nil { + message := fmt.Sprintf("analysis spec invalid: %v", err) + log.Warn(message) + run.Status.Phase = v1alpha1.AnalysisPhaseError + run.Status.Message = message + c.recordAnalysisRunCompletionEvent(run) + return run + } + + tasks := generateMetricTasks(run, resolvedMetrics) log.Infof("taking %d measurements", len(tasks)) - err := c.runMeasurements(run, tasks) + err = c.runMeasurements(run, tasks) if err != nil { message := fmt.Sprintf("unable to resolve metric arguments: %v", err) log.Warn(message) @@ -66,7 +79,7 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph return run } - newStatus, newMessage := c.assessRunStatus(run) + newStatus, newMessage := c.assessRunStatus(run, resolvedMetrics) if newStatus != run.Status.Phase { run.Status.Phase = newStatus run.Status.Message = newMessage @@ -81,7 +94,7 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph log.Warnf("Failed to garbage collect measurements: %v", err) } - nextReconcileTime := calculateNextReconcileTime(run) + nextReconcileTime := calculateNextReconcileTime(run, resolvedMetrics) if nextReconcileTime != nil { enqueueSeconds := nextReconcileTime.Sub(time.Now()) if enqueueSeconds < 0 { @@ -93,6 +106,27 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph return run } +func getResolvedMetricsWithoutSecrets(metrics []v1alpha1.Metric, args []v1alpha1.Argument) ([]v1alpha1.Metric, error) { + newArgs := make([]v1alpha1.Argument, 0) + for _, arg := range args { + newArg := arg.DeepCopy() + if newArg.ValueFrom != nil && newArg.ValueFrom.SecretKeyRef != nil { + newArg.ValueFrom = nil + newArg.Value = pointer.StringPtr("temp-for-secret") + } + newArgs = append(newArgs, *newArg) + } + resolvedMetrics := make([]v1alpha1.Metric, 0) + for _, metric := range metrics { + resolvedMetric, err := analysisutil.ResolveMetricArgs(metric, newArgs) + if err != nil { + return nil, err + } + resolvedMetrics = append(resolvedMetrics, *resolvedMetric) + } + return resolvedMetrics, nil +} + func (c *Controller) recordAnalysisRunCompletionEvent(run *v1alpha1.AnalysisRun) { eventType := corev1.EventTypeNormal switch run.Status.Phase { @@ -106,11 +140,12 @@ func (c *Controller) recordAnalysisRunCompletionEvent(run *v1alpha1.AnalysisRun) // sync, based on the last completion times that metric was measured (if ever). If the run is // terminating (e.g. due to manual termination or failing metric), will not schedule further // measurements other than to resume any in-flight measurements. -func generateMetricTasks(run *v1alpha1.AnalysisRun) []metricTask { +func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) []metricTask { log := logutil.WithAnalysisRun(run) var tasks []metricTask terminating := analysisutil.IsTerminating(run) - for _, metric := range run.Spec.Metrics { + + for i, metric := range metrics { if analysisutil.MetricCompleted(run, metric.Name) { continue } @@ -124,7 +159,7 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun) []metricTask { // last measurement is still in-progress. need to complete it logCtx.Infof("resuming in-progress measurement") tasks = append(tasks, metricTask{ - metric: metric, + metric: run.Spec.Metrics[i], incompleteMeasurement: lastMeasurement, }) continue @@ -149,7 +184,7 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun) []metricTask { } } // measurement never taken - tasks = append(tasks, metricTask{metric: metric}) + tasks = append(tasks, metricTask{metric: run.Spec.Metrics[i]}) logCtx.Infof("running initial measurement") continue } @@ -174,7 +209,7 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun) []metricTask { interval = metricInterval } if time.Now().After(lastMeasurement.FinishedAt.Add(interval)) { - tasks = append(tasks, metricTask{metric: metric}) + tasks = append(tasks, metricTask{metric: run.Spec.Metrics[i]}) logCtx.Infof("running overdue measurement") continue } @@ -238,7 +273,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa var resultsLock sync.Mutex terminating := analysisutil.IsTerminating(run) - // resolve args for metricTasks + // resolve args for metric tasks // get list of secret values for log redaction tasks, secrets, err := c.resolveArgs(tasks, run.Spec.Args, run.Namespace) if err != nil { @@ -345,7 +380,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa // assessRunStatus assesses the overall status of this AnalysisRun // If any metric is not yet completed, the AnalysisRun is still considered Running // Once all metrics are complete, the worst status is used as the overall AnalysisRun status -func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun) (v1alpha1.AnalysisPhase, string) { +func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) (v1alpha1.AnalysisPhase, string) { var worstStatus v1alpha1.AnalysisPhase var worstMessage string terminating := analysisutil.IsTerminating(run) @@ -360,7 +395,7 @@ func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun) (v1alpha1.Analys } // Iterate all metrics and update MetricResult.Phase fields based on latest measurement(s) - for _, metric := range run.Spec.Metrics { + for _, metric := range metrics { if result := analysisutil.GetResult(run, metric.Name); result != nil { log := logutil.WithAnalysisRun(run).WithField("metric", metric.Name) metricStatus := assessMetricStatus(metric, *result, terminating) @@ -497,9 +532,9 @@ func assessMetricFailureInconclusiveOrError(metric v1alpha1.Metric, result v1alp // calculateNextReconcileTime calculates the next time that this AnalysisRun should be reconciled, // based on the earliest time of all metrics intervals, counts, and their finishedAt timestamps -func calculateNextReconcileTime(run *v1alpha1.AnalysisRun) *time.Time { +func calculateNextReconcileTime(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) *time.Time { var reconcileTime *time.Time - for _, metric := range run.Spec.Metrics { + for _, metric := range metrics { if analysisutil.MetricCompleted(run, metric.Name) { // NOTE: this also covers the case where metric.Count is reached continue diff --git a/analysis/analysis_test.go b/analysis/analysis_test.go index c901984e35..5b1fa56062 100644 --- a/analysis/analysis_test.go +++ b/analysis/analysis_test.go @@ -173,7 +173,7 @@ func TestGenerateMetricTasksInterval(t *testing.T) { } { // ensure we don't take measurements when within the interval - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 0, len(tasks)) } { @@ -182,7 +182,7 @@ func TestGenerateMetricTasksInterval(t *testing.T) { successRate.Measurements[0].StartedAt = timePtr(metav1.NewTime(time.Now().Add(-61 * time.Second))) successRate.Measurements[0].FinishedAt = timePtr(metav1.NewTime(time.Now().Add(-61 * time.Second))) run.Status.MetricResults[0] = successRate - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 1, len(tasks)) } } @@ -208,11 +208,11 @@ func TestGenerateMetricTasksFailing(t *testing.T) { }, } // ensure we don't perform more measurements when one result already failed - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 0, len(tasks)) run.Status.MetricResults = nil // ensure we schedule tasks when no results are failed - tasks = generateMetricTasks(run) + tasks = generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 2, len(tasks)) } @@ -239,7 +239,7 @@ func TestGenerateMetricTasksNoIntervalOrCount(t *testing.T) { } { // ensure we don't take measurement when result count indicates we completed - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 0, len(tasks)) } { @@ -248,7 +248,7 @@ func TestGenerateMetricTasksNoIntervalOrCount(t *testing.T) { successRate.Measurements = nil successRate.Count = 0 run.Status.MetricResults[0] = successRate - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 1, len(tasks)) } } @@ -275,7 +275,7 @@ func TestGenerateMetricTasksIncomplete(t *testing.T) { } { // ensure we don't take measurement when interval is not specified and we already took measurement - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 1, len(tasks)) assert.NotNil(t, tasks[0].incompleteMeasurement) } @@ -300,25 +300,25 @@ func TestGenerateMetricTasksHonorInitialDelay(t *testing.T) { } { // ensure we don't take measurement for metrics with start delays when no startAt is set - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 0, len(tasks)) } { run.Status.StartedAt = &nowMinus10 // ensure we don't take measurement for metrics with start delays where we haven't waited the start delay - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 0, len(tasks)) } { run.Status.StartedAt = &nowMinus20 // ensure we do take measurement for metrics with start delays where we have waited the start delay - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 1, len(tasks)) } { run.Spec.Metrics[0].InitialDelay = "invalid-start-delay" // ensure we don't take measurement for metrics with invalid start delays - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 0, len(tasks)) } } @@ -366,7 +366,7 @@ func TestGenerateMetricTasksHonorResumeAt(t *testing.T) { } { // ensure we don't take measurement when resumeAt has not passed - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 1, len(tasks)) assert.Equal(t, "success-rate2", tasks[0].metric.Name) } @@ -397,13 +397,13 @@ func TestGenerateMetricTasksError(t *testing.T) { } { run := run.DeepCopy() - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 1, len(tasks)) } { run := run.DeepCopy() run.Spec.Metrics[0].Interval = "5m" - tasks := generateMetricTasks(run) + tasks := generateMetricTasks(run, run.Spec.Metrics) assert.Equal(t, 1, len(tasks)) } } @@ -439,7 +439,7 @@ func TestAssessRunStatus(t *testing.T) { }, }, } - status, message := c.assessRunStatus(run) + status, message := c.assessRunStatus(run, run.Spec.Metrics) assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) } @@ -458,7 +458,7 @@ func TestAssessRunStatus(t *testing.T) { }, }, } - status, message := c.assessRunStatus(run) + status, message := c.assessRunStatus(run, run.Spec.Metrics) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, status) assert.Equal(t, "", message) } @@ -512,7 +512,7 @@ func TestAssessRunStatusUpdateResult(t *testing.T) { }, }, } - status, message := c.assessRunStatus(run) + status, message := c.assessRunStatus(run, run.Spec.Metrics) assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, run.Status.MetricResults[1].Phase) @@ -671,11 +671,11 @@ func TestCalculateNextReconcileTimeInterval(t *testing.T) { }, } // ensure we requeue at correct interval - assert.Equal(t, now.Add(time.Second*30), *calculateNextReconcileTime(run)) + assert.Equal(t, now.Add(time.Second*30), *calculateNextReconcileTime(run, run.Spec.Metrics)) // when in-flight is not set, we do not requeue run.Status.MetricResults[0].Measurements[0].FinishedAt = nil run.Status.MetricResults[0].Measurements[0].Phase = v1alpha1.AnalysisPhaseRunning - assert.Nil(t, calculateNextReconcileTime(run)) + assert.Nil(t, calculateNextReconcileTime(run, run.Spec.Metrics)) // do not queue completed metrics nowMinus120 := metav1.NewTime(now.Add(time.Second * -120)) run.Status.MetricResults[0] = v1alpha1.MetricResult{ @@ -687,7 +687,7 @@ func TestCalculateNextReconcileTimeInterval(t *testing.T) { FinishedAt: &nowMinus120, }}, } - assert.Nil(t, calculateNextReconcileTime(run)) + assert.Nil(t, calculateNextReconcileTime(run, run.Spec.Metrics)) } func TestCalculateNextReconcileTimeInitialDelay(t *testing.T) { @@ -723,10 +723,10 @@ func TestCalculateNextReconcileTimeInitialDelay(t *testing.T) { }, } // ensure we requeue after start delay - assert.Equal(t, now.Add(time.Second*10), *calculateNextReconcileTime(run)) + assert.Equal(t, now.Add(time.Second*10), *calculateNextReconcileTime(run, run.Spec.Metrics)) run.Spec.Metrics[1].InitialDelay = "not-valid-start-delay" // skip invalid start delay and use the other metrics next reconcile time - assert.Equal(t, now.Add(time.Second*30), *calculateNextReconcileTime(run)) + assert.Equal(t, now.Add(time.Second*30), *calculateNextReconcileTime(run, run.Spec.Metrics)) } @@ -754,7 +754,7 @@ func TestCalculateNextReconcileTimeNoInterval(t *testing.T) { }}, }, } - assert.Nil(t, calculateNextReconcileTime(run)) + assert.Nil(t, calculateNextReconcileTime(run, run.Spec.Metrics)) } func TestCalculateNextReconcileEarliestMetric(t *testing.T) { @@ -801,7 +801,7 @@ func TestCalculateNextReconcileEarliestMetric(t *testing.T) { }, } // ensure we requeue at correct interval - assert.Equal(t, now.Add(time.Second*10), *calculateNextReconcileTime(run)) + assert.Equal(t, now.Add(time.Second*10), *calculateNextReconcileTime(run, run.Spec.Metrics)) } func TestCalculateNextReconcileHonorResumeAt(t *testing.T) { @@ -830,7 +830,7 @@ func TestCalculateNextReconcileHonorResumeAt(t *testing.T) { }, } // ensure we requeue at correct interval - assert.Equal(t, now.Add(time.Second*10), *calculateNextReconcileTime(run)) + assert.Equal(t, now.Add(time.Second*10), *calculateNextReconcileTime(run, run.Spec.Metrics)) } // TestCalculateNextReconcileUponError ensure we requeue at error interval when we error @@ -860,12 +860,12 @@ func TestCalculateNextReconcileUponError(t *testing.T) { } { run := run.DeepCopy() - assert.Equal(t, now.Add(DefaultErrorRetryInterval), *calculateNextReconcileTime(run)) + assert.Equal(t, now.Add(DefaultErrorRetryInterval), *calculateNextReconcileTime(run, run.Spec.Metrics)) } { run := run.DeepCopy() run.Spec.Metrics[0].Interval = "5m" - assert.Equal(t, now.Add(DefaultErrorRetryInterval), *calculateNextReconcileTime(run)) + assert.Equal(t, now.Add(DefaultErrorRetryInterval), *calculateNextReconcileTime(run, run.Spec.Metrics)) } } @@ -1083,8 +1083,8 @@ func TestResolveMetricArgsUnableToSubstitute(t *testing.T) { }, } newRun := c.reconcileAnalysisRun(run) - assert.Equal(t, newRun.Status.Phase, v1alpha1.AnalysisPhaseError) - assert.Equal(t, newRun.Status.Message, "unable to resolve metric arguments: failed to resolve {{args.metric-name}}") + assert.Equal(t, v1alpha1.AnalysisPhaseError, newRun.Status.Phase) + assert.Equal(t, "unable to resolve metric arguments: failed to resolve {{args.metric-name}}", newRun.Status.Message) } // TestSecretContentReferenceSuccess verifies that secret arguments are properly resolved @@ -1403,7 +1403,7 @@ func TestAssessRunStatusErrorMessageAnalysisPhaseFail(t *testing.T) { run := newTerminatingRun(v1alpha1.AnalysisPhaseFailed) run.Status.MetricResults[0].Phase = v1alpha1.AnalysisPhaseSuccessful - status, message := c.assessRunStatus(run) + status, message := c.assessRunStatus(run, run.Spec.Metrics) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, status) assert.Equal(t, "metric \"failed-metric\" assessed Failed due to failed (1) > failureLimit (0)", message) } @@ -1421,7 +1421,7 @@ func TestAssessRunStatusErrorMessageFromProvider(t *testing.T) { providerMessage := "Provider error" run.Status.MetricResults[1].Message = providerMessage - status, message := c.assessRunStatus(run) + status, message := c.assessRunStatus(run, run.Spec.Metrics) expectedMessage := fmt.Sprintf("metric \"failed-metric\" assessed Failed due to failed (1) > failureLimit (0): \"Error Message: %s\"", providerMessage) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, status) assert.Equal(t, expectedMessage, message) @@ -1438,7 +1438,7 @@ func TestAssessRunStatusMultipleFailures(t *testing.T) { run.Status.MetricResults[0].Phase = v1alpha1.AnalysisPhaseFailed run.Status.MetricResults[0].Failed = 1 - status, message := c.assessRunStatus(run) + status, message := c.assessRunStatus(run, run.Spec.Metrics) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, status) assert.Equal(t, "metric \"run-forever\" assessed Failed due to failed (1) > failureLimit (0)", message) } diff --git a/test/e2e/analysis_test.go b/test/e2e/analysis_test.go index 23adfe4de3..8eb4f44585 100644 --- a/test/e2e/analysis_test.go +++ b/test/e2e/analysis_test.go @@ -4,10 +4,12 @@ package e2e import ( "fmt" + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "testing" "time" "github.com/stretchr/testify/suite" + "github.com/tj/assert" "github.com/argoproj/argo-rollouts/test/fixtures" ) @@ -623,7 +625,7 @@ spec: } func (s *AnalysisSuite) TestAnalysisWithSecret() { - (s.Given(). + s.Given(). RolloutObjects("@functional/rollout-secret.yaml"). When(). ApplyManifests(). @@ -634,11 +636,63 @@ func (s *AnalysisSuite) TestAnalysisWithSecret() { UpdateSpec(). WaitForRolloutStatus("Paused"). Then(). - ExpectAnalysisRunCount(1). + Assert(func(t *fixtures.Then) { + ar := t.GetRolloutAnalysisRuns().Items[0] + assert.Equal(s.T(), v1alpha1.AnalysisPhaseSuccessful, ar.Status.Phase) + metricResult := ar.Status.MetricResults[0] + assert.Equal(s.T(), int32(2), metricResult.Count) + }). When(). WaitForInlineAnalysisRunPhase("Successful"). PromoteRollout(). WaitForRolloutStatus("Healthy"). Then(). - ExpectStableRevision("2")) + ExpectStableRevision("2") } + + +func (s *AnalysisSuite) TestAnalysisWithArgs() { + s.Given(). + RolloutObjects("@functional/rollout-secret-withArgs.yaml"). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + Then(). + ExpectAnalysisRunCount(0). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Then(). + Assert(func(t *fixtures.Then) { + ar := t.GetRolloutAnalysisRuns().Items[0] + assert.Equal(s.T(), v1alpha1.AnalysisPhaseSuccessful, ar.Status.Phase) + metricResult := ar.Status.MetricResults[0] + assert.Equal(s.T(), int32(3), metricResult.Count) + }). + When(). + WaitForInlineAnalysisRunPhase("Successful"). + PromoteRollout(). + WaitForRolloutStatus("Healthy"). + Then(). + ExpectStableRevision("2") +} + +func (s *AnalysisSuite) TestBackgroundAnalysisWithArgs() { + s.Given(). + RolloutObjects("@functional/rollout-bg-analysis-withArgs.yaml"). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + Then(). + ExpectAnalysisRunCount(0). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Then(). + ExpectAnalysisRunCount(1). + ExpectBackgroundAnalysisRunPhase("Running"). + When(). + PromoteRollout(). + WaitForRolloutStatus("Healthy"). + WaitForBackgroundAnalysisRunPhase("Successful") +} \ No newline at end of file diff --git a/test/e2e/functional/analysistemplate-web-background.yaml b/test/e2e/functional/analysistemplate-web-background.yaml index f76a96f801..8f4fa90571 100644 --- a/test/e2e/functional/analysistemplate-web-background.yaml +++ b/test/e2e/functional/analysistemplate-web-background.yaml @@ -4,11 +4,14 @@ kind: AnalysisTemplate metadata: name: web-background spec: + args: + - name: url-val + value: "https://kubernetes.default.svc/version" metrics: - name: web interval: 5s successCondition: result.major == '1' provider: web: - url: https://kubernetes.default.svc/version + url: "{{args.url-val}}" insecure: true diff --git a/test/e2e/functional/rollout-bg-analysis-withArgs.yaml b/test/e2e/functional/rollout-bg-analysis-withArgs.yaml new file mode 100644 index 0000000000..5cd2f5ba65 --- /dev/null +++ b/test/e2e/functional/rollout-bg-analysis-withArgs.yaml @@ -0,0 +1,74 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-bg-analysis +spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-bg-analysis + template: + metadata: + labels: + app: rollout-bg-analysis + spec: + containers: + - name: rollouts-demo + image: nginx:1.19-alpine + imagePullPolicy: Always + ports: + - containerPort: 8080 + strategy: + canary: + analysis: + templates: + - templateName: analysis-secret + startingStep: 1 + args: + - name: failure-limit + value: "2" + - name: analysis-interval + value: "10s" + - name: inconclusive-limit + value: "2" + - name: success-condition + value: "It worked!" + steps: + - setWeight: 25 + - pause: {} +--- +apiVersion: v1 +kind: Secret +metadata: + name: example-secret +type: Opaque +data: + secretUrl: aHR0cHM6Ly9naXN0LmdpdGh1YnVzZXJjb250ZW50LmNvbS9raGhpcmFuaS8yYWIxMTIzMjQwMjUxOGQ1Mjc3YWYwMzBkZDg5MTZkNy9yYXcvZDI3MmY1NTFmMmQxODA2YTAzOTc0ZGJhZWYxMWRmZDU1MTAyZmVlYS9leGFtcGxlLmpzb24= +--- +kind: AnalysisTemplate +apiVersion: argoproj.io/v1alpha1 +metadata: + name: analysis-secret +spec: + args: + - name: analysis-interval + - name: failure-limit + - name: inconclusive-limit + - name: success-condition + value: "replace" + - name: secret-url + valueFrom: + secretKeyRef: + name: example-secret + key: secretUrl + metrics: + - name: webmetric + interval: "{{args.analysis-interval}}" + initialDelay: "{{args.analysis-interval}}" + failureLimit: "{{args.failure-limit}}" + successCondition: result == "{{args.success-condition}}" + provider: + web: + url: "{{args.secret-url}}" + jsonPath: "{$.message}" diff --git a/test/e2e/functional/rollout-secret-withArgs.yaml b/test/e2e/functional/rollout-secret-withArgs.yaml new file mode 100644 index 0000000000..16da5da049 --- /dev/null +++ b/test/e2e/functional/rollout-secret-withArgs.yaml @@ -0,0 +1,78 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-secret +spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-secret + template: + metadata: + labels: + app: rollout-secret + spec: + containers: + - name: rollouts-demo + image: nginx:1.19-alpine + imagePullPolicy: Always + ports: + - containerPort: 8080 + strategy: + canary: + steps: + - setWeight: 25 + - analysis: + templates: + - templateName: analysis-secret-args + args: + - name: failure-limit + value: "2" + - name: analysis-interval + value: "5s" + - name: analysis-runs + value: "3" + - name: inconclusive-limit + value: "2" + - name: success-condition + value: "It worked!" + - pause: {} +--- +apiVersion: v1 +kind: Secret +metadata: + name: example-secret +type: Opaque +data: + secretUrl: aHR0cHM6Ly9naXN0LmdpdGh1YnVzZXJjb250ZW50LmNvbS9raGhpcmFuaS8yYWIxMTIzMjQwMjUxOGQ1Mjc3YWYwMzBkZDg5MTZkNy9yYXcvZDI3MmY1NTFmMmQxODA2YTAzOTc0ZGJhZWYxMWRmZDU1MTAyZmVlYS9leGFtcGxlLmpzb24= +--- +kind: AnalysisTemplate +apiVersion: argoproj.io/v1alpha1 +metadata: + name: analysis-secret-args +spec: + args: + - name: analysis-interval + value: "100s" + - name: analysis-runs + value: "10" + - name: failure-limit + - name: inconclusive-limit + - name: success-condition + - name: secret-url + valueFrom: + secretKeyRef: + name: example-secret + key: secretUrl + metrics: + - name: webmetric + count: "{{args.analysis-runs}}" + interval: "{{args.analysis-interval}}" + initialDelay: "{{args.analysis-interval}}" + failureLimit: "{{args.failure-limit}}" + successCondition: result == "{{args.success-condition}}" + provider: + web: + url: "{{args.secret-url}}" + jsonPath: "{$.message}" diff --git a/test/e2e/functional/rollout-secret.yaml b/test/e2e/functional/rollout-secret.yaml index 42db8000f2..b584f9f90e 100644 --- a/test/e2e/functional/rollout-secret.yaml +++ b/test/e2e/functional/rollout-secret.yaml @@ -15,7 +15,7 @@ spec: spec: containers: - name: rollouts-demo - image: argoproj/rollouts-demo:blue + image: nginx:1.19-alpine imagePullPolicy: Always ports: - containerPort: 8080 @@ -42,6 +42,14 @@ metadata: name: analysis-secret spec: args: + - name: analysis-interval + value: "5s" + - name: analysis-runs + value: "2" + - name: failure-limit + value: "1" + - name: inconclusive-limit + value: "1" - name: secret-url valueFrom: secretKeyRef: @@ -49,6 +57,9 @@ spec: key: secretUrl metrics: - name: webmetric + count: "{{args.analysis-runs}}" + interval: "{{args.analysis-interval}}" + failureLimit: "{{args.failure-limit}}" successCondition: result == 'It worked!' provider: web: From 980a56d3e6e1d5f79a513af2e1dc412463d2fd32 Mon Sep 17 00:00:00 2001 From: Kareena Hirani Date: Wed, 25 Aug 2021 13:34:24 -0700 Subject: [PATCH 12/90] fix: Nginx ingressClassName passed to canary ingress (#1448) * fix: nginx ingressClassName passed to canary ingress Signed-off-by: khhirani --- rollout/trafficrouting/nginx/nginx.go | 5 +++++ rollout/trafficrouting/nginx/nginx_test.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/rollout/trafficrouting/nginx/nginx.go b/rollout/trafficrouting/nginx/nginx.go index ed9e95ac2b..85e49a421c 100644 --- a/rollout/trafficrouting/nginx/nginx.go +++ b/rollout/trafficrouting/nginx/nginx.go @@ -72,6 +72,11 @@ func (r *Reconciler) canaryIngress(stableIngress *extensionsv1beta1.Ingress, nam }, } + // Preserve ingressClassName from stable ingress + if stableIngress.Spec.IngressClassName != nil { + desiredCanaryIngress.Spec.IngressClassName = stableIngress.Spec.IngressClassName + } + // Must preserve ingress.class on canary ingress, no other annotations matter // See: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary if val, ok := stableIngress.Annotations["kubernetes.io/ingress.class"]; ok { diff --git a/rollout/trafficrouting/nginx/nginx_test.go b/rollout/trafficrouting/nginx/nginx_test.go index a747e34835..04349bba42 100644 --- a/rollout/trafficrouting/nginx/nginx_test.go +++ b/rollout/trafficrouting/nginx/nginx_test.go @@ -4,6 +4,8 @@ import ( "fmt" "testing" + "k8s.io/utils/pointer" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" @@ -94,6 +96,7 @@ func TestCanaryIngressCreate(t *testing.T) { }, } stableIngress := ingress("stable-ingress", 80, "stable-service") + stableIngress.Spec.IngressClassName = pointer.StringPtr("nginx-ext") desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 10) assert.Nil(t, err, "No error returned when calling canaryIngress") @@ -101,6 +104,8 @@ func TestCanaryIngressCreate(t *testing.T) { checkBackendService(t, desiredCanaryIngress, "canary-service") assert.Equal(t, "true", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") assert.Equal(t, "10", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.NotNil(t, desiredCanaryIngress.Spec.IngressClassName) + assert.Equal(t, "nginx-ext", *desiredCanaryIngress.Spec.IngressClassName) } func TestCanaryIngressPatchWeight(t *testing.T) { From 5b332f6bb76f6399bbc26067caa9a28c59f2bade Mon Sep 17 00:00:00 2001 From: harikrongali <81331774+harikrongali@users.noreply.github.com> Date: Wed, 25 Aug 2021 22:17:19 -0700 Subject: [PATCH 13/90] fix: replica count for new deployment (#1449) fix: replica count for new deployment (#1449) Signed-off-by: hari rongali --- utils/replicaset/canary.go | 3 +-- utils/replicaset/canary_test.go | 9 +++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index d73c9f5e19..d8ad236e08 100644 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -187,12 +187,11 @@ func CalculateReplicaCountsForCanary(rollout *v1alpha1.Rollout, newRS *appsv1.Re } scaleDownCount := replicasToScaleDown - minAvailableReplicaCount - if !isIncreasing { // Skip scalingDown Stable replicaSet when Canary availability is not taken into calculation for scaleDown newRSReplicaCount = calculateScaleDownReplicaCount(newRS, desiredNewRSReplicaCount, scaleDownCount, newRSReplicaCount) newRSReplicaCount, stableRSReplicaCount = adjustReplicaWithinLimits(newRS, stableRS, newRSReplicaCount, stableRSReplicaCount, maxReplicaCountAllowed, minAvailableReplicaCount) - } else { + } else if scaleStableRS { // Skip scalingDown canary replicaSet when StableSet availability is not taken into calculation for scaleDown stableRSReplicaCount = calculateScaleDownReplicaCount(stableRS, desiredStableRSReplicaCount, scaleDownCount, stableRSReplicaCount) stableRSReplicaCount, newRSReplicaCount = adjustReplicaWithinLimits(stableRS, newRS, stableRSReplicaCount, newRSReplicaCount, maxReplicaCountAllowed, minAvailableReplicaCount) diff --git a/utils/replicaset/canary_test.go b/utils/replicaset/canary_test.go index c82ba28836..1c5f046fb5 100644 --- a/utils/replicaset/canary_test.go +++ b/utils/replicaset/canary_test.go @@ -602,6 +602,15 @@ func TestCalculateReplicaCountsForCanary(t *testing.T) { } } +func TestCalculateReplicaCountsForNewDeployment(t *testing.T) { + rollout := newRollout(10, 10, intstr.FromInt(0), intstr.FromInt(1), "canary", "stable", nil, nil) + stableRS := newRS("stable", 10, 0) + newRS := newRS("stable", 10, 0) + newRSReplicaCount, stableRSReplicaCount := CalculateReplicaCountsForCanary(rollout, newRS, stableRS, nil) + assert.Equal(t, int32(10), newRSReplicaCount) + assert.Equal(t, int32(0), stableRSReplicaCount) +} + func TestCalculateReplicaCountsForCanaryTrafficRouting(t *testing.T) { rollout := newRollout(10, 10, intstr.FromInt(0), intstr.FromInt(1), "canary", "stable", nil, nil) rollout.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{} From c8dc3c910d667ce5c92610bed342e6e1ae92d6d5 Mon Sep 17 00:00:00 2001 From: ilyagorban-codefresh <75360841+ilyagorban-codefresh@users.noreply.github.com> Date: Sun, 12 Sep 2021 14:00:11 +0300 Subject: [PATCH 14/90] change configuration of sonarcloud (#1) Co-authored-by: Ilya Gorban --- sonar-project.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 448dba91da..a18737a6a9 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,5 +1,5 @@ -sonar.projectKey=argoproj_argo-rollouts -sonar.organization=argoproj +sonar.projectKey=argo-rollouts +sonar.organization=codefresh-io sonar.sources=. sonar.sourceEncoding=UTF-8 @@ -12,4 +12,4 @@ sonar.coverage.exclusions=**/*.pb.go,**/*.pb.gw.go,**/mocks/**,**/*.ts*,**/vendo sonar.go.exclusions=**/vendor/**,*/*.pb.go,**/*_test.go,**/*.pb.gw.go,**/mocks/**,**/openapi_generated.go,**/*_generated*.go # Exclude following set of patterns from duplication detection -sonar.cpd.exclusions=**/*.pb.go,**/*.g.cs,**/*.gw.go,**/mocks/* \ No newline at end of file +sonar.cpd.exclusions=**/*.pb.go,**/*.g.cs,**/*.gw.go,**/mocks/* From f142bfcf8b4e5548bc81eb03de1dcb67a1e00179 Mon Sep 17 00:00:00 2001 From: ilyagorban-codefresh <75360841+ilyagorban-codefresh@users.noreply.github.com> Date: Tue, 14 Sep 2021 11:48:25 +0300 Subject: [PATCH 15/90] replace argoproj for ghcr.io and quay.io (#3) Co-authored-by: Ilya Gorban --- .github/workflows/docker-publish.yml | 10 +++++----- .github/workflows/release.yaml | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 95ba2254b6..fb3fe9f360 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -36,8 +36,8 @@ jobs: uses: docker/metadata-action@v3 with: images: | - quay.io/argoproj/argo-rollouts - ghcr.io/argoproj/argo-rollouts + quay.io/codefresh/argo-rollouts + ghcr.io/codefresh-io/argo-rollouts tags: | type=ref,event=branch flavor: | @@ -48,8 +48,8 @@ jobs: uses: docker/metadata-action@v3 with: images: | - quay.io/argoproj/kubectl-argo-rollouts - ghcr.io/argoproj/kubectl-argo-rollouts + quay.io/codefresh/kubectl-argo-rollouts + ghcr.io/codefresh-io/kubectl-argo-rollouts tags: | type=ref,event=branch flavor: | @@ -57,7 +57,7 @@ jobs: - name: Login to GitHub Container Registry if: github.event_name != 'pull_request' - uses: docker/login-action@v1 + uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d80a2b406b..93e0093a4d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -41,8 +41,8 @@ jobs: uses: docker/metadata-action@v3 with: images: | - quay.io/argoproj/argo-rollouts - ghcr.io/argoproj/argo-rollouts + quay.io/codefresh/argo-rollouts + ghcr.io/codefresh-io/argo-rollouts tags: | type=semver,pattern={{version}},prefix=v,value=${{ github.event.inputs.tag }} @@ -51,14 +51,14 @@ jobs: uses: docker/metadata-action@v3 with: images: | - quay.io/argoproj/kubectl-argo-rollouts - ghcr.io/argoproj/kubectl-argo-rollouts + quay.io/codefresh/kubectl-argo-rollouts + ghcr.io/codefresh-io/kubectl-argo-rollouts tags: | type=semver,pattern={{version}},prefix=v,value=${{ github.event.inputs.tag }} - name: Login to GitHub Container Registry if: github.event_name != 'pull_request' - uses: docker/login-action@v1 + uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} From d0e6877078d23351b4e1754ed378f4df7668541e Mon Sep 17 00:00:00 2001 From: ilyagorban-codefresh <75360841+ilyagorban-codefresh@users.noreply.github.com> Date: Tue, 14 Sep 2021 13:01:39 +0300 Subject: [PATCH 16/90] replace argoproj for ghcr.io and quay.io (#4) Co-authored-by: Ilya Gorban From d860a957b651c6de2333937df55457302b6bed13 Mon Sep 17 00:00:00 2001 From: ilyagorban-codefresh <75360841+ilyagorban-codefresh@users.noreply.github.com> Date: Sun, 26 Sep 2021 17:46:10 +0300 Subject: [PATCH 17/90] Retrigger CI pipeline (#13) * Retrigger CI pipeline * Retrigger CI pipeline * Retrigger CI pipeline * Retrigger CI pipeline Co-authored-by: Ilya Gorban From 34196f9f9ef07906c169a8aae470ed35356b33af Mon Sep 17 00:00:00 2001 From: ilyagorban-codefresh <75360841+ilyagorban-codefresh@users.noreply.github.com> Date: Sun, 26 Sep 2021 20:37:43 +0300 Subject: [PATCH 18/90] fix manifests to fetch from quay.io/codefresh/* (#14) Co-authored-by: Ilya Gorban --- manifests/base/argo-rollouts-deployment.yaml | 2 +- manifests/base/kustomization.yaml | 2 +- manifests/dashboard-install.yaml | 2 +- manifests/dashboard-install/dashboard-deployment.yaml | 2 +- manifests/dashboard-install/kustomization.yaml | 2 +- manifests/install.yaml | 2 +- manifests/namespace-install.yaml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/manifests/base/argo-rollouts-deployment.yaml b/manifests/base/argo-rollouts-deployment.yaml index 4f8dc2e7eb..17b1035283 100644 --- a/manifests/base/argo-rollouts-deployment.yaml +++ b/manifests/base/argo-rollouts-deployment.yaml @@ -18,7 +18,7 @@ spec: serviceAccountName: argo-rollouts containers: - name: argo-rollouts - image: quay.io/argoproj/argo-rollouts:latest + image: quay.io/codefresh/argo-rollouts:latest imagePullPolicy: Always ports: - containerPort: 8090 diff --git a/manifests/base/kustomization.yaml b/manifests/base/kustomization.yaml index 783d899ec8..92de98ca79 100644 --- a/manifests/base/kustomization.yaml +++ b/manifests/base/kustomization.yaml @@ -7,5 +7,5 @@ resources: - argo-rollouts-aggregate-roles.yaml - argo-rollouts-metrics-service.yaml images: -- name: quay.io/argoproj/argo-rollouts +- name: quay.io/codefresh/argo-rollouts newTag: latest diff --git a/manifests/dashboard-install.yaml b/manifests/dashboard-install.yaml index 4ecf48208e..6a0241e4b4 100644 --- a/manifests/dashboard-install.yaml +++ b/manifests/dashboard-install.yaml @@ -118,7 +118,7 @@ spec: app.kubernetes.io/name: argo-rollouts-dashboard spec: containers: - - image: quay.io/argoproj/kubectl-argo-rollouts:latest + - image: quay.io/codefresh/kubectl-argo-rollouts:latest name: argo-rollouts-dashboard ports: - containerPort: 3100 diff --git a/manifests/dashboard-install/dashboard-deployment.yaml b/manifests/dashboard-install/dashboard-deployment.yaml index 11d9224e9e..e97dd33114 100644 --- a/manifests/dashboard-install/dashboard-deployment.yaml +++ b/manifests/dashboard-install/dashboard-deployment.yaml @@ -19,6 +19,6 @@ spec: serviceAccountName: argo-rollouts-dashboard containers: - name: argo-rollouts-dashboard - image: quay.io/argoproj/kubectl-argo-rollouts + image: quay.io/codefresh/kubectl-argo-rollouts ports: - containerPort: 3100 diff --git a/manifests/dashboard-install/kustomization.yaml b/manifests/dashboard-install/kustomization.yaml index 777437c811..b981d2e14a 100644 --- a/manifests/dashboard-install/kustomization.yaml +++ b/manifests/dashboard-install/kustomization.yaml @@ -8,5 +8,5 @@ resources: - dashboard-service.yaml - dashboard-serviceaccount.yaml images: -- name: quay.io/argoproj/kubectl-argo-rollouts +- name: quay.io/codefresh/kubectl-argo-rollouts newTag: latest diff --git a/manifests/install.yaml b/manifests/install.yaml index 273a0928aa..ffaa354b03 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -12830,7 +12830,7 @@ spec: app.kubernetes.io/name: argo-rollouts spec: containers: - - image: quay.io/argoproj/argo-rollouts:latest + - image: quay.io/codefresh/argo-rollouts:latest imagePullPolicy: Always name: argo-rollouts ports: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index fd7acadcfa..577d4f0ab7 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -12831,7 +12831,7 @@ spec: containers: - args: - --namespaced - image: quay.io/argoproj/argo-rollouts:latest + image: quay.io/codefresh/argo-rollouts:latest imagePullPolicy: Always name: argo-rollouts ports: From 41ae2edba724194746a1c6996a56147be2406932 Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Wed, 10 Nov 2021 11:03:11 +0200 Subject: [PATCH 19/90] bump From de30b20e57d60d46a271152f119cb842c0400cf6 Mon Sep 17 00:00:00 2001 From: Ilya Gorban Date: Sun, 14 Nov 2021 11:18:40 +0200 Subject: [PATCH 20/90] result of `make codegen` --- pkg/apis/rollouts/v1alpha1/generated.pb.go | 835 +++++++++--------- .../rollouts/v1alpha1/openapi_generated.go | 1 - 2 files changed, 421 insertions(+), 415 deletions(-) diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 4f0148edd0..4ae2acb4ba 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -2502,409 +2502,409 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 6426 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0xc9, - 0x51, 0xf0, 0x55, 0xf7, 0xfc, 0xf4, 0x44, 0xcf, 0x6f, 0xee, 0xac, 0x77, 0x6e, 0xee, 0x76, 0xfb, - 0x5c, 0x67, 0xdd, 0xb7, 0xfe, 0xb0, 0x67, 0xed, 0xbd, 0x3b, 0x38, 0x7c, 0xd6, 0x89, 0xe9, 0x99, - 0xdd, 0xdb, 0xd9, 0x9b, 0xd9, 0x9d, 0xcd, 0x9e, 0xdd, 0xb5, 0xcf, 0x3e, 0xe3, 0x9a, 0xee, 0x9c, - 0x9e, 0xda, 0xed, 0xae, 0x6a, 0x57, 0x55, 0xcf, 0xee, 0x9c, 0x2d, 0xff, 0x60, 0xd9, 0x18, 0x64, - 0xcb, 0x06, 0xdb, 0x0f, 0x08, 0x19, 0x59, 0x88, 0x07, 0x84, 0x79, 0x40, 0x16, 0x88, 0x17, 0x23, - 0x2c, 0xc0, 0x92, 0x79, 0x00, 0x19, 0xc9, 0x70, 0x06, 0xd9, 0x8d, 0xdd, 0xe6, 0x05, 0x5e, 0x90, - 0x91, 0x11, 0xf2, 0x49, 0x48, 0x28, 0x7f, 0x2b, 0xb3, 0xba, 0x7a, 0xb6, 0x7b, 0xba, 0x66, 0xb1, - 0x80, 0xb7, 0xee, 0x8c, 0xc8, 0x88, 0xfc, 0x89, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x82, 0xcd, 0xba, - 0x1b, 0xed, 0xb7, 0x77, 0x57, 0xaa, 0x7e, 0xf3, 0x82, 0x13, 0xd4, 0xfd, 0x56, 0xe0, 0xdf, 0x61, - 0x3f, 0xde, 0x1a, 0xf8, 0x8d, 0x86, 0xdf, 0x8e, 0xc2, 0x0b, 0xad, 0xbb, 0xf5, 0x0b, 0x4e, 0xcb, - 0x0d, 0x2f, 0xa8, 0x92, 0x83, 0xb7, 0x3b, 0x8d, 0xd6, 0xbe, 0xf3, 0xf6, 0x0b, 0x75, 0xe2, 0x91, - 0xc0, 0x89, 0x48, 0x6d, 0xa5, 0x15, 0xf8, 0x91, 0x8f, 0xde, 0x19, 0x53, 0x5b, 0x91, 0xd4, 0xd8, - 0x8f, 0x5f, 0x94, 0x75, 0x57, 0x5a, 0x77, 0xeb, 0x2b, 0x94, 0xda, 0x8a, 0x2a, 0x91, 0xd4, 0x96, - 0xdf, 0xaa, 0xb5, 0xa5, 0xee, 0xd7, 0xfd, 0x0b, 0x8c, 0xe8, 0x6e, 0x7b, 0x8f, 0xfd, 0x63, 0x7f, - 0xd8, 0x2f, 0xce, 0x6c, 0xf9, 0xc9, 0xbb, 0xcf, 0x85, 0x2b, 0xae, 0x4f, 0xdb, 0x76, 0x61, 0xd7, - 0x89, 0xaa, 0xfb, 0x17, 0x0e, 0x7a, 0x5a, 0xb4, 0x6c, 0x6b, 0x48, 0x55, 0x3f, 0x20, 0x69, 0x38, - 0xcf, 0xc4, 0x38, 0x4d, 0xa7, 0xba, 0xef, 0x7a, 0x24, 0x38, 0x8c, 0x7b, 0xdd, 0x24, 0x91, 0x93, - 0x56, 0xeb, 0x42, 0xbf, 0x5a, 0x41, 0xdb, 0x8b, 0xdc, 0x26, 0xe9, 0xa9, 0xf0, 0xb3, 0x0f, 0xaa, - 0x10, 0x56, 0xf7, 0x49, 0xd3, 0xe9, 0xa9, 0xf7, 0x74, 0xbf, 0x7a, 0xed, 0xc8, 0x6d, 0x5c, 0x70, - 0xbd, 0x28, 0x8c, 0x82, 0x64, 0x25, 0xfb, 0xdf, 0x2c, 0x58, 0x58, 0xdd, 0x2c, 0xef, 0x04, 0xce, - 0xde, 0x9e, 0x5b, 0xc5, 0x7e, 0x3b, 0x72, 0xbd, 0x3a, 0x7a, 0x33, 0x4c, 0xba, 0x5e, 0x3d, 0x20, - 0x61, 0xb8, 0x64, 0x3d, 0x61, 0x9d, 0x9f, 0x2a, 0xcf, 0x7d, 0xb3, 0x53, 0x7a, 0xa4, 0xdb, 0x29, - 0x4d, 0x6e, 0xf0, 0x62, 0x2c, 0xe1, 0xe8, 0x59, 0x28, 0x86, 0x24, 0x38, 0x70, 0xab, 0x64, 0xdb, - 0x0f, 0xa2, 0xa5, 0xdc, 0x13, 0xd6, 0xf9, 0xf1, 0xf2, 0x29, 0x81, 0x5e, 0xac, 0xc4, 0x20, 0xac, - 0xe3, 0xd1, 0x6a, 0x81, 0xef, 0x47, 0x02, 0xbe, 0x94, 0x67, 0x5c, 0x54, 0x35, 0x1c, 0x83, 0xb0, - 0x8e, 0x87, 0xd6, 0x61, 0xde, 0xf1, 0x3c, 0x3f, 0x72, 0x22, 0xd7, 0xf7, 0xb6, 0x03, 0xb2, 0xe7, - 0xde, 0x5f, 0x1a, 0x63, 0x75, 0x97, 0x44, 0xdd, 0xf9, 0xd5, 0x04, 0x1c, 0xf7, 0xd4, 0xb0, 0xd7, - 0x61, 0x69, 0xb5, 0xb9, 0xeb, 0x84, 0xa1, 0x53, 0xf3, 0x83, 0x44, 0xd7, 0xcf, 0x43, 0xa1, 0xe9, - 0xb4, 0x5a, 0xae, 0x57, 0xa7, 0x7d, 0xcf, 0x9f, 0x9f, 0x2a, 0x4f, 0x77, 0x3b, 0xa5, 0xc2, 0x96, - 0x28, 0xc3, 0x0a, 0x6a, 0xff, 0x7d, 0x0e, 0x8a, 0xab, 0x9e, 0xd3, 0x38, 0x0c, 0xdd, 0x10, 0xb7, - 0x3d, 0xf4, 0x7e, 0x28, 0x50, 0x19, 0xa8, 0x39, 0x91, 0xc3, 0x46, 0xad, 0x78, 0xf1, 0x6d, 0x2b, - 0x7c, 0x4a, 0x56, 0xf4, 0x29, 0x89, 0x25, 0x9b, 0x62, 0xaf, 0x1c, 0xbc, 0x7d, 0xe5, 0xfa, 0xee, - 0x1d, 0x52, 0x8d, 0xb6, 0x48, 0xe4, 0x94, 0x91, 0xe8, 0x05, 0xc4, 0x65, 0x58, 0x51, 0x45, 0x3e, - 0x8c, 0x85, 0x2d, 0x52, 0x65, 0x83, 0x5c, 0xbc, 0xb8, 0xb5, 0x32, 0xca, 0x2a, 0x5a, 0xd1, 0x9a, - 0x5e, 0x69, 0x91, 0x6a, 0x79, 0x5a, 0xb0, 0x1e, 0xa3, 0xff, 0x30, 0x63, 0x84, 0xee, 0xc1, 0x44, - 0x18, 0x39, 0x51, 0x3b, 0x64, 0x13, 0x54, 0xbc, 0x78, 0x3d, 0x3b, 0x96, 0x8c, 0x6c, 0x79, 0x56, - 0x30, 0x9d, 0xe0, 0xff, 0xb1, 0x60, 0x67, 0xff, 0x83, 0x05, 0xa7, 0x34, 0xec, 0xd5, 0xa0, 0xde, - 0x6e, 0x12, 0x2f, 0x42, 0x4f, 0xc0, 0x98, 0xe7, 0x34, 0x89, 0x90, 0x4a, 0xd5, 0xe4, 0x6b, 0x4e, - 0x93, 0x60, 0x06, 0x41, 0x4f, 0xc2, 0xf8, 0x81, 0xd3, 0x68, 0x13, 0x36, 0x48, 0x53, 0xe5, 0x19, - 0x81, 0x32, 0x7e, 0x8b, 0x16, 0x62, 0x0e, 0x43, 0x1f, 0x82, 0x29, 0xf6, 0xe3, 0x72, 0xe0, 0x37, - 0x33, 0xea, 0x9a, 0x68, 0xe1, 0x2d, 0x49, 0xb6, 0x3c, 0xd3, 0xed, 0x94, 0xa6, 0xd4, 0x5f, 0x1c, - 0x33, 0xb4, 0xff, 0xd1, 0x82, 0x39, 0xad, 0x73, 0x9b, 0x6e, 0x18, 0xa1, 0xf7, 0xf6, 0x08, 0xcf, - 0xca, 0x60, 0xc2, 0x43, 0x6b, 0x33, 0xd1, 0x99, 0x17, 0x3d, 0x2d, 0xc8, 0x12, 0x4d, 0x70, 0x3c, - 0x18, 0x77, 0x23, 0xd2, 0x0c, 0x97, 0x72, 0x4f, 0xe4, 0xcf, 0x17, 0x2f, 0x6e, 0x64, 0x36, 0x8d, - 0xf1, 0xf8, 0x6e, 0x50, 0xfa, 0x98, 0xb3, 0xb1, 0xbf, 0x94, 0x33, 0x7a, 0x48, 0x25, 0x0a, 0xf9, - 0x30, 0xd9, 0x24, 0x51, 0xe0, 0x56, 0xf9, 0xba, 0x2a, 0x5e, 0x5c, 0x1f, 0xad, 0x15, 0x5b, 0x8c, - 0x58, 0xac, 0x99, 0xf8, 0xff, 0x10, 0x4b, 0x2e, 0x68, 0x1f, 0xc6, 0x9c, 0xa0, 0x2e, 0xfb, 0x7c, - 0x39, 0x9b, 0xf9, 0x8d, 0x65, 0x6e, 0x35, 0xa8, 0x87, 0x98, 0x71, 0x40, 0x17, 0x60, 0x2a, 0x22, - 0x41, 0xd3, 0xf5, 0x9c, 0x88, 0xab, 0xb2, 0x42, 0x79, 0x41, 0xa0, 0x4d, 0xed, 0x48, 0x00, 0x8e, - 0x71, 0xec, 0xd7, 0x72, 0xb0, 0xd0, 0xb3, 0x18, 0xd0, 0x33, 0x30, 0xde, 0xda, 0x77, 0x42, 0x29, - 0xdd, 0xe7, 0xe4, 0xd0, 0x6e, 0xd3, 0xc2, 0xd7, 0x3b, 0xa5, 0x19, 0x59, 0x85, 0x15, 0x60, 0x8e, - 0x4c, 0x75, 0x75, 0x93, 0x84, 0xa1, 0x53, 0x97, 0x22, 0xaf, 0x8d, 0x08, 0x2b, 0xc6, 0x12, 0x8e, - 0x7e, 0xd9, 0x82, 0x19, 0x3e, 0x3a, 0x98, 0x84, 0xed, 0x46, 0x44, 0x97, 0x35, 0x1d, 0x9b, 0xab, - 0x59, 0xcc, 0x04, 0x27, 0x59, 0x3e, 0x2d, 0xb8, 0xcf, 0xe8, 0xa5, 0x21, 0x36, 0xf9, 0xa2, 0xdb, - 0x30, 0x15, 0x46, 0x4e, 0x10, 0x91, 0xda, 0x6a, 0xc4, 0x14, 0x78, 0xf1, 0xe2, 0xff, 0x1f, 0x4c, - 0xde, 0x77, 0xdc, 0x26, 0xe1, 0x6b, 0xab, 0x22, 0x09, 0xe0, 0x98, 0x96, 0xfd, 0xb7, 0xa6, 0xe2, - 0xa8, 0x44, 0x74, 0xb3, 0xab, 0x1f, 0xa2, 0xf7, 0xc0, 0xa3, 0x61, 0xbb, 0x5a, 0x25, 0x61, 0xb8, - 0xd7, 0x6e, 0xe0, 0xb6, 0x77, 0xc5, 0x0d, 0x23, 0x3f, 0x38, 0xdc, 0x74, 0x9b, 0x6e, 0xc4, 0xc6, - 0x7b, 0xbc, 0x7c, 0xb6, 0xdb, 0x29, 0x3d, 0x5a, 0xe9, 0x87, 0x84, 0xfb, 0xd7, 0x47, 0x0e, 0x3c, - 0xd6, 0xf6, 0xfa, 0x93, 0xe7, 0x7b, 0x62, 0xa9, 0xdb, 0x29, 0x3d, 0x76, 0xb3, 0x3f, 0x1a, 0x3e, - 0x8a, 0x86, 0xfd, 0x2f, 0x16, 0xcc, 0xcb, 0x7e, 0xed, 0x90, 0x66, 0xab, 0xe1, 0x44, 0xe4, 0x21, - 0xec, 0x38, 0x91, 0xb1, 0xe3, 0xe0, 0x6c, 0xf4, 0x86, 0x6c, 0x7f, 0xbf, 0x6d, 0xc7, 0xfe, 0x67, - 0x0b, 0x16, 0x93, 0xc8, 0x0f, 0x41, 0x4b, 0x86, 0xa6, 0x96, 0xbc, 0x96, 0x6d, 0x6f, 0xfb, 0xa8, - 0xca, 0x1f, 0xa5, 0xf4, 0xf5, 0x7f, 0xb8, 0xbe, 0xb4, 0x7f, 0x77, 0x0c, 0xa6, 0x57, 0xbd, 0xc8, - 0x5d, 0xdd, 0xdb, 0x73, 0x3d, 0x37, 0x3a, 0x44, 0x9f, 0xce, 0xc1, 0x85, 0x56, 0x40, 0xf6, 0x48, - 0x10, 0x90, 0xda, 0x7a, 0x3b, 0x70, 0xbd, 0x7a, 0xa5, 0xba, 0x4f, 0x6a, 0xed, 0x86, 0xeb, 0xd5, - 0x37, 0xea, 0x9e, 0xaf, 0x8a, 0x2f, 0xdd, 0x27, 0xd5, 0x36, 0x35, 0xe5, 0xc4, 0xfc, 0x37, 0x47, - 0x6b, 0xe6, 0xf6, 0x70, 0x4c, 0xcb, 0x4f, 0x77, 0x3b, 0xa5, 0x0b, 0x43, 0x56, 0xc2, 0xc3, 0x76, - 0x0d, 0x7d, 0x2a, 0x07, 0x2b, 0x01, 0xf9, 0x40, 0xdb, 0x1d, 0x7c, 0x34, 0xf8, 0x02, 0x6d, 0x8c, - 0x36, 0x1a, 0x78, 0x28, 0x9e, 0xe5, 0x8b, 0xdd, 0x4e, 0x69, 0xc8, 0x3a, 0x78, 0xc8, 0x7e, 0xd9, - 0x7f, 0x6e, 0x41, 0x61, 0x08, 0xeb, 0xaf, 0x64, 0x5a, 0x7f, 0x53, 0x3d, 0x96, 0x5f, 0xd4, 0x6b, - 0xf9, 0xbd, 0x38, 0xda, 0xa0, 0x0d, 0x62, 0xf1, 0xfd, 0x2b, 0x3d, 0x65, 0x25, 0x2d, 0x44, 0xb4, - 0x0f, 0x8b, 0x2d, 0xbf, 0x26, 0x17, 0xfd, 0x15, 0x27, 0xdc, 0x67, 0x30, 0xd1, 0xbd, 0x67, 0xba, - 0x9d, 0xd2, 0xe2, 0x76, 0x0a, 0xfc, 0xf5, 0x4e, 0x69, 0x49, 0x11, 0x49, 0x20, 0xe0, 0x54, 0x8a, - 0xa8, 0x05, 0x85, 0x3d, 0x97, 0x34, 0x6a, 0x98, 0xec, 0x09, 0x49, 0x19, 0x71, 0x79, 0x5f, 0x16, - 0xd4, 0xf8, 0xe1, 0x48, 0xfe, 0xc3, 0x8a, 0x8b, 0xfd, 0x93, 0x31, 0x98, 0x2b, 0x37, 0xda, 0xe4, - 0xc5, 0x80, 0x10, 0x69, 0xdf, 0xac, 0xc2, 0x5c, 0x2b, 0x20, 0x07, 0x2e, 0xb9, 0x57, 0x21, 0x0d, - 0x52, 0x8d, 0xfc, 0x40, 0x74, 0xf5, 0x8c, 0x98, 0xc9, 0xb9, 0x6d, 0x13, 0x8c, 0x93, 0xf8, 0xe8, - 0x05, 0x98, 0x75, 0xaa, 0x91, 0x7b, 0x40, 0x14, 0x05, 0x3e, 0xd1, 0x6f, 0x10, 0x14, 0x66, 0x57, - 0x0d, 0x28, 0x4e, 0x60, 0xa3, 0xf7, 0xc2, 0x52, 0x58, 0x75, 0x1a, 0xe4, 0x66, 0x4b, 0xb0, 0x5a, - 0xdb, 0x27, 0xd5, 0xbb, 0xdb, 0xbe, 0xeb, 0x45, 0xc2, 0x70, 0x7b, 0x42, 0x50, 0x5a, 0xaa, 0xf4, - 0xc1, 0xc3, 0x7d, 0x29, 0xa0, 0x3f, 0xb5, 0xe0, 0x6c, 0x2b, 0x20, 0xdb, 0x81, 0xdf, 0xf4, 0xa9, - 0xf4, 0xf6, 0x98, 0x78, 0xc2, 0xd4, 0xb9, 0x35, 0xe2, 0x32, 0xe5, 0x25, 0xbd, 0xa7, 0xa9, 0x37, - 0x76, 0x3b, 0xa5, 0xb3, 0xdb, 0x47, 0x35, 0x00, 0x1f, 0xdd, 0x3e, 0xf4, 0x67, 0x16, 0x9c, 0x6b, - 0xf9, 0x61, 0x74, 0x44, 0x17, 0xc6, 0x4f, 0xb4, 0x0b, 0x76, 0xb7, 0x53, 0x3a, 0xb7, 0x7d, 0x64, - 0x0b, 0xf0, 0x03, 0x5a, 0x68, 0x77, 0x8b, 0xb0, 0xa0, 0xc9, 0x9e, 0xb0, 0x00, 0x9f, 0x87, 0x19, - 0x29, 0x0c, 0xdc, 0xe7, 0xc0, 0x65, 0x4f, 0xd9, 0xab, 0xab, 0x3a, 0x10, 0x9b, 0xb8, 0x54, 0xee, - 0x94, 0x28, 0xf2, 0xda, 0x09, 0xb9, 0xdb, 0x36, 0xa0, 0x38, 0x81, 0x8d, 0x36, 0xe0, 0x94, 0x28, - 0xc1, 0xa4, 0xd5, 0x70, 0xab, 0xce, 0x9a, 0xdf, 0x16, 0x22, 0x37, 0x5e, 0x3e, 0xd3, 0xed, 0x94, - 0x4e, 0x6d, 0xf7, 0x82, 0x71, 0x5a, 0x1d, 0xb4, 0x09, 0x8b, 0x4e, 0x3b, 0xf2, 0x55, 0xff, 0x2f, - 0x79, 0xce, 0x6e, 0x83, 0xd4, 0x98, 0x68, 0x15, 0xca, 0x4b, 0x54, 0x6b, 0xac, 0xa6, 0xc0, 0x71, - 0x6a, 0x2d, 0xb4, 0x9d, 0xa0, 0x56, 0x21, 0x55, 0xdf, 0xab, 0xf1, 0x59, 0x1e, 0x2f, 0x3f, 0x2e, - 0xba, 0x67, 0x52, 0x14, 0x38, 0x38, 0xb5, 0x26, 0x6a, 0xc0, 0x6c, 0xd3, 0xb9, 0x7f, 0xd3, 0x73, - 0x0e, 0x1c, 0xb7, 0x41, 0x99, 0x2c, 0x4d, 0x3c, 0xc0, 0x34, 0x6d, 0x47, 0x6e, 0x63, 0x85, 0xfb, - 0xa7, 0x56, 0x36, 0xbc, 0xe8, 0x7a, 0x50, 0x89, 0xe8, 0x26, 0x50, 0x46, 0x74, 0x60, 0xb7, 0x0c, - 0x5a, 0x38, 0x41, 0x1b, 0x5d, 0x87, 0xd3, 0x6c, 0x39, 0xae, 0xfb, 0xf7, 0xbc, 0x75, 0xd2, 0x70, - 0x0e, 0x65, 0x07, 0x26, 0x59, 0x07, 0x1e, 0xed, 0x76, 0x4a, 0xa7, 0x2b, 0x69, 0x08, 0x38, 0xbd, - 0x1e, 0xb5, 0xe5, 0x4d, 0x00, 0x26, 0x07, 0x6e, 0xe8, 0xfa, 0x1e, 0xb7, 0xe5, 0x0b, 0xb1, 0x2d, - 0x5f, 0xe9, 0x8f, 0x86, 0x8f, 0xa2, 0x81, 0x7e, 0xd3, 0x82, 0xc5, 0xb4, 0x65, 0xb8, 0x34, 0x95, - 0x85, 0x5f, 0x27, 0xb1, 0xb4, 0xb8, 0x44, 0xa4, 0x2a, 0x85, 0xd4, 0x46, 0xa0, 0x8f, 0x5a, 0x30, - 0xed, 0x68, 0xc6, 0xd9, 0x12, 0xb0, 0x56, 0x5d, 0x1d, 0xd5, 0x1a, 0x8e, 0x29, 0x96, 0xe7, 0xbb, - 0x9d, 0x92, 0x61, 0x00, 0x62, 0x83, 0x23, 0xfa, 0x2d, 0x0b, 0x4e, 0xa7, 0xae, 0xf1, 0xa5, 0xe2, - 0x49, 0x8c, 0x10, 0x13, 0x92, 0x74, 0x9d, 0x93, 0xde, 0x0c, 0xf4, 0x39, 0x4b, 0x6d, 0x65, 0x5b, - 0xf2, 0x3c, 0x32, 0xcd, 0x9a, 0x76, 0x63, 0x44, 0x7b, 0x34, 0xde, 0xbd, 0x25, 0xe1, 0xf2, 0x29, - 0x6d, 0x67, 0x94, 0x85, 0x38, 0xc9, 0x1e, 0x7d, 0xc6, 0x92, 0x5b, 0xa3, 0x6a, 0xd1, 0xcc, 0x49, - 0xb5, 0x08, 0xc5, 0x3b, 0xad, 0x6a, 0x50, 0x82, 0x39, 0x7a, 0x1f, 0x2c, 0x3b, 0xbb, 0x7e, 0x10, - 0xa5, 0x2e, 0xbe, 0xa5, 0x59, 0xb6, 0x8c, 0xce, 0x75, 0x3b, 0xa5, 0xe5, 0xd5, 0xbe, 0x58, 0xf8, - 0x08, 0x0a, 0xf6, 0x77, 0xc7, 0x60, 0x7a, 0xcd, 0xf1, 0x9c, 0xe0, 0x50, 0x6c, 0x5d, 0x5f, 0xb3, - 0xe0, 0xf1, 0x6a, 0x3b, 0x08, 0x88, 0x17, 0x55, 0x22, 0xd2, 0xea, 0xdd, 0xb8, 0xac, 0x13, 0xdd, - 0xb8, 0x9e, 0xe8, 0x76, 0x4a, 0x8f, 0xaf, 0x1d, 0xc1, 0x1f, 0x1f, 0xd9, 0x3a, 0xf4, 0xd7, 0x16, - 0xd8, 0x02, 0xa1, 0xec, 0x54, 0xef, 0xd6, 0x03, 0xbf, 0xed, 0xd5, 0x7a, 0x3b, 0x91, 0x3b, 0xd1, - 0x4e, 0x3c, 0xd5, 0xed, 0x94, 0xec, 0xb5, 0x07, 0xb6, 0x02, 0x0f, 0xd0, 0x52, 0xf4, 0x22, 0x2c, - 0x08, 0xac, 0x4b, 0xf7, 0x5b, 0x24, 0x70, 0xa9, 0xed, 0x2b, 0xfc, 0xfc, 0x8f, 0x8a, 0x6d, 0x65, - 0x61, 0x2d, 0x89, 0x80, 0x7b, 0xeb, 0xa0, 0x10, 0x26, 0xef, 0x11, 0xb7, 0xbe, 0x1f, 0x49, 0xf3, - 0x69, 0x73, 0xb4, 0xde, 0x0b, 0x87, 0xff, 0x6d, 0x4e, 0xb3, 0x5c, 0xa4, 0x87, 0x61, 0xf1, 0x07, - 0x4b, 0x4e, 0xf6, 0x1f, 0x8c, 0x01, 0x48, 0xf1, 0x22, 0x2d, 0xf4, 0x33, 0x30, 0x15, 0x92, 0x88, - 0x63, 0x09, 0x77, 0x11, 0xf7, 0x41, 0xc9, 0x42, 0x1c, 0xc3, 0xd1, 0x5d, 0x18, 0x6f, 0x39, 0xed, - 0x90, 0x88, 0xc9, 0xba, 0x9a, 0xc9, 0x64, 0x6d, 0x53, 0x8a, 0xfc, 0x40, 0xc3, 0x7e, 0x62, 0xce, - 0x03, 0x7d, 0xdc, 0x02, 0x20, 0xe6, 0x00, 0x17, 0x2f, 0x56, 0x32, 0x61, 0x19, 0xcf, 0x01, 0x1d, - 0x83, 0xf2, 0x6c, 0xb7, 0x53, 0x02, 0x6d, 0xaa, 0x34, 0xb6, 0xe8, 0x1e, 0x14, 0x1c, 0xa9, 0xa3, - 0xc7, 0x4e, 0x42, 0x47, 0xb3, 0x73, 0x86, 0x12, 0x32, 0xc5, 0x0c, 0x7d, 0xca, 0x82, 0xd9, 0x90, - 0x44, 0x62, 0xaa, 0xa8, 0xa6, 0x10, 0x06, 0xea, 0x88, 0x42, 0x52, 0x31, 0x68, 0x72, 0x8d, 0x67, - 0x96, 0xe1, 0x04, 0x5f, 0xfb, 0xbb, 0x45, 0x98, 0x95, 0x22, 0x13, 0xdb, 0x9c, 0x55, 0x5e, 0x92, - 0x6e, 0x73, 0xae, 0xe9, 0x40, 0x6c, 0xe2, 0xd2, 0xca, 0x61, 0x44, 0x8d, 0x1c, 0xd3, 0xe4, 0x54, - 0x95, 0x2b, 0x3a, 0x10, 0x9b, 0xb8, 0xa8, 0x09, 0xe3, 0x61, 0x44, 0x5a, 0xd2, 0xc3, 0x7b, 0x65, - 0xb4, 0xd1, 0x88, 0x57, 0x42, 0xec, 0xc5, 0xa2, 0xff, 0x42, 0xcc, 0xb9, 0xa0, 0xcf, 0x5a, 0x30, - 0x1b, 0x19, 0x17, 0x69, 0x42, 0x0c, 0xb2, 0x91, 0x44, 0xf3, 0x8e, 0x8e, 0xcf, 0x86, 0x59, 0x86, - 0x13, 0xec, 0x53, 0xcc, 0xd0, 0xf1, 0x13, 0x34, 0x43, 0x5f, 0x86, 0x42, 0xd3, 0xb9, 0x5f, 0x69, - 0x07, 0xf5, 0xe3, 0x9b, 0xbb, 0xe2, 0x9e, 0x91, 0x53, 0xc1, 0x8a, 0x1e, 0xfa, 0x98, 0xa5, 0x2d, - 0xae, 0x49, 0x46, 0xfc, 0x76, 0xb6, 0x8b, 0x4b, 0x69, 0xf1, 0xbe, 0xcb, 0xac, 0xc7, 0x28, 0x2c, - 0x3c, 0x74, 0xa3, 0x90, 0x1a, 0x38, 0x7c, 0x81, 0x28, 0x03, 0x67, 0xea, 0x44, 0x0d, 0x9c, 0x35, - 0x83, 0x19, 0x4e, 0x30, 0x67, 0xed, 0xe1, 0x6b, 0x4e, 0xb5, 0x07, 0x4e, 0xb4, 0x3d, 0x15, 0x83, - 0x19, 0x4e, 0x30, 0xef, 0x7f, 0x12, 0x2a, 0x9e, 0xcc, 0x49, 0x68, 0x3a, 0x83, 0x93, 0xd0, 0xd1, - 0x46, 0xe2, 0xcc, 0xa8, 0x46, 0x22, 0xba, 0x0a, 0xa8, 0x76, 0xe8, 0x39, 0x4d, 0xb7, 0x2a, 0x94, - 0x25, 0xdb, 0x20, 0x66, 0xd9, 0x49, 0x79, 0x59, 0x28, 0x32, 0xb4, 0xde, 0x83, 0x81, 0x53, 0x6a, - 0xd9, 0xff, 0x6e, 0xc1, 0xfc, 0x5a, 0xc3, 0x6f, 0xd7, 0x6e, 0x3b, 0x51, 0x75, 0x9f, 0x7b, 0xcf, - 0xd1, 0x0b, 0x50, 0x70, 0xbd, 0x88, 0x04, 0x07, 0x4e, 0x43, 0xe8, 0x76, 0x5b, 0x5e, 0x30, 0x6c, - 0x88, 0xf2, 0xd7, 0x3b, 0xa5, 0xd9, 0xf5, 0x76, 0xc0, 0xe2, 0x0f, 0xf8, 0x4a, 0xc7, 0xaa, 0x0e, - 0xfa, 0xb2, 0x05, 0x0b, 0xdc, 0xff, 0xbe, 0xee, 0x44, 0xce, 0x8d, 0x36, 0x09, 0x5c, 0x22, 0x3d, - 0xf0, 0x23, 0x2e, 0xf2, 0x64, 0x5b, 0x25, 0x83, 0xc3, 0xd8, 0xfc, 0xda, 0x4a, 0x72, 0xc6, 0xbd, - 0x8d, 0xb1, 0x3f, 0x9f, 0x87, 0x47, 0xfb, 0xd2, 0x42, 0xcb, 0x90, 0x73, 0x6b, 0xa2, 0xeb, 0x20, - 0xe8, 0xe6, 0x36, 0x6a, 0x38, 0xe7, 0xd6, 0xd0, 0x0a, 0xb3, 0x4c, 0x02, 0x12, 0x86, 0xd2, 0x43, - 0x3d, 0xa5, 0x8c, 0x08, 0x51, 0x8a, 0x35, 0x0c, 0x54, 0x82, 0xf1, 0x86, 0xb3, 0x4b, 0x1a, 0xc2, - 0x4a, 0x64, 0xb6, 0xce, 0x26, 0x2d, 0xc0, 0xbc, 0x1c, 0xfd, 0x92, 0x05, 0xc0, 0x1b, 0x48, 0x6d, - 0x4c, 0xb1, 0xc3, 0xe0, 0x6c, 0x87, 0x89, 0x52, 0xe6, 0xad, 0x8c, 0xff, 0x63, 0x8d, 0x2b, 0xda, - 0x81, 0x09, 0x6a, 0xf6, 0xf8, 0xb5, 0x63, 0x6f, 0x28, 0xd0, 0xed, 0x94, 0x26, 0xb6, 0x19, 0x0d, - 0x2c, 0x68, 0xd1, 0xb1, 0x0a, 0x48, 0xd4, 0x0e, 0x3c, 0x3a, 0xb4, 0x6c, 0x0b, 0x29, 0xf0, 0x56, - 0x60, 0x55, 0x8a, 0x35, 0x0c, 0xfb, 0x8f, 0x73, 0xb0, 0x98, 0xd6, 0x74, 0xaa, 0xa9, 0x27, 0x78, - 0x6b, 0xc5, 0x81, 0xe7, 0x5d, 0xd9, 0x8f, 0x8f, 0xb8, 0x4a, 0x52, 0xc1, 0x1b, 0xe2, 0xaa, 0x57, - 0xf0, 0x45, 0xef, 0x52, 0x23, 0x94, 0x3b, 0xe6, 0x08, 0x29, 0xca, 0x89, 0x51, 0x7a, 0x02, 0xc6, - 0x42, 0x3a, 0xf3, 0x79, 0xf3, 0x02, 0x80, 0xcd, 0x11, 0x83, 0x50, 0x8c, 0xb6, 0xe7, 0x46, 0x22, - 0x28, 0x48, 0x61, 0xdc, 0xf4, 0xdc, 0x08, 0x33, 0x88, 0xfd, 0xc5, 0x1c, 0x2c, 0xf7, 0xef, 0x14, - 0xfa, 0xa2, 0x05, 0x50, 0xa3, 0x46, 0x2d, 0x15, 0x49, 0x79, 0xf5, 0xe6, 0x9c, 0xd4, 0x18, 0xae, - 0x4b, 0x4e, 0xf1, 0x3d, 0xac, 0x2a, 0x0a, 0xb1, 0xd6, 0x10, 0x74, 0x51, 0x8a, 0xfe, 0x35, 0xa7, - 0x29, 0x4d, 0x41, 0x55, 0x67, 0x4b, 0x41, 0xb0, 0x86, 0x45, 0x4f, 0x2d, 0x9e, 0xd3, 0x24, 0x61, - 0xcb, 0x51, 0x21, 0x56, 0xec, 0xd4, 0x72, 0x4d, 0x16, 0xe2, 0x18, 0x6e, 0x37, 0xe0, 0xc9, 0x01, - 0xda, 0x99, 0x51, 0x04, 0x8e, 0xfd, 0x23, 0x0b, 0xce, 0xac, 0x35, 0xda, 0x61, 0x44, 0x82, 0xff, - 0x35, 0xd7, 0xda, 0xff, 0x61, 0xc1, 0x63, 0x7d, 0xfa, 0xfc, 0x10, 0x6e, 0xb7, 0x5f, 0x35, 0x6f, - 0xb7, 0x6f, 0x8e, 0x2a, 0xd2, 0xa9, 0xfd, 0xe8, 0x73, 0xc9, 0x1d, 0xc1, 0x0c, 0xd5, 0x5a, 0x35, - 0xbf, 0x9e, 0xd1, 0xbe, 0xf9, 0x24, 0x8c, 0x7f, 0x80, 0xee, 0x3f, 0x49, 0x19, 0x63, 0x9b, 0x12, - 0xe6, 0x30, 0xfb, 0xef, 0x72, 0xa0, 0x9d, 0x57, 0x1f, 0x82, 0x58, 0x79, 0x86, 0x58, 0x8d, 0x78, - 0x02, 0xd5, 0x4e, 0xdf, 0xfd, 0xc2, 0xf3, 0x0e, 0x12, 0xe1, 0x79, 0xd7, 0x32, 0xe3, 0x78, 0x74, - 0x74, 0xde, 0x6b, 0x16, 0x3c, 0x16, 0x23, 0xf7, 0xba, 0x7e, 0x1e, 0xac, 0x23, 0x9e, 0x85, 0xa2, - 0x13, 0x57, 0x13, 0xb3, 0xa8, 0xc2, 0x3f, 0x35, 0x8a, 0x58, 0xc7, 0x8b, 0x23, 0xa4, 0xf2, 0xc7, - 0x8c, 0x90, 0x1a, 0x3b, 0x3a, 0x42, 0xca, 0xfe, 0x71, 0x0e, 0xce, 0xf6, 0xf6, 0x4c, 0x4a, 0x37, - 0x26, 0x7b, 0x03, 0xf4, 0xed, 0x39, 0x98, 0x8e, 0x44, 0x05, 0x4d, 0x57, 0x2f, 0x0a, 0xcc, 0xe9, - 0x1d, 0x0d, 0x86, 0x0d, 0x4c, 0x5a, 0xb3, 0xca, 0xd7, 0x55, 0xa5, 0xea, 0xb7, 0x64, 0x28, 0x99, - 0xaa, 0xb9, 0xa6, 0xc1, 0xb0, 0x81, 0xa9, 0x62, 0x37, 0xc6, 0x4e, 0x3c, 0xd6, 0xad, 0x02, 0xa7, - 0xe5, 0x15, 0xfe, 0x65, 0x3f, 0x58, 0xf3, 0x9b, 0xad, 0x06, 0x61, 0x11, 0x08, 0xe3, 0xac, 0xb1, - 0x67, 0x45, 0x95, 0xd3, 0x38, 0x0d, 0x09, 0xa7, 0xd7, 0xb5, 0x5f, 0xcb, 0xc3, 0xa9, 0x78, 0xd8, - 0xd7, 0x7c, 0xaf, 0xe6, 0xb2, 0x40, 0x88, 0xe7, 0x61, 0x2c, 0x3a, 0x6c, 0xc9, 0xc1, 0xfe, 0x7f, - 0xb2, 0x39, 0x3b, 0x87, 0x2d, 0x3a, 0xdb, 0x67, 0x52, 0xaa, 0x50, 0x10, 0x66, 0x95, 0xd0, 0xa6, - 0x5a, 0x1d, 0x7c, 0x06, 0x9e, 0x31, 0xa5, 0xf9, 0xf5, 0x4e, 0x29, 0x25, 0xe8, 0x7b, 0x45, 0x51, - 0x32, 0x65, 0x1e, 0xdd, 0x81, 0xd9, 0x86, 0x13, 0x46, 0x37, 0x5b, 0x35, 0x27, 0x22, 0x3b, 0x6e, - 0x93, 0x88, 0x35, 0x37, 0x4c, 0xd8, 0x9a, 0xba, 0x2d, 0xdc, 0x34, 0x28, 0xe1, 0x04, 0x65, 0x74, - 0x00, 0x88, 0x96, 0xec, 0x04, 0x8e, 0x17, 0xf2, 0x5e, 0x51, 0x7e, 0xc3, 0x87, 0xc9, 0xa9, 0x23, - 0xce, 0x66, 0x0f, 0x35, 0x9c, 0xc2, 0x01, 0x3d, 0x05, 0x13, 0x01, 0x71, 0x42, 0x31, 0x99, 0x53, - 0xf1, 0xfa, 0xc7, 0xac, 0x14, 0x0b, 0xa8, 0xbe, 0xa0, 0x26, 0x1e, 0xb0, 0xa0, 0xbe, 0x67, 0xc1, - 0x6c, 0x3c, 0x4d, 0x0f, 0x61, 0x9b, 0x6b, 0x9a, 0xdb, 0xdc, 0x95, 0xac, 0x54, 0x62, 0x9f, 0x9d, - 0xed, 0xab, 0x63, 0x7a, 0xff, 0x58, 0xe0, 0xd6, 0x07, 0x61, 0x4a, 0xae, 0x6a, 0x69, 0x3f, 0x8e, - 0xe8, 0x27, 0x31, 0x2c, 0x0b, 0x2d, 0xb2, 0x54, 0x30, 0xc1, 0x31, 0x3f, 0xba, 0xb1, 0xd6, 0xc4, - 0xa6, 0x29, 0xc4, 0x5e, 0x6d, 0xac, 0x72, 0x33, 0x4d, 0xdb, 0x58, 0x65, 0x1d, 0x74, 0x13, 0xce, - 0xb4, 0x02, 0x9f, 0x85, 0xf6, 0xaf, 0x13, 0xa7, 0xd6, 0x70, 0x3d, 0x22, 0x8f, 0xe3, 0xfc, 0xb2, - 0xfa, 0xb1, 0x6e, 0xa7, 0x74, 0x66, 0x3b, 0x1d, 0x05, 0xf7, 0xab, 0x6b, 0x46, 0xc8, 0x8e, 0x3d, - 0x38, 0x42, 0x16, 0xfd, 0x8a, 0x72, 0x7a, 0x91, 0x70, 0x69, 0x9c, 0x0d, 0xe2, 0x7b, 0xb2, 0x9a, - 0xca, 0x14, 0xb5, 0x1e, 0x8b, 0xd4, 0xaa, 0x60, 0x8a, 0x15, 0xfb, 0xfe, 0x9e, 0x95, 0x89, 0xe3, - 0x79, 0x56, 0xec, 0x4f, 0x8c, 0xc3, 0x7c, 0x72, 0xb3, 0x3d, 0xf9, 0xe8, 0xdf, 0x5f, 0xb7, 0x60, - 0x5e, 0x0a, 0x0a, 0xe7, 0x49, 0xa4, 0x7b, 0x78, 0x33, 0x23, 0xf9, 0xe4, 0x66, 0x83, 0x7a, 0x8a, - 0xb1, 0x93, 0xe0, 0x86, 0x7b, 0xf8, 0xa3, 0x57, 0xa0, 0xa8, 0xbc, 0xa8, 0xc7, 0x0a, 0x05, 0x9e, - 0x63, 0x06, 0x43, 0x4c, 0x02, 0xeb, 0xf4, 0xd0, 0x27, 0x2c, 0x80, 0xaa, 0xd4, 0xe8, 0x52, 0x90, - 0x6e, 0x64, 0x25, 0x48, 0x6a, 0xaf, 0x88, 0xed, 0x42, 0x55, 0x14, 0x62, 0x8d, 0x31, 0xfa, 0x3c, - 0xf3, 0x9f, 0x2a, 0x43, 0x86, 0x8a, 0x0e, 0x6d, 0xc9, 0xbb, 0xb3, 0x16, 0xe9, 0xf8, 0x2a, 0x4f, - 0x59, 0x0d, 0x1a, 0x28, 0xc4, 0x46, 0x23, 0xec, 0xe7, 0x41, 0x85, 0x6e, 0xd1, 0x15, 0xca, 0x82, - 0xb7, 0xb6, 0x9d, 0x68, 0x5f, 0x88, 0xa0, 0x5a, 0xa1, 0x97, 0x25, 0x00, 0xc7, 0x38, 0xf6, 0xfb, - 0x61, 0xf6, 0xc5, 0xc0, 0x69, 0xed, 0xbb, 0xcc, 0x4f, 0x49, 0x8d, 0xfa, 0x37, 0xc3, 0xa4, 0x53, - 0xab, 0xa5, 0xbd, 0x1a, 0x5a, 0xe5, 0xc5, 0x58, 0xc2, 0x07, 0xb3, 0xdf, 0xff, 0xc2, 0x82, 0xc5, - 0x8d, 0x30, 0x72, 0xfd, 0x75, 0x12, 0x46, 0x54, 0x2d, 0x50, 0x0b, 0xa2, 0xdd, 0x20, 0x03, 0xd8, - 0x60, 0xeb, 0x30, 0x2f, 0x2e, 0x53, 0xda, 0xbb, 0x21, 0x89, 0x34, 0x3b, 0x4c, 0x09, 0xe7, 0x5a, - 0x02, 0x8e, 0x7b, 0x6a, 0x50, 0x2a, 0xe2, 0x56, 0x25, 0xa6, 0x92, 0x37, 0xa9, 0x54, 0x12, 0x70, - 0xdc, 0x53, 0xc3, 0xfe, 0x76, 0x1e, 0x4e, 0xb1, 0x6e, 0x24, 0x5e, 0x1a, 0xfd, 0x9a, 0x05, 0xb3, - 0x07, 0x6e, 0x10, 0xb5, 0x9d, 0x86, 0x7e, 0x3d, 0x34, 0xb2, 0x7c, 0x32, 0x5e, 0xb7, 0x0c, 0xc2, - 0xb1, 0xe5, 0x61, 0x96, 0xe3, 0x44, 0x03, 0x68, 0x9b, 0xe6, 0x6a, 0xe6, 0x68, 0x67, 0x73, 0x48, - 0x4e, 0x9b, 0x47, 0x1e, 0xd9, 0x90, 0x28, 0xc4, 0x49, 0xfe, 0xe8, 0x0b, 0x16, 0xcc, 0x99, 0xcd, - 0x94, 0x6a, 0xeb, 0x04, 0x06, 0x4a, 0x85, 0x22, 0x9a, 0xe5, 0x21, 0x4e, 0x36, 0xc1, 0xfe, 0xb6, - 0x25, 0xa6, 0xd5, 0xc4, 0x1c, 0x40, 0x38, 0x6d, 0x98, 0x08, 0xfc, 0x76, 0x24, 0x1c, 0xbd, 0x53, - 0xdc, 0x1f, 0x88, 0x59, 0x09, 0x16, 0x10, 0x74, 0x0f, 0xa6, 0xa2, 0x46, 0xc8, 0x0b, 0x45, 0x6f, - 0x47, 0xb4, 0xea, 0x77, 0x36, 0x2b, 0x8c, 0x9c, 0xb6, 0xf1, 0x8a, 0x12, 0x6a, 0x40, 0x48, 0x5e, - 0xf6, 0x57, 0x2c, 0x98, 0xba, 0xea, 0xef, 0x8a, 0x25, 0xfd, 0xbe, 0x0c, 0xce, 0xcc, 0x6a, 0x6b, - 0x55, 0x57, 0x17, 0xb1, 0xb5, 0xf6, 0x82, 0x71, 0x62, 0x7e, 0x5c, 0xa3, 0xbd, 0xc2, 0x9e, 0x6a, - 0x52, 0x52, 0x57, 0xfd, 0xdd, 0xbe, 0x2e, 0x95, 0xdf, 0x1e, 0x87, 0x99, 0x97, 0x9c, 0x43, 0xe2, - 0x45, 0xce, 0xf0, 0x4a, 0x88, 0x1e, 0x42, 0x5b, 0x2c, 0xb2, 0x4e, 0x33, 0x97, 0xe2, 0x43, 0x68, - 0x0c, 0xc2, 0x3a, 0x5e, 0xac, 0x5b, 0xd6, 0x7c, 0x6f, 0xcf, 0xad, 0xa7, 0x69, 0x85, 0xb5, 0x04, - 0x1c, 0xf7, 0xd4, 0x40, 0x57, 0x01, 0x89, 0xc0, 0xfb, 0xd5, 0x6a, 0xd5, 0x6f, 0x7b, 0x5c, 0xbb, - 0xf0, 0xf3, 0xa9, 0xb2, 0xdb, 0xb7, 0x7a, 0x30, 0x70, 0x4a, 0x2d, 0xf4, 0x5e, 0x58, 0xaa, 0x32, - 0xca, 0xc2, 0x8a, 0xd3, 0x29, 0x72, 0x4b, 0x5e, 0x45, 0xb5, 0xae, 0xf5, 0xc1, 0xc3, 0x7d, 0x29, - 0xd0, 0x96, 0x86, 0x91, 0x1f, 0x38, 0x75, 0xa2, 0xd3, 0x9d, 0x30, 0x5b, 0x5a, 0xe9, 0xc1, 0xc0, - 0x29, 0xb5, 0xd0, 0x47, 0x60, 0x2a, 0xda, 0x0f, 0x48, 0xb8, 0xef, 0x37, 0x6a, 0xe2, 0x2e, 0x73, - 0x44, 0xa7, 0x85, 0x98, 0xfd, 0x1d, 0x49, 0x55, 0x13, 0x6f, 0x59, 0x84, 0x63, 0x9e, 0x28, 0x80, - 0x89, 0x90, 0x9e, 0x98, 0xc3, 0xa5, 0x42, 0x16, 0x96, 0xb9, 0xe0, 0xce, 0x0e, 0xe1, 0x9a, 0xbb, - 0x84, 0x71, 0xc0, 0x82, 0x93, 0xfd, 0x8d, 0x1c, 0x4c, 0xeb, 0x88, 0x03, 0xa8, 0x88, 0x8f, 0x5b, - 0x30, 0x5d, 0xf5, 0xbd, 0x28, 0xf0, 0x1b, 0xdc, 0x15, 0xc0, 0x17, 0xc8, 0x88, 0x0f, 0xf7, 0x18, - 0xa9, 0x75, 0x12, 0x39, 0x6e, 0x43, 0xf3, 0x2a, 0x68, 0x6c, 0xb0, 0xc1, 0x14, 0x7d, 0xda, 0x82, - 0xb9, 0x38, 0xc8, 0x23, 0xf6, 0x49, 0x64, 0xda, 0x10, 0xa5, 0x71, 0x2f, 0x99, 0x9c, 0x70, 0x92, - 0xb5, 0xbd, 0x0b, 0xf3, 0xc9, 0xd9, 0xa6, 0x43, 0xd9, 0x72, 0xc4, 0x5a, 0xcf, 0xc7, 0x43, 0xb9, - 0xed, 0x84, 0x21, 0x66, 0x10, 0xf4, 0x16, 0x28, 0x34, 0x9d, 0xa0, 0xee, 0x7a, 0x4e, 0x83, 0x8d, - 0x62, 0x5e, 0x53, 0x48, 0xa2, 0x1c, 0x2b, 0x0c, 0xfb, 0x87, 0x63, 0x50, 0xdc, 0x22, 0x4e, 0xd8, - 0x0e, 0x08, 0x73, 0x1a, 0x9e, 0xb8, 0x55, 0x6e, 0xbc, 0x84, 0xcb, 0x67, 0xf7, 0x12, 0x0e, 0xbd, - 0x0c, 0xb0, 0xe7, 0x7a, 0x6e, 0xb8, 0x7f, 0xcc, 0x37, 0x76, 0xec, 0xf6, 0xe9, 0xb2, 0xa2, 0x80, - 0x35, 0x6a, 0xb1, 0x8b, 0x7f, 0xfc, 0x88, 0x47, 0xb6, 0x9f, 0xb0, 0xb4, 0xcd, 0x63, 0x22, 0x8b, - 0x2b, 0x4d, 0x6d, 0x62, 0x56, 0xe4, 0x66, 0x72, 0xc9, 0x8b, 0x82, 0xc3, 0x23, 0xf7, 0x98, 0x1d, - 0x28, 0x04, 0x24, 0x6c, 0x37, 0xe9, 0xf9, 0x62, 0x72, 0xe8, 0x61, 0x60, 0x11, 0x11, 0x58, 0xd4, - 0xc7, 0x8a, 0xd2, 0xf2, 0xf3, 0x30, 0x63, 0x34, 0x01, 0xcd, 0x43, 0xfe, 0x2e, 0x39, 0xe4, 0x72, - 0x82, 0xe9, 0x4f, 0xb4, 0x68, 0x5c, 0x84, 0x88, 0x61, 0x79, 0x47, 0xee, 0x39, 0xcb, 0xfe, 0xf1, - 0x04, 0x88, 0x4b, 0xb3, 0x01, 0x74, 0x81, 0xee, 0x2b, 0xcf, 0x1d, 0xc3, 0x57, 0x7e, 0x15, 0xa6, - 0x5d, 0xcf, 0x8d, 0x5c, 0xa7, 0xc1, 0x0e, 0xa1, 0x62, 0xaf, 0x7a, 0x4a, 0xae, 0xff, 0x0d, 0x0d, - 0x96, 0x42, 0xc7, 0xa8, 0x8b, 0x6e, 0xc0, 0x38, 0x53, 0xe6, 0x42, 0x9e, 0x86, 0xbf, 0xd9, 0x63, - 0x97, 0xba, 0x3c, 0xba, 0x9d, 0x53, 0x62, 0x46, 0x36, 0x7f, 0xf6, 0xa8, 0xce, 0x4e, 0x42, 0xac, - 0x62, 0x23, 0x3b, 0x01, 0xc7, 0x3d, 0x35, 0x28, 0x95, 0x3d, 0xc7, 0x6d, 0xb4, 0x03, 0x12, 0x53, - 0x99, 0x30, 0xa9, 0x5c, 0x4e, 0xc0, 0x71, 0x4f, 0x0d, 0xb4, 0x07, 0xd3, 0xa2, 0x8c, 0xc7, 0x38, - 0x4c, 0x1e, 0xb3, 0x97, 0x2c, 0x96, 0xe5, 0xb2, 0x46, 0x09, 0x1b, 0x74, 0x51, 0x1b, 0x16, 0x5c, - 0xaf, 0xea, 0x7b, 0xd5, 0x46, 0x3b, 0x74, 0x0f, 0x48, 0x1c, 0x5a, 0x7e, 0x1c, 0x66, 0xa7, 0xbb, - 0x9d, 0xd2, 0xc2, 0x46, 0x92, 0x1c, 0xee, 0xe5, 0x80, 0x3e, 0x66, 0xc1, 0xe9, 0xaa, 0xef, 0x85, - 0xec, 0x71, 0xd5, 0x01, 0xb9, 0x14, 0x04, 0x7e, 0xc0, 0x79, 0x4f, 0x1d, 0x93, 0x37, 0xf3, 0x7d, - 0xac, 0xa5, 0x91, 0xc4, 0xe9, 0x9c, 0xd0, 0xab, 0x50, 0x68, 0x05, 0xfe, 0x81, 0x5b, 0x23, 0x81, - 0x88, 0x97, 0xd9, 0xcc, 0xe2, 0x5d, 0xe3, 0xb6, 0xa0, 0x19, 0x6b, 0x02, 0x59, 0x82, 0x15, 0x3f, - 0xfb, 0xf7, 0x0b, 0x30, 0x6b, 0xa2, 0xa3, 0x0f, 0x03, 0xb4, 0x02, 0xbf, 0x49, 0xa2, 0x7d, 0xa2, - 0x42, 0x84, 0xaf, 0x8d, 0xfa, 0xa6, 0x50, 0xd2, 0x93, 0xf7, 0xe4, 0x54, 0x93, 0xc6, 0xa5, 0x58, - 0xe3, 0x88, 0x02, 0x98, 0xbc, 0xcb, 0xf7, 0x34, 0xb1, 0xc5, 0xbf, 0x94, 0x89, 0x41, 0x22, 0x38, - 0xb3, 0xd8, 0x56, 0x51, 0x84, 0x25, 0x23, 0xb4, 0x0b, 0xf9, 0x7b, 0x64, 0x37, 0x9b, 0xd7, 0x6f, - 0xb7, 0x89, 0x38, 0x2a, 0x94, 0x27, 0xbb, 0x9d, 0x52, 0xfe, 0x36, 0xd9, 0xc5, 0x94, 0x38, 0xed, - 0x57, 0x8d, 0xdf, 0xf8, 0x09, 0x55, 0x31, 0x62, 0xbf, 0x8c, 0xeb, 0x43, 0xde, 0x2f, 0x51, 0x84, - 0x25, 0x23, 0xf4, 0x2a, 0x4c, 0xdd, 0x73, 0x0e, 0xc8, 0x5e, 0xe0, 0x7b, 0x91, 0x08, 0xce, 0x18, - 0x31, 0x0a, 0xf5, 0xb6, 0x24, 0x27, 0xf8, 0xb2, 0xdd, 0x56, 0x15, 0xe2, 0x98, 0x1d, 0x3a, 0x80, - 0x82, 0x47, 0xee, 0x61, 0xd2, 0x70, 0xab, 0x22, 0x00, 0x70, 0x44, 0xb1, 0xbe, 0x26, 0xa8, 0x09, - 0xce, 0x6c, 0x1b, 0x92, 0x65, 0x58, 0xf1, 0xa2, 0x73, 0x79, 0xc7, 0xdf, 0x15, 0x8a, 0x6a, 0xc4, - 0xb9, 0x54, 0xc7, 0x3e, 0x3e, 0x97, 0x57, 0xfd, 0x5d, 0x4c, 0x89, 0xd3, 0x35, 0x52, 0x55, 0x91, - 0x01, 0x42, 0x4d, 0x5d, 0xcb, 0x36, 0x22, 0x82, 0xaf, 0x91, 0xb8, 0x14, 0x6b, 0x1c, 0xe9, 0xd8, - 0xd6, 0x85, 0xa7, 0x49, 0x28, 0xaa, 0x11, 0xc7, 0xd6, 0xf4, 0x5b, 0xf1, 0xb1, 0x95, 0x65, 0x58, - 0xf1, 0xb2, 0xff, 0x64, 0x0c, 0xa6, 0xf5, 0x2c, 0x06, 0x03, 0xec, 0xd5, 0xca, 0x5c, 0xcc, 0x0d, - 0x63, 0x2e, 0x52, 0x6b, 0xbf, 0x19, 0xdb, 0x36, 0xf2, 0xc0, 0xbf, 0x91, 0x99, 0xb5, 0x14, 0x5b, - 0xfb, 0x5a, 0x61, 0x88, 0x0d, 0xa6, 0x43, 0x5c, 0x93, 0x52, 0xfb, 0x8f, 0x9b, 0x01, 0xfc, 0x99, - 0x98, 0xb2, 0xff, 0x8c, 0x8d, 0xfd, 0x22, 0x40, 0x9c, 0xcf, 0x40, 0xf8, 0xca, 0x95, 0x9f, 0x54, - 0xcb, 0xb3, 0xa0, 0x61, 0xa1, 0xa7, 0x60, 0x82, 0x6e, 0x94, 0xa4, 0x26, 0xde, 0x6f, 0xa9, 0x23, - 0xd5, 0x65, 0x56, 0x8a, 0x05, 0x14, 0x3d, 0x47, 0x6d, 0x9a, 0x78, 0x7b, 0x13, 0xcf, 0xb2, 0x16, - 0x63, 0x9b, 0x26, 0x86, 0x61, 0x03, 0x93, 0x36, 0x9d, 0xd0, 0xdd, 0x88, 0x49, 0x92, 0xd6, 0x74, - 0xb6, 0x45, 0x61, 0x0e, 0x63, 0x47, 0xfc, 0xc4, 0xee, 0xc5, 0x36, 0xab, 0x71, 0xed, 0x88, 0x9f, - 0x80, 0xe3, 0x9e, 0x1a, 0xf6, 0xfb, 0x61, 0xd6, 0x5c, 0xc5, 0x74, 0x88, 0x5b, 0x81, 0xbf, 0xe7, - 0x36, 0x48, 0xd2, 0x39, 0xb1, 0xcd, 0x8b, 0xb1, 0x84, 0x0f, 0xe6, 0x21, 0xfd, 0xcb, 0x3c, 0x9c, - 0xba, 0x56, 0x77, 0xbd, 0xfb, 0x09, 0xd7, 0x62, 0x5a, 0x9a, 0x24, 0x6b, 0xd8, 0x34, 0x49, 0x71, - 0x00, 0xba, 0x48, 0xfa, 0x94, 0x1e, 0x80, 0x2e, 0x33, 0x42, 0x99, 0xb8, 0xe8, 0x7b, 0x16, 0x3c, - 0xee, 0xd4, 0xb8, 0x5d, 0xe5, 0x34, 0x44, 0x69, 0xcc, 0x54, 0xca, 0x78, 0x38, 0xa2, 0x96, 0xec, - 0xed, 0xfc, 0xca, 0xea, 0x11, 0x5c, 0xf9, 0x69, 0xe1, 0x4d, 0xa2, 0x07, 0x8f, 0x1f, 0x85, 0x8a, - 0x8f, 0x6c, 0xfe, 0xf2, 0x75, 0x78, 0xe3, 0x03, 0x19, 0x0d, 0x75, 0x26, 0xf8, 0xb8, 0x05, 0x53, - 0xdc, 0x6b, 0x86, 0xc9, 0x1e, 0x5d, 0x3c, 0x4e, 0xcb, 0xbd, 0x45, 0x82, 0x50, 0xe6, 0x3a, 0xd0, - 0xc2, 0xbd, 0x56, 0xb7, 0x37, 0x04, 0x04, 0x6b, 0x58, 0x54, 0x3d, 0xdd, 0x75, 0xbd, 0x9a, 0x98, - 0x26, 0xa5, 0x9e, 0x5e, 0x72, 0xbd, 0x1a, 0x66, 0x10, 0xa5, 0xc0, 0xf2, 0xfd, 0x14, 0x98, 0xfd, - 0x3b, 0x16, 0xcc, 0xb2, 0xf7, 0x25, 0xb1, 0x51, 0xfc, 0xac, 0xba, 0x15, 0xe6, 0xcd, 0x38, 0x6b, - 0xde, 0x0a, 0xbf, 0xde, 0x29, 0x15, 0xf9, 0x8b, 0x14, 0xf3, 0x92, 0xf8, 0x3d, 0xe2, 0x60, 0xcb, - 0xee, 0xae, 0x73, 0x43, 0x9f, 0xbb, 0x94, 0x1b, 0xa7, 0x22, 0x89, 0xe0, 0x98, 0x9e, 0xfd, 0x87, - 0x79, 0x38, 0x95, 0x12, 0x28, 0x4d, 0xcf, 0x9c, 0x13, 0x2c, 0x56, 0x54, 0xde, 0xbc, 0xbe, 0x92, - 0x79, 0x30, 0xf6, 0x0a, 0x0b, 0x49, 0x15, 0x92, 0xa4, 0xf4, 0x13, 0x2f, 0xc4, 0x82, 0x39, 0xfa, - 0x0d, 0x0b, 0x8a, 0x8e, 0x26, 0xec, 0xfc, 0x32, 0x7a, 0x37, 0xfb, 0xc6, 0xf4, 0xc8, 0xb6, 0x16, - 0x44, 0x13, 0x8b, 0xb2, 0xde, 0x96, 0xe5, 0x9f, 0x87, 0xa2, 0xd6, 0x85, 0x61, 0x64, 0x74, 0xf9, - 0x05, 0x98, 0x1f, 0x49, 0xc6, 0xdf, 0x0d, 0xc3, 0x26, 0xcf, 0xa0, 0x3b, 0xc2, 0x3d, 0xfd, 0xd9, - 0x95, 0x1a, 0x71, 0xf1, 0xee, 0x4a, 0x40, 0xed, 0x5d, 0x98, 0x4f, 0x1a, 0xde, 0x99, 0x5f, 0x48, - 0xbd, 0x0d, 0x86, 0x4c, 0x77, 0x61, 0xff, 0x55, 0x0e, 0x26, 0xc5, 0x6b, 0x8b, 0x87, 0x10, 0x7f, - 0x76, 0xd7, 0xf0, 0xa6, 0x6f, 0x64, 0xf2, 0x48, 0xa4, 0x6f, 0xf0, 0x59, 0x98, 0x08, 0x3e, 0x7b, - 0x29, 0x1b, 0x76, 0x47, 0x47, 0x9e, 0x7d, 0x36, 0x07, 0x73, 0x89, 0xd7, 0x2b, 0xe8, 0x93, 0x56, - 0x6f, 0xc0, 0xc5, 0xcd, 0x4c, 0x1f, 0xc8, 0xa8, 0xe8, 0xc6, 0xa3, 0x63, 0x2f, 0x42, 0x23, 0x81, - 0xce, 0x8d, 0xcc, 0x92, 0xac, 0x1d, 0x99, 0x4b, 0xe7, 0x9f, 0x2c, 0x78, 0xb4, 0xef, 0x7b, 0x1e, - 0xf6, 0x50, 0x39, 0x30, 0xa1, 0x42, 0xf6, 0x32, 0x7e, 0x9f, 0xa7, 0xbc, 0xb8, 0xc9, 0xb7, 0xa5, - 0x49, 0xf6, 0xe8, 0x19, 0x98, 0x66, 0x7a, 0x9c, 0x2e, 0x9f, 0x88, 0xb4, 0x44, 0x76, 0x2c, 0xe6, - 0x31, 0xa9, 0x68, 0xe5, 0xd8, 0xc0, 0xb2, 0xbf, 0x6c, 0xc1, 0x52, 0xbf, 0x67, 0xab, 0x03, 0xd8, - 0xe5, 0x3f, 0x97, 0x88, 0x05, 0x2b, 0xf5, 0xc4, 0x82, 0x25, 0x2c, 0x73, 0x19, 0xf6, 0xa5, 0x19, - 0xc5, 0xf9, 0x07, 0x84, 0x3a, 0x7d, 0xc6, 0x82, 0x33, 0x7d, 0x04, 0xa7, 0x27, 0x26, 0xd0, 0x3a, - 0x76, 0x4c, 0x60, 0x6e, 0xd0, 0x98, 0x40, 0xfb, 0x6f, 0xf2, 0x30, 0x2f, 0xda, 0x13, 0x6f, 0xe6, - 0xcf, 0x19, 0x11, 0x75, 0x6f, 0x4a, 0x44, 0xd4, 0x2d, 0x26, 0xf1, 0xff, 0x2f, 0x9c, 0xee, 0xa7, - 0x2b, 0x9c, 0xee, 0x27, 0x39, 0x38, 0x9d, 0xfa, 0x3a, 0x17, 0x7d, 0x2a, 0x45, 0x0b, 0xde, 0xce, - 0xf8, 0x19, 0xf0, 0x80, 0x7a, 0x70, 0xd4, 0x18, 0xb4, 0x2f, 0xe8, 0xb1, 0x5f, 0xfc, 0x98, 0xb0, - 0x77, 0x02, 0x0f, 0x9a, 0x87, 0x0c, 0x03, 0xb3, 0x7f, 0x35, 0x0f, 0xe7, 0x07, 0x25, 0xf4, 0x53, - 0x1a, 0x26, 0x1c, 0x1a, 0x61, 0xc2, 0x0f, 0x67, 0x87, 0x3a, 0x99, 0x88, 0xe1, 0xaf, 0xe4, 0xd5, - 0xb6, 0xd7, 0x2b, 0x9f, 0x03, 0x5d, 0xaa, 0x4c, 0x52, 0x2b, 0x46, 0x26, 0xc4, 0x8a, 0x55, 0xe1, - 0x64, 0x85, 0x17, 0xbf, 0xde, 0x29, 0x2d, 0x88, 0xbc, 0x3b, 0x15, 0x12, 0x89, 0x42, 0x2c, 0x2b, - 0xa1, 0xf3, 0x50, 0x08, 0x38, 0x54, 0x06, 0x46, 0x8a, 0x8b, 0x22, 0x5e, 0x86, 0x15, 0x14, 0x7d, - 0x44, 0x33, 0xfb, 0xc6, 0x4e, 0xea, 0x81, 0xe8, 0x51, 0xf7, 0x5f, 0xaf, 0x40, 0x21, 0x94, 0xd9, - 0xb2, 0xb8, 0x57, 0xf4, 0xe9, 0x01, 0xe3, 0x6d, 0xe9, 0x29, 0x41, 0xa6, 0xce, 0xe2, 0xfd, 0x53, - 0x89, 0xb5, 0x14, 0x49, 0x64, 0x2b, 0x03, 0x9d, 0xbb, 0x78, 0x20, 0xc5, 0x38, 0x7f, 0xcd, 0x82, - 0xa2, 0x98, 0xad, 0x87, 0x10, 0x02, 0x7c, 0xc7, 0x0c, 0x01, 0xbe, 0x94, 0x89, 0xee, 0xe8, 0x13, - 0xff, 0x7b, 0x07, 0xa6, 0xf5, 0x04, 0x0d, 0xe8, 0x65, 0x4d, 0xf7, 0x59, 0xa3, 0x3c, 0x04, 0x97, - 0xda, 0x31, 0xd6, 0x8b, 0xf6, 0x97, 0x0a, 0x6a, 0x14, 0x59, 0xa0, 0xb1, 0x2e, 0x83, 0xd6, 0x91, - 0x32, 0xa8, 0x8b, 0x40, 0x2e, 0x7b, 0x11, 0xb8, 0x01, 0x05, 0xa9, 0xa0, 0xc4, 0x36, 0xfe, 0xa4, - 0x1e, 0xc9, 0x43, 0x6d, 0x01, 0x4a, 0x4c, 0x13, 0x5c, 0x76, 0xaa, 0x50, 0x73, 0xa8, 0x14, 0xa7, - 0x22, 0x83, 0x5e, 0x85, 0xe2, 0x3d, 0x3f, 0xb8, 0xdb, 0xf0, 0x1d, 0x96, 0xb4, 0x0e, 0xb2, 0xf0, - 0x6f, 0x2b, 0xef, 0x0a, 0x0f, 0x1a, 0xbd, 0x1d, 0xd3, 0xc7, 0x3a, 0x33, 0xb4, 0x0a, 0x73, 0x4d, - 0xd7, 0xc3, 0xc4, 0xa9, 0xa9, 0x48, 0xdf, 0x31, 0x9e, 0xa8, 0x4b, 0x1a, 0xb9, 0x5b, 0x26, 0x18, - 0x27, 0xf1, 0xd1, 0x07, 0xa1, 0x10, 0x8a, 0x24, 0x10, 0xd9, 0xdc, 0x44, 0xa8, 0xe3, 0x11, 0x27, - 0x1a, 0x8f, 0x9d, 0x2c, 0xc1, 0x8a, 0x21, 0xda, 0x84, 0xc5, 0x40, 0x3c, 0xb3, 0x36, 0xf2, 0xd0, - 0xf2, 0xf5, 0xc9, 0xf2, 0x41, 0xe1, 0x14, 0x38, 0x4e, 0xad, 0x45, 0xad, 0x18, 0x96, 0x69, 0x84, - 0xbb, 0x64, 0x0b, 0xda, 0xdb, 0x4c, 0x56, 0x8a, 0x05, 0xf4, 0xa8, 0xc8, 0xf1, 0xc2, 0x08, 0x91, - 0xe3, 0x15, 0x38, 0x9d, 0x04, 0xb1, 0xc7, 0xe0, 0xec, 0xfd, 0xb9, 0xb6, 0x7b, 0x6c, 0xa7, 0x21, - 0xe1, 0xf4, 0xba, 0xe8, 0x36, 0x4c, 0x05, 0x84, 0x9d, 0x2f, 0x56, 0xe5, 0xdd, 0xe7, 0xd0, 0x41, - 0x17, 0x58, 0x12, 0xc0, 0x31, 0x2d, 0x3a, 0xef, 0x8e, 0x99, 0xab, 0xea, 0x46, 0x86, 0x29, 0xd3, - 0xc5, 0xdc, 0xf7, 0x49, 0xd2, 0x60, 0xff, 0xe7, 0x0c, 0xcc, 0x18, 0xc7, 0x68, 0xf4, 0x24, 0x8c, - 0xb3, 0xd7, 0xf1, 0x4c, 0x3d, 0x14, 0x62, 0x15, 0xc6, 0x07, 0x87, 0xc3, 0xd0, 0x67, 0x2d, 0x98, - 0x6b, 0x19, 0x2e, 0x3f, 0xa9, 0x39, 0x47, 0xbc, 0x66, 0x31, 0xfd, 0x88, 0x5a, 0x96, 0x47, 0x93, - 0x19, 0x4e, 0x72, 0xa7, 0x0b, 0x50, 0xc4, 0x21, 0x35, 0x48, 0xc0, 0xb0, 0x85, 0x8d, 0xa3, 0x48, - 0xac, 0x99, 0x60, 0x9c, 0xc4, 0xa7, 0x33, 0xcc, 0x7a, 0x37, 0x4a, 0x82, 0xe9, 0x55, 0x49, 0x00, - 0xc7, 0xb4, 0xd0, 0x0b, 0x30, 0x2b, 0x52, 0x14, 0x6d, 0xfb, 0xb5, 0x2b, 0x4e, 0xb8, 0x2f, 0x8c, - 0x7b, 0x75, 0x18, 0x59, 0x33, 0xa0, 0x38, 0x81, 0xcd, 0xfa, 0x16, 0xe7, 0x81, 0x62, 0x04, 0x26, - 0xcc, 0x24, 0x98, 0x6b, 0x26, 0x18, 0x27, 0xf1, 0xd1, 0x5b, 0x34, 0xbd, 0xcf, 0xaf, 0x49, 0x94, - 0x36, 0x48, 0xd1, 0xfd, 0xab, 0x30, 0xd7, 0x66, 0x67, 0xa1, 0x9a, 0x04, 0x8a, 0xf5, 0xa8, 0x18, - 0xde, 0x34, 0xc1, 0x38, 0x89, 0x8f, 0x9e, 0x87, 0x99, 0x80, 0x6a, 0x37, 0x45, 0x80, 0xdf, 0x9d, - 0xa8, 0x8b, 0x00, 0xac, 0x03, 0xb1, 0x89, 0x8b, 0x5e, 0x84, 0x85, 0x38, 0x6f, 0x8a, 0x24, 0xc0, - 0x2f, 0x53, 0x54, 0x22, 0x82, 0xd5, 0x24, 0x02, 0xee, 0xad, 0x83, 0x7e, 0x01, 0xe6, 0xb5, 0x91, - 0xd8, 0xf0, 0x6a, 0xe4, 0xbe, 0xc8, 0x6d, 0xb1, 0xc8, 0x2e, 0x64, 0x12, 0x30, 0xdc, 0x83, 0x8d, - 0xde, 0x01, 0xb3, 0x55, 0xbf, 0xd1, 0x60, 0x3a, 0x8e, 0x27, 0x60, 0xe4, 0x49, 0x2c, 0x78, 0xba, - 0x0f, 0x03, 0x82, 0x13, 0x98, 0xe8, 0x2a, 0x20, 0x7f, 0x37, 0x24, 0xc1, 0x01, 0xa9, 0xbd, 0xc8, - 0xbf, 0xa1, 0x41, 0xb7, 0xf8, 0x19, 0x33, 0x0a, 0xf2, 0x7a, 0x0f, 0x06, 0x4e, 0xa9, 0x85, 0x76, - 0x61, 0x59, 0xee, 0x37, 0xbd, 0x35, 0x96, 0x96, 0x8c, 0x23, 0xd3, 0xf2, 0xed, 0xbe, 0x98, 0xf8, - 0x08, 0x2a, 0x2c, 0x57, 0x82, 0xf6, 0xf2, 0x61, 0x36, 0x8b, 0x94, 0xd6, 0x49, 0xef, 0xc0, 0x03, - 0x9f, 0x3d, 0x04, 0x30, 0xc1, 0x03, 0x5f, 0x97, 0xe6, 0xb2, 0xc8, 0x17, 0xa3, 0xe7, 0x7b, 0x8b, - 0xf7, 0x21, 0x5e, 0x8a, 0x05, 0x27, 0xf4, 0x61, 0x98, 0xda, 0x95, 0xc9, 0x3f, 0x97, 0xe6, 0xb3, - 0xd8, 0x7b, 0x13, 0x79, 0x6c, 0xe3, 0xd3, 0xaf, 0x02, 0xe0, 0x98, 0x25, 0x7a, 0x0a, 0x8a, 0x57, - 0xb6, 0x57, 0x95, 0xa4, 0x2f, 0x30, 0x09, 0x1b, 0xa3, 0x55, 0xb0, 0x0e, 0xa0, 0xab, 0x58, 0xd9, - 0x64, 0x88, 0x4d, 0x79, 0xbc, 0xa7, 0xf7, 0x9a, 0x58, 0x14, 0x9b, 0xdd, 0xaf, 0xe1, 0xca, 0xd2, - 0xa9, 0x04, 0xb6, 0x28, 0xc7, 0x0a, 0x03, 0xbd, 0x02, 0x45, 0xb1, 0x27, 0x31, 0xfd, 0xb7, 0x78, - 0xbc, 0x57, 0x35, 0x38, 0x26, 0x81, 0x75, 0x7a, 0xe8, 0x59, 0x28, 0xb6, 0x58, 0x4e, 0x44, 0x72, - 0xb9, 0xdd, 0x68, 0x2c, 0x9d, 0x66, 0xba, 0x59, 0x5d, 0x3c, 0x6c, 0xc7, 0x20, 0xac, 0xe3, 0xa1, - 0xa7, 0xe5, 0xe5, 0xf8, 0x1b, 0x8c, 0x7b, 0x24, 0x75, 0x39, 0xae, 0x2c, 0xe9, 0x3e, 0xa1, 0x94, - 0x67, 0x1e, 0xe0, 0x1c, 0xf9, 0x58, 0xec, 0x1c, 0x56, 0x19, 0xb8, 0x3e, 0xa4, 0x4b, 0x83, 0x95, - 0xc5, 0x97, 0x3e, 0x7a, 0x32, 0xcb, 0xf2, 0xcd, 0x22, 0x55, 0x16, 0x5a, 0x4a, 0xfe, 0x33, 0x79, - 0x12, 0x6e, 0x66, 0x17, 0xe3, 0x27, 0x2d, 0x53, 0xfa, 0xed, 0xef, 0x8f, 0x29, 0x07, 0x51, 0xe2, - 0x4e, 0x38, 0x80, 0x71, 0x37, 0x8c, 0x5c, 0x3f, 0xc3, 0x47, 0x26, 0x89, 0xb4, 0x5c, 0x2c, 0xb6, - 0x8f, 0x01, 0x30, 0x67, 0x45, 0x79, 0x7a, 0x75, 0xd7, 0xbb, 0x2f, 0xba, 0x7f, 0x23, 0xf3, 0xcb, - 0x5e, 0xce, 0x93, 0x01, 0x30, 0x67, 0x85, 0xee, 0x40, 0xde, 0x69, 0xec, 0x66, 0xf4, 0x55, 0x97, - 0xe4, 0x97, 0x91, 0x78, 0x64, 0xcc, 0xea, 0x66, 0x19, 0x53, 0x26, 0x94, 0x57, 0xd8, 0x74, 0x85, - 0x7d, 0x31, 0x22, 0xaf, 0xca, 0xd6, 0x46, 0x1a, 0xaf, 0xca, 0xd6, 0x06, 0xa6, 0x4c, 0xd0, 0x27, - 0x2d, 0x00, 0x47, 0x7d, 0xb5, 0x28, 0x9b, 0x34, 0xcc, 0xfd, 0xbe, 0x82, 0xc4, 0xc3, 0x71, 0x62, - 0x28, 0xd6, 0x38, 0xdb, 0x9f, 0xb3, 0x60, 0xa1, 0xa7, 0xb1, 0xc9, 0x0f, 0x3a, 0x59, 0x83, 0x7f, - 0xd0, 0x49, 0x24, 0x6e, 0xab, 0xb4, 0x1a, 0x6e, 0xea, 0x43, 0xad, 0x9d, 0x04, 0x1c, 0xf7, 0xd4, - 0xb0, 0xbf, 0x6e, 0x41, 0x51, 0x8b, 0x29, 0xa7, 0x76, 0x2f, 0x8b, 0xbd, 0x17, 0xcd, 0x88, 0x73, - 0xd6, 0x31, 0x9f, 0x18, 0x87, 0x71, 0xf7, 0x6c, 0x5d, 0x4b, 0x4d, 0x14, 0xbb, 0x67, 0x69, 0x29, - 0x16, 0x50, 0x9e, 0x74, 0x86, 0xb4, 0x98, 0x44, 0xe5, 0xf5, 0xa4, 0x33, 0xa4, 0x85, 0x19, 0x84, - 0xb1, 0xa3, 0xca, 0x51, 0xc4, 0xcd, 0x68, 0x29, 0xf2, 0x1c, 0x6a, 0x66, 0x33, 0x18, 0x3a, 0x0b, - 0x79, 0xe2, 0xd5, 0x84, 0xb5, 0x58, 0x14, 0x28, 0xf9, 0x4b, 0x5e, 0x0d, 0xd3, 0x72, 0xfb, 0x3a, - 0x4c, 0x57, 0x48, 0x35, 0x20, 0xd1, 0x4b, 0xe4, 0x70, 0x30, 0x07, 0xe2, 0x59, 0x7e, 0xf1, 0x9a, - 0x33, 0x09, 0xd2, 0xea, 0xb4, 0xdc, 0xfe, 0x3d, 0x0b, 0x12, 0x19, 0x0b, 0x35, 0x57, 0x8d, 0xd5, - 0xcf, 0x55, 0x63, 0x38, 0x15, 0x72, 0x47, 0x3a, 0x15, 0xae, 0x02, 0x6a, 0x3a, 0x51, 0x75, 0xdf, - 0xc8, 0xa7, 0x29, 0x0c, 0xf5, 0xf8, 0x05, 0x4b, 0x0f, 0x06, 0x4e, 0xa9, 0x65, 0xdf, 0x82, 0x82, - 0x7c, 0x8d, 0xc4, 0x42, 0xfa, 0xe5, 0x99, 0x45, 0x0f, 0xe9, 0xa7, 0x47, 0x16, 0x06, 0xa1, 0x6d, - 0x0c, 0x3d, 0xf7, 0x8a, 0x1f, 0x46, 0xf2, 0x09, 0x15, 0xf7, 0x4c, 0x5c, 0xdb, 0x60, 0x65, 0x58, - 0x41, 0xed, 0x05, 0x98, 0x53, 0x2e, 0x07, 0x2e, 0x71, 0xf6, 0x37, 0xf2, 0x30, 0x6d, 0x7c, 0x68, - 0xe3, 0xc1, 0x23, 0x3d, 0xf8, 0x98, 0xa4, 0xb8, 0x0e, 0xf2, 0x43, 0xba, 0x0e, 0x74, 0x5f, 0xcd, - 0xd8, 0xc9, 0xfa, 0x6a, 0xc6, 0xb3, 0xf1, 0xd5, 0x44, 0x30, 0x29, 0x3e, 0xed, 0x26, 0x42, 0x1f, - 0xb7, 0x32, 0x7a, 0x4e, 0x2c, 0xde, 0xe4, 0xb1, 0x68, 0x4f, 0xa9, 0x3d, 0x24, 0x2b, 0xfb, 0x6b, - 0xe3, 0x30, 0x6b, 0x3e, 0x30, 0x1e, 0x60, 0x26, 0xdf, 0xd2, 0x33, 0x93, 0x43, 0x1e, 0x9d, 0xf2, - 0xa3, 0x1e, 0x9d, 0xc6, 0x46, 0x3d, 0x3a, 0x8d, 0x1f, 0xe3, 0xe8, 0xd4, 0x7b, 0xf0, 0x99, 0x18, - 0xf8, 0xe0, 0xf3, 0x4e, 0x75, 0xef, 0x37, 0x69, 0x38, 0xca, 0xe3, 0x7b, 0x3f, 0x64, 0x4e, 0xc3, - 0x9a, 0x5f, 0x4b, 0xbd, 0x3f, 0x2d, 0x3c, 0x20, 0xa8, 0x30, 0x48, 0xbd, 0xa6, 0x1b, 0xde, 0x3b, - 0xf3, 0x86, 0x21, 0xae, 0xe8, 0xe2, 0xaf, 0x17, 0xb2, 0x9d, 0x07, 0xcc, 0x5d, 0xab, 0x12, 0x83, - 0xb0, 0x8e, 0xc7, 0xbe, 0x64, 0x61, 0x7e, 0x67, 0x83, 0x9d, 0x44, 0xf5, 0x2f, 0x59, 0x24, 0xbe, - 0xcb, 0x91, 0xc4, 0xb7, 0xbf, 0x9a, 0x87, 0x59, 0x33, 0x13, 0x31, 0xba, 0xa7, 0xac, 0xc5, 0x4c, - 0x0c, 0x55, 0x4e, 0x56, 0x7b, 0x5e, 0xdb, 0xf7, 0xc8, 0xc4, 0x3f, 0xf3, 0xb7, 0xab, 0xde, 0xfa, - 0x9e, 0x1c, 0x63, 0x71, 0x56, 0x11, 0xec, 0x58, 0xf2, 0xe2, 0x38, 0xca, 0x4e, 0xdc, 0xf5, 0x65, - 0xce, 0x3d, 0x8e, 0x9b, 0x53, 0xac, 0xb0, 0xc6, 0x96, 0xaa, 0xf7, 0x03, 0x12, 0xb8, 0x7b, 0xae, - 0xfa, 0x8a, 0x02, 0x53, 0x9e, 0xb7, 0x44, 0x19, 0x56, 0x50, 0xfb, 0xa3, 0x39, 0x88, 0x3f, 0xf0, - 0xc2, 0x92, 0xa2, 0x86, 0xda, 0x9e, 0x2d, 0xa6, 0xed, 0xea, 0xa8, 0x99, 0x87, 0x63, 0x8a, 0x22, - 0x2c, 0x42, 0x2b, 0xc1, 0x06, 0xc7, 0xff, 0x86, 0x0f, 0xbb, 0x38, 0x30, 0x97, 0x88, 0x8a, 0xcf, - 0x3c, 0xcc, 0xea, 0xeb, 0x39, 0x98, 0x52, 0xef, 0x0a, 0xa8, 0x99, 0xd3, 0x0e, 0x64, 0x96, 0x30, - 0x65, 0xe6, 0xdc, 0xc4, 0x9b, 0x98, 0x96, 0xa3, 0xfb, 0x30, 0xb9, 0x4f, 0x9c, 0x1a, 0x09, 0xa4, - 0xd3, 0x72, 0x2b, 0xa3, 0x07, 0x0d, 0x57, 0x18, 0xd5, 0xb8, 0x2f, 0xfc, 0x7f, 0x88, 0x25, 0x3b, - 0xf4, 0x02, 0xcc, 0x46, 0x6e, 0x93, 0xd0, 0xd3, 0xa6, 0xb6, 0xd5, 0xe7, 0x63, 0x4f, 0xe0, 0x8e, - 0x01, 0xc5, 0x09, 0x6c, 0xba, 0x17, 0xdd, 0x09, 0x7d, 0x8f, 0x25, 0x5c, 0x18, 0x33, 0x8f, 0xf4, - 0x57, 0x2b, 0xd7, 0xaf, 0xb1, 0x7c, 0x0b, 0x0a, 0x83, 0x62, 0xbb, 0x2c, 0xbe, 0x38, 0x20, 0xe2, - 0xe2, 0x74, 0x3e, 0x7e, 0x05, 0xc6, 0xcb, 0xb1, 0xc2, 0xb0, 0x6f, 0xc2, 0x5c, 0xa2, 0x23, 0xd2, - 0x5c, 0xb4, 0xd2, 0xcd, 0xc5, 0xc1, 0xb2, 0xf6, 0xfd, 0x91, 0x05, 0x0b, 0x3d, 0xeb, 0x6b, 0xd0, - 0x10, 0xbd, 0xa4, 0xb2, 0xcd, 0x1d, 0x5f, 0xd9, 0xe6, 0x87, 0x53, 0xb6, 0xe5, 0x95, 0x6f, 0xfe, - 0xe0, 0xdc, 0x23, 0xdf, 0xfa, 0xc1, 0xb9, 0x47, 0xbe, 0xf3, 0x83, 0x73, 0x8f, 0x7c, 0xb4, 0x7b, - 0xce, 0xfa, 0x66, 0xf7, 0x9c, 0xf5, 0xad, 0xee, 0x39, 0xeb, 0x3b, 0xdd, 0x73, 0xd6, 0xf7, 0xbb, - 0xe7, 0xac, 0xcf, 0xfd, 0xf0, 0xdc, 0x23, 0x2f, 0x17, 0xa4, 0x10, 0xfc, 0x57, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x63, 0x4a, 0xda, 0x7b, 0xee, 0x78, 0x00, 0x00, + // 6424 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x6d, 0x8c, 0x1c, 0xc9, + 0x55, 0xd7, 0x33, 0xfb, 0x31, 0xfb, 0x66, 0x3f, 0xcb, 0xeb, 0x78, 0x6f, 0xef, 0xec, 0xb9, 0xf4, + 0x45, 0x87, 0x03, 0xc9, 0x3a, 0xf1, 0xdd, 0xc1, 0x91, 0x8b, 0x4e, 0xec, 0xec, 0xda, 0xe7, 0xf5, + 0xed, 0xda, 0xeb, 0x9a, 0xb5, 0x9d, 0x5c, 0x72, 0x21, 0xbd, 0x33, 0xb5, 0xb3, 0x6d, 0xcf, 0x74, + 0x4f, 0xba, 0x7b, 0xd6, 0xde, 0x4b, 0x94, 0x0f, 0xa2, 0x84, 0x80, 0x12, 0x25, 0x90, 0xe4, 0x07, + 0x42, 0x41, 0x11, 0xe2, 0x07, 0x22, 0xfc, 0x40, 0x11, 0x88, 0x3f, 0x41, 0x44, 0x40, 0xa4, 0xf0, + 0x03, 0x14, 0x24, 0xe0, 0x02, 0x4a, 0x86, 0x64, 0xc2, 0x1f, 0xf8, 0x83, 0x82, 0x82, 0x50, 0x4e, + 0x42, 0x42, 0xf5, 0xd9, 0x55, 0x3d, 0x3d, 0xeb, 0x99, 0x9d, 0x5e, 0x13, 0x01, 0xff, 0x66, 0xea, + 0xbd, 0x7a, 0xaf, 0x3e, 0x5e, 0xbd, 0x7a, 0xf5, 0xea, 0xd5, 0x6b, 0xd8, 0xac, 0xbb, 0xd1, 0x7e, + 0x7b, 0x77, 0xa5, 0xea, 0x37, 0x2f, 0x38, 0x41, 0xdd, 0x6f, 0x05, 0xfe, 0x1d, 0xf6, 0xe3, 0xad, + 0x81, 0xdf, 0x68, 0xf8, 0xed, 0x28, 0xbc, 0xd0, 0xba, 0x5b, 0xbf, 0xe0, 0xb4, 0xdc, 0xf0, 0x82, + 0x2a, 0x39, 0x78, 0xbb, 0xd3, 0x68, 0xed, 0x3b, 0x6f, 0xbf, 0x50, 0x27, 0x1e, 0x09, 0x9c, 0x88, + 0xd4, 0x56, 0x5a, 0x81, 0x1f, 0xf9, 0xe8, 0x9d, 0x31, 0xb5, 0x15, 0x49, 0x8d, 0xfd, 0xf8, 0x45, + 0x59, 0x77, 0xa5, 0x75, 0xb7, 0xbe, 0x42, 0xa9, 0xad, 0xa8, 0x12, 0x49, 0x6d, 0xf9, 0xad, 0x5a, + 0x5b, 0xea, 0x7e, 0xdd, 0xbf, 0xc0, 0x88, 0xee, 0xb6, 0xf7, 0xd8, 0x3f, 0xf6, 0x87, 0xfd, 0xe2, + 0xcc, 0x96, 0x9f, 0xbc, 0xfb, 0x5c, 0xb8, 0xe2, 0xfa, 0xb4, 0x6d, 0x17, 0x76, 0x9d, 0xa8, 0xba, + 0x7f, 0xe1, 0xa0, 0xa7, 0x45, 0xcb, 0xb6, 0x86, 0x54, 0xf5, 0x03, 0x92, 0x86, 0xf3, 0x4c, 0x8c, + 0xd3, 0x74, 0xaa, 0xfb, 0xae, 0x47, 0x82, 0xc3, 0xb8, 0xd7, 0x4d, 0x12, 0x39, 0x69, 0xb5, 0x2e, + 0xf4, 0xab, 0x15, 0xb4, 0xbd, 0xc8, 0x6d, 0x92, 0x9e, 0x0a, 0x3f, 0xfb, 0xa0, 0x0a, 0x61, 0x75, + 0x9f, 0x34, 0x9d, 0x9e, 0x7a, 0x4f, 0xf7, 0xab, 0xd7, 0x8e, 0xdc, 0xc6, 0x05, 0xd7, 0x8b, 0xc2, + 0x28, 0x48, 0x56, 0xb2, 0xff, 0xdd, 0x82, 0x85, 0xd5, 0xcd, 0xf2, 0x4e, 0xe0, 0xec, 0xed, 0xb9, + 0x55, 0xec, 0xb7, 0x23, 0xd7, 0xab, 0xa3, 0x37, 0xc3, 0xa4, 0xeb, 0xd5, 0x03, 0x12, 0x86, 0x4b, + 0xd6, 0x13, 0xd6, 0xf9, 0xa9, 0xf2, 0xdc, 0x37, 0x3b, 0xa5, 0x47, 0xba, 0x9d, 0xd2, 0xe4, 0x06, + 0x2f, 0xc6, 0x12, 0x8e, 0x9e, 0x85, 0x62, 0x48, 0x82, 0x03, 0xb7, 0x4a, 0xb6, 0xfd, 0x20, 0x5a, + 0xca, 0x3d, 0x61, 0x9d, 0x1f, 0x2f, 0x9f, 0x12, 0xe8, 0xc5, 0x4a, 0x0c, 0xc2, 0x3a, 0x1e, 0xad, + 0x16, 0xf8, 0x7e, 0x24, 0xe0, 0x4b, 0x79, 0xc6, 0x45, 0x55, 0xc3, 0x31, 0x08, 0xeb, 0x78, 0x68, + 0x1d, 0xe6, 0x1d, 0xcf, 0xf3, 0x23, 0x27, 0x72, 0x7d, 0x6f, 0x3b, 0x20, 0x7b, 0xee, 0xfd, 0xa5, + 0x31, 0x56, 0x77, 0x49, 0xd4, 0x9d, 0x5f, 0x4d, 0xc0, 0x71, 0x4f, 0x0d, 0x7b, 0x1d, 0x96, 0x56, + 0x9b, 0xbb, 0x4e, 0x18, 0x3a, 0x35, 0x3f, 0x48, 0x74, 0xfd, 0x3c, 0x14, 0x9a, 0x4e, 0xab, 0xe5, + 0x7a, 0x75, 0xda, 0xf7, 0xfc, 0xf9, 0xa9, 0xf2, 0x74, 0xb7, 0x53, 0x2a, 0x6c, 0x89, 0x32, 0xac, + 0xa0, 0xf6, 0x3f, 0xe4, 0xa0, 0xb8, 0xea, 0x39, 0x8d, 0xc3, 0xd0, 0x0d, 0x71, 0xdb, 0x43, 0xef, + 0x87, 0x02, 0x95, 0x81, 0x9a, 0x13, 0x39, 0x6c, 0xd4, 0x8a, 0x17, 0xdf, 0xb6, 0xc2, 0xa7, 0x64, + 0x45, 0x9f, 0x92, 0x58, 0xb2, 0x29, 0xf6, 0xca, 0xc1, 0xdb, 0x57, 0xae, 0xef, 0xde, 0x21, 0xd5, + 0x68, 0x8b, 0x44, 0x4e, 0x19, 0x89, 0x5e, 0x40, 0x5c, 0x86, 0x15, 0x55, 0xe4, 0xc3, 0x58, 0xd8, + 0x22, 0x55, 0x36, 0xc8, 0xc5, 0x8b, 0x5b, 0x2b, 0xa3, 0xac, 0xa2, 0x15, 0xad, 0xe9, 0x95, 0x16, + 0xa9, 0x96, 0xa7, 0x05, 0xeb, 0x31, 0xfa, 0x0f, 0x33, 0x46, 0xe8, 0x1e, 0x4c, 0x84, 0x91, 0x13, + 0xb5, 0x43, 0x36, 0x41, 0xc5, 0x8b, 0xd7, 0xb3, 0x63, 0xc9, 0xc8, 0x96, 0x67, 0x05, 0xd3, 0x09, + 0xfe, 0x1f, 0x0b, 0x76, 0xf6, 0x3f, 0x5a, 0x70, 0x4a, 0xc3, 0x5e, 0x0d, 0xea, 0xed, 0x26, 0xf1, + 0x22, 0xf4, 0x04, 0x8c, 0x79, 0x4e, 0x93, 0x08, 0xa9, 0x54, 0x4d, 0xbe, 0xe6, 0x34, 0x09, 0x66, + 0x10, 0xf4, 0x24, 0x8c, 0x1f, 0x38, 0x8d, 0x36, 0x61, 0x83, 0x34, 0x55, 0x9e, 0x11, 0x28, 0xe3, + 0xb7, 0x68, 0x21, 0xe6, 0x30, 0xf4, 0x21, 0x98, 0x62, 0x3f, 0x2e, 0x07, 0x7e, 0x33, 0xa3, 0xae, + 0x89, 0x16, 0xde, 0x92, 0x64, 0xcb, 0x33, 0xdd, 0x4e, 0x69, 0x4a, 0xfd, 0xc5, 0x31, 0x43, 0xfb, + 0x9f, 0x2c, 0x98, 0xd3, 0x3a, 0xb7, 0xe9, 0x86, 0x11, 0x7a, 0x6f, 0x8f, 0xf0, 0xac, 0x0c, 0x26, + 0x3c, 0xb4, 0x36, 0x13, 0x9d, 0x79, 0xd1, 0xd3, 0x82, 0x2c, 0xd1, 0x04, 0xc7, 0x83, 0x71, 0x37, + 0x22, 0xcd, 0x70, 0x29, 0xf7, 0x44, 0xfe, 0x7c, 0xf1, 0xe2, 0x46, 0x66, 0xd3, 0x18, 0x8f, 0xef, + 0x06, 0xa5, 0x8f, 0x39, 0x1b, 0xfb, 0x4b, 0x39, 0xa3, 0x87, 0x54, 0xa2, 0x90, 0x0f, 0x93, 0x4d, + 0x12, 0x05, 0x6e, 0x95, 0xaf, 0xab, 0xe2, 0xc5, 0xf5, 0xd1, 0x5a, 0xb1, 0xc5, 0x88, 0xc5, 0x9a, + 0x89, 0xff, 0x0f, 0xb1, 0xe4, 0x82, 0xf6, 0x61, 0xcc, 0x09, 0xea, 0xb2, 0xcf, 0x97, 0xb3, 0x99, + 0xdf, 0x58, 0xe6, 0x56, 0x83, 0x7a, 0x88, 0x19, 0x07, 0x74, 0x01, 0xa6, 0x22, 0x12, 0x34, 0x5d, + 0xcf, 0x89, 0xb8, 0x2a, 0x2b, 0x94, 0x17, 0x04, 0xda, 0xd4, 0x8e, 0x04, 0xe0, 0x18, 0xc7, 0x7e, + 0x2d, 0x07, 0x0b, 0x3d, 0x8b, 0x01, 0x3d, 0x03, 0xe3, 0xad, 0x7d, 0x27, 0x94, 0xd2, 0x7d, 0x4e, + 0x0e, 0xed, 0x36, 0x2d, 0x7c, 0xbd, 0x53, 0x9a, 0x91, 0x55, 0x58, 0x01, 0xe6, 0xc8, 0x54, 0x57, + 0x37, 0x49, 0x18, 0x3a, 0x75, 0x29, 0xf2, 0xda, 0x88, 0xb0, 0x62, 0x2c, 0xe1, 0xe8, 0x97, 0x2d, + 0x98, 0xe1, 0xa3, 0x83, 0x49, 0xd8, 0x6e, 0x44, 0x74, 0x59, 0xd3, 0xb1, 0xb9, 0x9a, 0xc5, 0x4c, + 0x70, 0x92, 0xe5, 0xd3, 0x82, 0xfb, 0x8c, 0x5e, 0x1a, 0x62, 0x93, 0x2f, 0xba, 0x0d, 0x53, 0x61, + 0xe4, 0x04, 0x11, 0xa9, 0xad, 0x46, 0x4c, 0x81, 0x17, 0x2f, 0xfe, 0xf4, 0x60, 0xf2, 0xbe, 0xe3, + 0x36, 0x09, 0x5f, 0x5b, 0x15, 0x49, 0x00, 0xc7, 0xb4, 0xec, 0xbf, 0x33, 0x15, 0x47, 0x25, 0xa2, + 0x9b, 0x5d, 0xfd, 0x10, 0xbd, 0x07, 0x1e, 0x0d, 0xdb, 0xd5, 0x2a, 0x09, 0xc3, 0xbd, 0x76, 0x03, + 0xb7, 0xbd, 0x2b, 0x6e, 0x18, 0xf9, 0xc1, 0xe1, 0xa6, 0xdb, 0x74, 0x23, 0x36, 0xde, 0xe3, 0xe5, + 0xb3, 0xdd, 0x4e, 0xe9, 0xd1, 0x4a, 0x3f, 0x24, 0xdc, 0xbf, 0x3e, 0x72, 0xe0, 0xb1, 0xb6, 0xd7, + 0x9f, 0x3c, 0xdf, 0x13, 0x4b, 0xdd, 0x4e, 0xe9, 0xb1, 0x9b, 0xfd, 0xd1, 0xf0, 0x51, 0x34, 0xec, + 0x7f, 0xb5, 0x60, 0x5e, 0xf6, 0x6b, 0x87, 0x34, 0x5b, 0x0d, 0x27, 0x22, 0x0f, 0x61, 0xc7, 0x89, + 0x8c, 0x1d, 0x07, 0x67, 0xa3, 0x37, 0x64, 0xfb, 0xfb, 0x6d, 0x3b, 0xf6, 0xbf, 0x58, 0xb0, 0x98, + 0x44, 0x7e, 0x08, 0x5a, 0x32, 0x34, 0xb5, 0xe4, 0xb5, 0x6c, 0x7b, 0xdb, 0x47, 0x55, 0xfe, 0x30, + 0xa5, 0xaf, 0xff, 0xcb, 0xf5, 0xa5, 0xfd, 0xbb, 0x63, 0x30, 0xbd, 0xea, 0x45, 0xee, 0xea, 0xde, + 0x9e, 0xeb, 0xb9, 0xd1, 0x21, 0xfa, 0x74, 0x0e, 0x2e, 0xb4, 0x02, 0xb2, 0x47, 0x82, 0x80, 0xd4, + 0xd6, 0xdb, 0x81, 0xeb, 0xd5, 0x2b, 0xd5, 0x7d, 0x52, 0x6b, 0x37, 0x5c, 0xaf, 0xbe, 0x51, 0xf7, + 0x7c, 0x55, 0x7c, 0xe9, 0x3e, 0xa9, 0xb6, 0xa9, 0x29, 0x27, 0xe6, 0xbf, 0x39, 0x5a, 0x33, 0xb7, + 0x87, 0x63, 0x5a, 0x7e, 0xba, 0xdb, 0x29, 0x5d, 0x18, 0xb2, 0x12, 0x1e, 0xb6, 0x6b, 0xe8, 0x53, + 0x39, 0x58, 0x09, 0xc8, 0x07, 0xda, 0xee, 0xe0, 0xa3, 0xc1, 0x17, 0x68, 0x63, 0xb4, 0xd1, 0xc0, + 0x43, 0xf1, 0x2c, 0x5f, 0xec, 0x76, 0x4a, 0x43, 0xd6, 0xc1, 0x43, 0xf6, 0xcb, 0xfe, 0x73, 0x0b, + 0x0a, 0x43, 0x58, 0x7f, 0x25, 0xd3, 0xfa, 0x9b, 0xea, 0xb1, 0xfc, 0xa2, 0x5e, 0xcb, 0xef, 0xc5, + 0xd1, 0x06, 0x6d, 0x10, 0x8b, 0xef, 0xdf, 0xe8, 0x29, 0x2b, 0x69, 0x21, 0xa2, 0x7d, 0x58, 0x6c, + 0xf9, 0x35, 0xb9, 0xe8, 0xaf, 0x38, 0xe1, 0x3e, 0x83, 0x89, 0xee, 0x3d, 0xd3, 0xed, 0x94, 0x16, + 0xb7, 0x53, 0xe0, 0xaf, 0x77, 0x4a, 0x4b, 0x8a, 0x48, 0x02, 0x01, 0xa7, 0x52, 0x44, 0x2d, 0x28, + 0xec, 0xb9, 0xa4, 0x51, 0xc3, 0x64, 0x4f, 0x48, 0xca, 0x88, 0xcb, 0xfb, 0xb2, 0xa0, 0xc6, 0x0f, + 0x47, 0xf2, 0x1f, 0x56, 0x5c, 0xec, 0x1f, 0x8f, 0xc1, 0x5c, 0xb9, 0xd1, 0x26, 0x2f, 0x06, 0x84, + 0x48, 0xfb, 0x66, 0x15, 0xe6, 0x5a, 0x01, 0x39, 0x70, 0xc9, 0xbd, 0x0a, 0x69, 0x90, 0x6a, 0xe4, + 0x07, 0xa2, 0xab, 0x67, 0xc4, 0x4c, 0xce, 0x6d, 0x9b, 0x60, 0x9c, 0xc4, 0x47, 0x2f, 0xc0, 0xac, + 0x53, 0x8d, 0xdc, 0x03, 0xa2, 0x28, 0xf0, 0x89, 0x7e, 0x83, 0xa0, 0x30, 0xbb, 0x6a, 0x40, 0x71, + 0x02, 0x1b, 0xbd, 0x17, 0x96, 0xc2, 0xaa, 0xd3, 0x20, 0x37, 0x5b, 0x82, 0xd5, 0xda, 0x3e, 0xa9, + 0xde, 0xdd, 0xf6, 0x5d, 0x2f, 0x12, 0x86, 0xdb, 0x13, 0x82, 0xd2, 0x52, 0xa5, 0x0f, 0x1e, 0xee, + 0x4b, 0x01, 0xfd, 0xa9, 0x05, 0x67, 0x5b, 0x01, 0xd9, 0x0e, 0xfc, 0xa6, 0x4f, 0xa5, 0xb7, 0xc7, + 0xc4, 0x13, 0xa6, 0xce, 0xad, 0x11, 0x97, 0x29, 0x2f, 0xe9, 0x3d, 0x4d, 0xbd, 0xb1, 0xdb, 0x29, + 0x9d, 0xdd, 0x3e, 0xaa, 0x01, 0xf8, 0xe8, 0xf6, 0xa1, 0x3f, 0xb3, 0xe0, 0x5c, 0xcb, 0x0f, 0xa3, + 0x23, 0xba, 0x30, 0x7e, 0xa2, 0x5d, 0xb0, 0xbb, 0x9d, 0xd2, 0xb9, 0xed, 0x23, 0x5b, 0x80, 0x1f, + 0xd0, 0x42, 0xbb, 0x5b, 0x84, 0x05, 0x4d, 0xf6, 0x84, 0x05, 0xf8, 0x3c, 0xcc, 0x48, 0x61, 0xe0, + 0x3e, 0x07, 0x2e, 0x7b, 0xca, 0x5e, 0x5d, 0xd5, 0x81, 0xd8, 0xc4, 0xa5, 0x72, 0xa7, 0x44, 0x91, + 0xd7, 0x4e, 0xc8, 0xdd, 0xb6, 0x01, 0xc5, 0x09, 0x6c, 0xb4, 0x01, 0xa7, 0x44, 0x09, 0x26, 0xad, + 0x86, 0x5b, 0x75, 0xd6, 0xfc, 0xb6, 0x10, 0xb9, 0xf1, 0xf2, 0x99, 0x6e, 0xa7, 0x74, 0x6a, 0xbb, + 0x17, 0x8c, 0xd3, 0xea, 0xa0, 0x4d, 0x58, 0x74, 0xda, 0x91, 0xaf, 0xfa, 0x7f, 0xc9, 0x73, 0x76, + 0x1b, 0xa4, 0xc6, 0x44, 0xab, 0x50, 0x5e, 0xa2, 0x5a, 0x63, 0x35, 0x05, 0x8e, 0x53, 0x6b, 0xa1, + 0xed, 0x04, 0xb5, 0x0a, 0xa9, 0xfa, 0x5e, 0x8d, 0xcf, 0xf2, 0x78, 0xf9, 0x71, 0xd1, 0x3d, 0x93, + 0xa2, 0xc0, 0xc1, 0xa9, 0x35, 0x51, 0x03, 0x66, 0x9b, 0xce, 0xfd, 0x9b, 0x9e, 0x73, 0xe0, 0xb8, + 0x0d, 0xca, 0x64, 0x69, 0xe2, 0x01, 0xa6, 0x69, 0x3b, 0x72, 0x1b, 0x2b, 0xdc, 0x3f, 0xb5, 0xb2, + 0xe1, 0x45, 0xd7, 0x83, 0x4a, 0x44, 0x37, 0x81, 0x32, 0xa2, 0x03, 0xbb, 0x65, 0xd0, 0xc2, 0x09, + 0xda, 0xe8, 0x3a, 0x9c, 0x66, 0xcb, 0x71, 0xdd, 0xbf, 0xe7, 0xad, 0x93, 0x86, 0x73, 0x28, 0x3b, + 0x30, 0xc9, 0x3a, 0xf0, 0x68, 0xb7, 0x53, 0x3a, 0x5d, 0x49, 0x43, 0xc0, 0xe9, 0xf5, 0xa8, 0x2d, + 0x6f, 0x02, 0x30, 0x39, 0x70, 0x43, 0xd7, 0xf7, 0xb8, 0x2d, 0x5f, 0x88, 0x6d, 0xf9, 0x4a, 0x7f, + 0x34, 0x7c, 0x14, 0x0d, 0xf4, 0x9b, 0x16, 0x2c, 0xa6, 0x2d, 0xc3, 0xa5, 0xa9, 0x2c, 0xfc, 0x3a, + 0x89, 0xa5, 0xc5, 0x25, 0x22, 0x55, 0x29, 0xa4, 0x36, 0x02, 0x7d, 0xd4, 0x82, 0x69, 0x47, 0x33, + 0xce, 0x96, 0x80, 0xb5, 0xea, 0xea, 0xa8, 0xd6, 0x70, 0x4c, 0xb1, 0x3c, 0xdf, 0xed, 0x94, 0x0c, + 0x03, 0x10, 0x1b, 0x1c, 0xd1, 0x6f, 0x59, 0x70, 0x3a, 0x75, 0x8d, 0x2f, 0x15, 0x4f, 0x62, 0x84, + 0x98, 0x90, 0xa4, 0xeb, 0x9c, 0xf4, 0x66, 0xa0, 0xcf, 0x59, 0x6a, 0x2b, 0xdb, 0x92, 0xe7, 0x91, + 0x69, 0xd6, 0xb4, 0x1b, 0x23, 0xda, 0xa3, 0xf1, 0xee, 0x2d, 0x09, 0x97, 0x4f, 0x69, 0x3b, 0xa3, + 0x2c, 0xc4, 0x49, 0xf6, 0xe8, 0x33, 0x96, 0xdc, 0x1a, 0x55, 0x8b, 0x66, 0x4e, 0xaa, 0x45, 0x28, + 0xde, 0x69, 0x55, 0x83, 0x12, 0xcc, 0xd1, 0xfb, 0x60, 0xd9, 0xd9, 0xf5, 0x83, 0x28, 0x75, 0xf1, + 0x2d, 0xcd, 0xb2, 0x65, 0x74, 0xae, 0xdb, 0x29, 0x2d, 0xaf, 0xf6, 0xc5, 0xc2, 0x47, 0x50, 0xb0, + 0xbf, 0x33, 0x06, 0xd3, 0x6b, 0x8e, 0xe7, 0x04, 0x87, 0x62, 0xeb, 0xfa, 0x9a, 0x05, 0x8f, 0x57, + 0xdb, 0x41, 0x40, 0xbc, 0xa8, 0x12, 0x91, 0x56, 0xef, 0xc6, 0x65, 0x9d, 0xe8, 0xc6, 0xf5, 0x44, + 0xb7, 0x53, 0x7a, 0x7c, 0xed, 0x08, 0xfe, 0xf8, 0xc8, 0xd6, 0xa1, 0xbf, 0xb6, 0xc0, 0x16, 0x08, + 0x65, 0xa7, 0x7a, 0xb7, 0x1e, 0xf8, 0x6d, 0xaf, 0xd6, 0xdb, 0x89, 0xdc, 0x89, 0x76, 0xe2, 0xa9, + 0x6e, 0xa7, 0x64, 0xaf, 0x3d, 0xb0, 0x15, 0x78, 0x80, 0x96, 0xa2, 0x17, 0x61, 0x41, 0x60, 0x5d, + 0xba, 0xdf, 0x22, 0x81, 0x4b, 0x6d, 0x5f, 0xe1, 0xe7, 0x7f, 0x54, 0x6c, 0x2b, 0x0b, 0x6b, 0x49, + 0x04, 0xdc, 0x5b, 0x07, 0x85, 0x30, 0x79, 0x8f, 0xb8, 0xf5, 0xfd, 0x48, 0x9a, 0x4f, 0x9b, 0xa3, + 0xf5, 0x5e, 0x38, 0xfc, 0x6f, 0x73, 0x9a, 0xe5, 0x22, 0x3d, 0x0c, 0x8b, 0x3f, 0x58, 0x72, 0xb2, + 0xff, 0x60, 0x0c, 0x40, 0x8a, 0x17, 0x69, 0xa1, 0x9f, 0x81, 0xa9, 0x90, 0x44, 0x1c, 0x4b, 0xb8, + 0x8b, 0xb8, 0x0f, 0x4a, 0x16, 0xe2, 0x18, 0x8e, 0xee, 0xc2, 0x78, 0xcb, 0x69, 0x87, 0x44, 0x4c, + 0xd6, 0xd5, 0x4c, 0x26, 0x6b, 0x9b, 0x52, 0xe4, 0x07, 0x1a, 0xf6, 0x13, 0x73, 0x1e, 0xe8, 0xe3, + 0x16, 0x00, 0x31, 0x07, 0xb8, 0x78, 0xb1, 0x92, 0x09, 0xcb, 0x78, 0x0e, 0xe8, 0x18, 0x94, 0x67, + 0xbb, 0x9d, 0x12, 0x68, 0x53, 0xa5, 0xb1, 0x45, 0xf7, 0xa0, 0xe0, 0x48, 0x1d, 0x3d, 0x76, 0x12, + 0x3a, 0x9a, 0x9d, 0x33, 0x94, 0x90, 0x29, 0x66, 0xe8, 0x53, 0x16, 0xcc, 0x86, 0x24, 0x12, 0x53, + 0x45, 0x35, 0x85, 0x30, 0x50, 0x47, 0x14, 0x92, 0x8a, 0x41, 0x93, 0x6b, 0x3c, 0xb3, 0x0c, 0x27, + 0xf8, 0xda, 0xdf, 0x29, 0xc2, 0xac, 0x14, 0x99, 0xd8, 0xe6, 0xac, 0xf2, 0x92, 0x74, 0x9b, 0x73, + 0x4d, 0x07, 0x62, 0x13, 0x97, 0x56, 0x0e, 0x23, 0x6a, 0xe4, 0x98, 0x26, 0xa7, 0xaa, 0x5c, 0xd1, + 0x81, 0xd8, 0xc4, 0x45, 0x4d, 0x18, 0x0f, 0x23, 0xd2, 0x92, 0x1e, 0xde, 0x2b, 0xa3, 0x8d, 0x46, + 0xbc, 0x12, 0x62, 0x2f, 0x16, 0xfd, 0x17, 0x62, 0xce, 0x05, 0x7d, 0xd6, 0x82, 0xd9, 0xc8, 0xb8, + 0x48, 0x13, 0x62, 0x90, 0x8d, 0x24, 0x9a, 0x77, 0x74, 0x7c, 0x36, 0xcc, 0x32, 0x9c, 0x60, 0x9f, + 0x62, 0x86, 0x8e, 0x9f, 0xa0, 0x19, 0xfa, 0x32, 0x14, 0x9a, 0xce, 0xfd, 0x4a, 0x3b, 0xa8, 0x1f, + 0xdf, 0xdc, 0x15, 0xf7, 0x8c, 0x9c, 0x0a, 0x56, 0xf4, 0xd0, 0xc7, 0x2c, 0x6d, 0x71, 0x4d, 0x32, + 0xe2, 0xb7, 0xb3, 0x5d, 0x5c, 0x4a, 0x8b, 0xf7, 0x5d, 0x66, 0x3d, 0x46, 0x61, 0xe1, 0xa1, 0x1b, + 0x85, 0xd4, 0xc0, 0xe1, 0x0b, 0x44, 0x19, 0x38, 0x53, 0x27, 0x6a, 0xe0, 0xac, 0x19, 0xcc, 0x70, + 0x82, 0x39, 0x6b, 0x0f, 0x5f, 0x73, 0xaa, 0x3d, 0x70, 0xa2, 0xed, 0xa9, 0x18, 0xcc, 0x70, 0x82, + 0x79, 0xff, 0x93, 0x50, 0xf1, 0x64, 0x4e, 0x42, 0xd3, 0x19, 0x9c, 0x84, 0x8e, 0x36, 0x12, 0x67, + 0x46, 0x35, 0x12, 0xd1, 0x55, 0x40, 0xb5, 0x43, 0xcf, 0x69, 0xba, 0x55, 0xa1, 0x2c, 0xd9, 0x06, + 0x31, 0xcb, 0x4e, 0xca, 0xcb, 0x42, 0x91, 0xa1, 0xf5, 0x1e, 0x0c, 0x9c, 0x52, 0xcb, 0xfe, 0x0f, + 0x0b, 0xe6, 0xd7, 0x1a, 0x7e, 0xbb, 0x76, 0xdb, 0x89, 0xaa, 0xfb, 0xdc, 0x7b, 0x8e, 0x5e, 0x80, + 0x82, 0xeb, 0x45, 0x24, 0x38, 0x70, 0x1a, 0x42, 0xb7, 0xdb, 0xf2, 0x82, 0x61, 0x43, 0x94, 0xbf, + 0xde, 0x29, 0xcd, 0xae, 0xb7, 0x03, 0x16, 0x7f, 0xc0, 0x57, 0x3a, 0x56, 0x75, 0xd0, 0x97, 0x2d, + 0x58, 0xe0, 0xfe, 0xf7, 0x75, 0x27, 0x72, 0x6e, 0xb4, 0x49, 0xe0, 0x12, 0xe9, 0x81, 0x1f, 0x71, + 0x91, 0x27, 0xdb, 0x2a, 0x19, 0x1c, 0xc6, 0xe6, 0xd7, 0x56, 0x92, 0x33, 0xee, 0x6d, 0x8c, 0xfd, + 0xf9, 0x3c, 0x3c, 0xda, 0x97, 0x16, 0x5a, 0x86, 0x9c, 0x5b, 0x13, 0x5d, 0x07, 0x41, 0x37, 0xb7, + 0x51, 0xc3, 0x39, 0xb7, 0x86, 0x56, 0x98, 0x65, 0x12, 0x90, 0x30, 0x94, 0x1e, 0xea, 0x29, 0x65, + 0x44, 0x88, 0x52, 0xac, 0x61, 0xa0, 0x12, 0x8c, 0x37, 0x9c, 0x5d, 0xd2, 0x10, 0x56, 0x22, 0xb3, + 0x75, 0x36, 0x69, 0x01, 0xe6, 0xe5, 0xe8, 0x97, 0x2c, 0x00, 0xde, 0x40, 0x6a, 0x63, 0x8a, 0x1d, + 0x06, 0x67, 0x3b, 0x4c, 0x94, 0x32, 0x6f, 0x65, 0xfc, 0x1f, 0x6b, 0x5c, 0xd1, 0x0e, 0x4c, 0x50, + 0xb3, 0xc7, 0xaf, 0x1d, 0x7b, 0x43, 0x81, 0x6e, 0xa7, 0x34, 0xb1, 0xcd, 0x68, 0x60, 0x41, 0x8b, + 0x8e, 0x55, 0x40, 0xa2, 0x76, 0xe0, 0xd1, 0xa1, 0x65, 0x5b, 0x48, 0x81, 0xb7, 0x02, 0xab, 0x52, + 0xac, 0x61, 0xd8, 0x7f, 0x9c, 0x83, 0xc5, 0xb4, 0xa6, 0x53, 0x4d, 0x3d, 0xc1, 0x5b, 0x2b, 0x0e, + 0x3c, 0xef, 0xca, 0x7e, 0x7c, 0xc4, 0x55, 0x92, 0x0a, 0xde, 0x10, 0x57, 0xbd, 0x82, 0x2f, 0x7a, + 0x97, 0x1a, 0xa1, 0xdc, 0x31, 0x47, 0x48, 0x51, 0x4e, 0x8c, 0xd2, 0x13, 0x30, 0x16, 0xd2, 0x99, + 0xcf, 0x9b, 0x17, 0x00, 0x6c, 0x8e, 0x18, 0x84, 0x62, 0xb4, 0x3d, 0x37, 0x12, 0x41, 0x41, 0x0a, + 0xe3, 0xa6, 0xe7, 0x46, 0x98, 0x41, 0xec, 0x2f, 0xe6, 0x60, 0xb9, 0x7f, 0xa7, 0xd0, 0x17, 0x2d, + 0x80, 0x1a, 0x35, 0x6a, 0xa9, 0x48, 0xca, 0xab, 0x37, 0xe7, 0xa4, 0xc6, 0x70, 0x5d, 0x72, 0x8a, + 0xef, 0x61, 0x55, 0x51, 0x88, 0xb5, 0x86, 0xa0, 0x8b, 0x52, 0xf4, 0xaf, 0x39, 0x4d, 0x69, 0x0a, + 0xaa, 0x3a, 0x5b, 0x0a, 0x82, 0x35, 0x2c, 0x7a, 0x6a, 0xf1, 0x9c, 0x26, 0x09, 0x5b, 0x8e, 0x0a, + 0xb1, 0x62, 0xa7, 0x96, 0x6b, 0xb2, 0x10, 0xc7, 0x70, 0xbb, 0x01, 0x4f, 0x0e, 0xd0, 0xce, 0x8c, + 0x22, 0x70, 0xec, 0x1f, 0x5a, 0x70, 0x66, 0xad, 0xd1, 0x0e, 0x23, 0x12, 0xfc, 0x9f, 0xb9, 0xd6, + 0xfe, 0x4f, 0x0b, 0x1e, 0xeb, 0xd3, 0xe7, 0x87, 0x70, 0xbb, 0xfd, 0xaa, 0x79, 0xbb, 0x7d, 0x73, + 0x54, 0x91, 0x4e, 0xed, 0x47, 0x9f, 0x4b, 0xee, 0x08, 0x66, 0xa8, 0xd6, 0xaa, 0xf9, 0xf5, 0x8c, + 0xf6, 0xcd, 0x27, 0x61, 0xfc, 0x03, 0x74, 0xff, 0x49, 0xca, 0x18, 0xdb, 0x94, 0x30, 0x87, 0xd9, + 0x7f, 0x9f, 0x03, 0xed, 0xbc, 0xfa, 0x10, 0xc4, 0xca, 0x33, 0xc4, 0x6a, 0xc4, 0x13, 0xa8, 0x76, + 0xfa, 0xee, 0x17, 0x9e, 0x77, 0x90, 0x08, 0xcf, 0xbb, 0x96, 0x19, 0xc7, 0xa3, 0xa3, 0xf3, 0x5e, + 0xb3, 0xe0, 0xb1, 0x18, 0xb9, 0xd7, 0xf5, 0xf3, 0x60, 0x1d, 0xf1, 0x2c, 0x14, 0x9d, 0xb8, 0x9a, + 0x98, 0x45, 0x15, 0xfe, 0xa9, 0x51, 0xc4, 0x3a, 0x5e, 0x1c, 0x21, 0x95, 0x3f, 0x66, 0x84, 0xd4, + 0xd8, 0xd1, 0x11, 0x52, 0xf6, 0x8f, 0x72, 0x70, 0xb6, 0xb7, 0x67, 0x52, 0xba, 0x31, 0xd9, 0x1b, + 0xa0, 0x6f, 0xcf, 0xc1, 0x74, 0x24, 0x2a, 0x68, 0xba, 0x7a, 0x51, 0x60, 0x4e, 0xef, 0x68, 0x30, + 0x6c, 0x60, 0xd2, 0x9a, 0x55, 0xbe, 0xae, 0x2a, 0x55, 0xbf, 0x25, 0x43, 0xc9, 0x54, 0xcd, 0x35, + 0x0d, 0x86, 0x0d, 0x4c, 0x15, 0xbb, 0x31, 0x76, 0xe2, 0xb1, 0x6e, 0x15, 0x38, 0x2d, 0xaf, 0xf0, + 0x2f, 0xfb, 0xc1, 0x9a, 0xdf, 0x6c, 0x35, 0x08, 0x8b, 0x40, 0x18, 0x67, 0x8d, 0x3d, 0x2b, 0xaa, + 0x9c, 0xc6, 0x69, 0x48, 0x38, 0xbd, 0xae, 0xfd, 0x5a, 0x1e, 0x4e, 0xc5, 0xc3, 0xbe, 0xe6, 0x7b, + 0x35, 0x97, 0x05, 0x42, 0x3c, 0x0f, 0x63, 0xd1, 0x61, 0x4b, 0x0e, 0xf6, 0x4f, 0xc9, 0xe6, 0xec, + 0x1c, 0xb6, 0xe8, 0x6c, 0x9f, 0x49, 0xa9, 0x42, 0x41, 0x98, 0x55, 0x42, 0x9b, 0x6a, 0x75, 0xf0, + 0x19, 0x78, 0xc6, 0x94, 0xe6, 0xd7, 0x3b, 0xa5, 0x94, 0xa0, 0xef, 0x15, 0x45, 0xc9, 0x94, 0x79, + 0x74, 0x07, 0x66, 0x1b, 0x4e, 0x18, 0xdd, 0x6c, 0xd5, 0x9c, 0x88, 0xec, 0xb8, 0x4d, 0x22, 0xd6, + 0xdc, 0x30, 0x61, 0x6b, 0xea, 0xb6, 0x70, 0xd3, 0xa0, 0x84, 0x13, 0x94, 0xd1, 0x01, 0x20, 0x5a, + 0xb2, 0x13, 0x38, 0x5e, 0xc8, 0x7b, 0x45, 0xf9, 0x0d, 0x1f, 0x26, 0xa7, 0x8e, 0x38, 0x9b, 0x3d, + 0xd4, 0x70, 0x0a, 0x07, 0xf4, 0x14, 0x4c, 0x04, 0xc4, 0x09, 0xc5, 0x64, 0x4e, 0xc5, 0xeb, 0x1f, + 0xb3, 0x52, 0x2c, 0xa0, 0xfa, 0x82, 0x9a, 0x78, 0xc0, 0x82, 0xfa, 0xae, 0x05, 0xb3, 0xf1, 0x34, + 0x3d, 0x84, 0x6d, 0xae, 0x69, 0x6e, 0x73, 0x57, 0xb2, 0x52, 0x89, 0x7d, 0x76, 0xb6, 0xaf, 0x8e, + 0xe9, 0xfd, 0x63, 0x81, 0x5b, 0x1f, 0x84, 0x29, 0xb9, 0xaa, 0xa5, 0xfd, 0x38, 0xa2, 0x9f, 0xc4, + 0xb0, 0x2c, 0xb4, 0xc8, 0x52, 0xc1, 0x04, 0xc7, 0xfc, 0xe8, 0xc6, 0x5a, 0x13, 0x9b, 0xa6, 0x10, + 0x7b, 0xb5, 0xb1, 0xca, 0xcd, 0x34, 0x6d, 0x63, 0x95, 0x75, 0xd0, 0x4d, 0x38, 0xd3, 0x0a, 0x7c, + 0x16, 0xda, 0xbf, 0x4e, 0x9c, 0x5a, 0xc3, 0xf5, 0x88, 0x3c, 0x8e, 0xf3, 0xcb, 0xea, 0xc7, 0xba, + 0x9d, 0xd2, 0x99, 0xed, 0x74, 0x14, 0xdc, 0xaf, 0xae, 0x19, 0x21, 0x3b, 0xf6, 0xe0, 0x08, 0x59, + 0xf4, 0x2b, 0xca, 0xe9, 0x45, 0xc2, 0xa5, 0x71, 0x36, 0x88, 0xef, 0xc9, 0x6a, 0x2a, 0x53, 0xd4, + 0x7a, 0x2c, 0x52, 0xab, 0x82, 0x29, 0x56, 0xec, 0xfb, 0x7b, 0x56, 0x26, 0x8e, 0xe7, 0x59, 0xb1, + 0x3f, 0x31, 0x0e, 0xf3, 0xc9, 0xcd, 0xf6, 0xe4, 0xa3, 0x7f, 0x7f, 0xdd, 0x82, 0x79, 0x29, 0x28, + 0x9c, 0x27, 0x91, 0xee, 0xe1, 0xcd, 0x8c, 0xe4, 0x93, 0x9b, 0x0d, 0xea, 0x29, 0xc6, 0x4e, 0x82, + 0x1b, 0xee, 0xe1, 0x8f, 0x5e, 0x81, 0xa2, 0xf2, 0xa2, 0x1e, 0x2b, 0x14, 0x78, 0x8e, 0x19, 0x0c, + 0x31, 0x09, 0xac, 0xd3, 0x43, 0x9f, 0xb0, 0x00, 0xaa, 0x52, 0xa3, 0x4b, 0x41, 0xba, 0x91, 0x95, + 0x20, 0xa9, 0xbd, 0x22, 0xb6, 0x0b, 0x55, 0x51, 0x88, 0x35, 0xc6, 0xe8, 0xf3, 0xcc, 0x7f, 0xaa, + 0x0c, 0x19, 0x2a, 0x3a, 0xb4, 0x25, 0xef, 0xce, 0x5a, 0xa4, 0xe3, 0xab, 0x3c, 0x65, 0x35, 0x68, + 0xa0, 0x10, 0x1b, 0x8d, 0xb0, 0x9f, 0x07, 0x15, 0xba, 0x45, 0x57, 0x28, 0x0b, 0xde, 0xda, 0x76, + 0xa2, 0x7d, 0x21, 0x82, 0x6a, 0x85, 0x5e, 0x96, 0x00, 0x1c, 0xe3, 0xd8, 0xef, 0x87, 0xd9, 0x17, + 0x03, 0xa7, 0xb5, 0xef, 0x32, 0x3f, 0x25, 0x35, 0xea, 0xdf, 0x0c, 0x93, 0x4e, 0xad, 0x96, 0xf6, + 0x6a, 0x68, 0x95, 0x17, 0x63, 0x09, 0x1f, 0xcc, 0x7e, 0xff, 0x0b, 0x0b, 0x16, 0x37, 0xc2, 0xc8, + 0xf5, 0xd7, 0x49, 0x18, 0x51, 0xb5, 0x40, 0x2d, 0x88, 0x76, 0x83, 0x0c, 0x60, 0x83, 0xad, 0xc3, + 0xbc, 0xb8, 0x4c, 0x69, 0xef, 0x86, 0x24, 0xd2, 0xec, 0x30, 0x25, 0x9c, 0x6b, 0x09, 0x38, 0xee, + 0xa9, 0x41, 0xa9, 0x88, 0x5b, 0x95, 0x98, 0x4a, 0xde, 0xa4, 0x52, 0x49, 0xc0, 0x71, 0x4f, 0x0d, + 0xfb, 0x5b, 0x79, 0x38, 0xc5, 0xba, 0x91, 0x78, 0x69, 0xf4, 0x19, 0x0b, 0x66, 0x0f, 0xdc, 0x20, + 0x6a, 0x3b, 0x0d, 0xfd, 0x7a, 0x68, 0x64, 0xf9, 0x64, 0xbc, 0x6e, 0x19, 0x84, 0xb9, 0x03, 0xd9, + 0x2c, 0xc3, 0x09, 0xe6, 0xe8, 0xd7, 0x2c, 0x98, 0xab, 0x99, 0x23, 0x9d, 0xcd, 0x01, 0x39, 0x6d, + 0x0e, 0x79, 0x54, 0x43, 0xa2, 0x10, 0x27, 0xf9, 0xa3, 0x2f, 0x58, 0x30, 0x67, 0x36, 0x53, 0xaa, + 0xac, 0x13, 0x18, 0x24, 0x15, 0x86, 0x68, 0x96, 0x87, 0x38, 0xd9, 0x04, 0xfb, 0x6f, 0x2d, 0x31, + 0xa5, 0x26, 0xe6, 0x00, 0x82, 0x69, 0xc3, 0x44, 0xe0, 0xb7, 0x23, 0xe1, 0xe4, 0x9d, 0xe2, 0xbe, + 0x40, 0xcc, 0x4a, 0xb0, 0x80, 0xa0, 0x7b, 0x30, 0x15, 0x35, 0x42, 0x5e, 0x28, 0x7a, 0x3b, 0xa2, + 0x45, 0xbf, 0xb3, 0x59, 0x61, 0xe4, 0xb4, 0x4d, 0x57, 0x94, 0x50, 0xe3, 0x41, 0xf2, 0xb2, 0xbf, + 0x62, 0xc1, 0xd4, 0x55, 0x7f, 0x57, 0x2c, 0xe7, 0xf7, 0x65, 0x70, 0x5e, 0x56, 0xdb, 0xaa, 0xba, + 0xb6, 0x88, 0x2d, 0xb5, 0x17, 0x8c, 0xd3, 0xf2, 0xe3, 0x1a, 0xed, 0x15, 0xf6, 0x4c, 0x93, 0x92, + 0xba, 0xea, 0xef, 0xf6, 0x75, 0xa7, 0xfc, 0xf6, 0x38, 0xcc, 0xbc, 0xe4, 0x1c, 0x12, 0x2f, 0x72, + 0x86, 0x57, 0x40, 0xf4, 0x00, 0xda, 0x62, 0x51, 0x75, 0x9a, 0xa9, 0x14, 0x1f, 0x40, 0x63, 0x10, + 0xd6, 0xf1, 0x62, 0xbd, 0xb2, 0xe6, 0x7b, 0x7b, 0x6e, 0x3d, 0x4d, 0x23, 0xac, 0x25, 0xe0, 0xb8, + 0xa7, 0x06, 0xba, 0x0a, 0x48, 0x04, 0xdd, 0xaf, 0x56, 0xab, 0x7e, 0xdb, 0xe3, 0x9a, 0x85, 0x9f, + 0x4d, 0x95, 0xcd, 0xbe, 0xd5, 0x83, 0x81, 0x53, 0x6a, 0xa1, 0xf7, 0xc2, 0x52, 0x95, 0x51, 0x16, + 0x16, 0x9c, 0x4e, 0x91, 0x5b, 0xf1, 0x2a, 0xa2, 0x75, 0xad, 0x0f, 0x1e, 0xee, 0x4b, 0x81, 0xb6, + 0x34, 0x8c, 0xfc, 0xc0, 0xa9, 0x13, 0x9d, 0xee, 0x84, 0xd9, 0xd2, 0x4a, 0x0f, 0x06, 0x4e, 0xa9, + 0x85, 0x3e, 0x02, 0x53, 0xd1, 0x7e, 0x40, 0xc2, 0x7d, 0xbf, 0x51, 0x13, 0xf7, 0x98, 0x23, 0x3a, + 0x2c, 0xc4, 0xec, 0xef, 0x48, 0xaa, 0x9a, 0x78, 0xcb, 0x22, 0x1c, 0xf3, 0x44, 0x01, 0x4c, 0x84, + 0xf4, 0xb4, 0x1c, 0x2e, 0x15, 0xb2, 0xb0, 0xca, 0x05, 0x77, 0x76, 0x00, 0xd7, 0x5c, 0x25, 0x8c, + 0x03, 0x16, 0x9c, 0xec, 0x6f, 0xe4, 0x60, 0x5a, 0x47, 0x1c, 0x40, 0x45, 0x7c, 0xdc, 0x82, 0xe9, + 0xaa, 0xef, 0x45, 0x81, 0xdf, 0xe0, 0x6e, 0x00, 0xbe, 0x40, 0x46, 0x7c, 0xb4, 0xc7, 0x48, 0xad, + 0x93, 0xc8, 0x71, 0x1b, 0x9a, 0x47, 0x41, 0x63, 0x83, 0x0d, 0xa6, 0xe8, 0xd3, 0x16, 0xcc, 0xc5, + 0x01, 0x1e, 0xb1, 0x3f, 0x22, 0xd3, 0x86, 0x28, 0x8d, 0x7b, 0xc9, 0xe4, 0x84, 0x93, 0xac, 0xed, + 0x5d, 0x98, 0x4f, 0xce, 0x36, 0x1d, 0xca, 0x96, 0x23, 0xd6, 0x7a, 0x3e, 0x1e, 0xca, 0x6d, 0x27, + 0x0c, 0x31, 0x83, 0xa0, 0xb7, 0x40, 0xa1, 0xe9, 0x04, 0x75, 0xd7, 0x73, 0x1a, 0x6c, 0x14, 0xf3, + 0x9a, 0x42, 0x12, 0xe5, 0x58, 0x61, 0xd8, 0x3f, 0x18, 0x83, 0xe2, 0x16, 0x71, 0xc2, 0x76, 0x40, + 0x98, 0xc3, 0xf0, 0xc4, 0x2d, 0x72, 0xe3, 0x15, 0x5c, 0x3e, 0xbb, 0x57, 0x70, 0xe8, 0x65, 0x80, + 0x3d, 0xd7, 0x73, 0xc3, 0xfd, 0x63, 0xbe, 0xaf, 0x63, 0x37, 0x4f, 0x97, 0x15, 0x05, 0xac, 0x51, + 0x8b, 0xdd, 0xfb, 0xe3, 0x47, 0x3c, 0xb0, 0xfd, 0x84, 0xa5, 0x6d, 0x1e, 0x13, 0x59, 0x5c, 0x67, + 0x6a, 0x13, 0xb3, 0x22, 0x37, 0x93, 0x4b, 0x5e, 0x14, 0x1c, 0x1e, 0xb9, 0xc7, 0xec, 0x40, 0x21, + 0x20, 0x61, 0xbb, 0x49, 0xcf, 0x16, 0x93, 0x43, 0x0f, 0x03, 0x8b, 0x86, 0xc0, 0xa2, 0x3e, 0x56, + 0x94, 0x96, 0x9f, 0x87, 0x19, 0xa3, 0x09, 0x68, 0x1e, 0xf2, 0x77, 0xc9, 0x21, 0x97, 0x13, 0x4c, + 0x7f, 0xa2, 0x45, 0xe3, 0x12, 0x44, 0x0c, 0xcb, 0x3b, 0x72, 0xcf, 0x59, 0xf6, 0x8f, 0x26, 0x40, + 0x5c, 0x98, 0x0d, 0xa0, 0x0b, 0x74, 0x3f, 0x79, 0xee, 0x18, 0x7e, 0xf2, 0xab, 0x30, 0xed, 0x7a, + 0x6e, 0xe4, 0x3a, 0x0d, 0x76, 0x00, 0x15, 0x7b, 0xd5, 0x53, 0x72, 0xfd, 0x6f, 0x68, 0xb0, 0x14, + 0x3a, 0x46, 0x5d, 0x74, 0x03, 0xc6, 0x99, 0x32, 0x17, 0xf2, 0x34, 0xfc, 0xad, 0x1e, 0xbb, 0xd0, + 0xe5, 0x91, 0xed, 0x9c, 0x12, 0x33, 0xb0, 0xf9, 0x93, 0x47, 0x75, 0x6e, 0x12, 0x62, 0x15, 0x1b, + 0xd8, 0x09, 0x38, 0xee, 0xa9, 0x41, 0xa9, 0xec, 0x39, 0x6e, 0xa3, 0x1d, 0x90, 0x98, 0xca, 0x84, + 0x49, 0xe5, 0x72, 0x02, 0x8e, 0x7b, 0x6a, 0xa0, 0x3d, 0x98, 0x16, 0x65, 0x3c, 0xbe, 0x61, 0xf2, + 0x98, 0xbd, 0x64, 0x71, 0x2c, 0x97, 0x35, 0x4a, 0xd8, 0xa0, 0x8b, 0xda, 0xb0, 0xe0, 0x7a, 0x55, + 0xdf, 0xab, 0x36, 0xda, 0xa1, 0x7b, 0x40, 0xe2, 0xb0, 0xf2, 0xe3, 0x30, 0x3b, 0xdd, 0xed, 0x94, + 0x16, 0x36, 0x92, 0xe4, 0x70, 0x2f, 0x07, 0xf4, 0x31, 0x0b, 0x4e, 0x57, 0x7d, 0x2f, 0x64, 0x0f, + 0xab, 0x0e, 0xc8, 0xa5, 0x20, 0xf0, 0x03, 0xce, 0x7b, 0xea, 0x98, 0xbc, 0x99, 0xdf, 0x63, 0x2d, + 0x8d, 0x24, 0x4e, 0xe7, 0x84, 0x5e, 0x85, 0x42, 0x2b, 0xf0, 0x0f, 0xdc, 0x1a, 0x09, 0x44, 0xac, + 0xcc, 0x66, 0x16, 0x6f, 0x1a, 0xb7, 0x05, 0xcd, 0x58, 0x13, 0xc8, 0x12, 0xac, 0xf8, 0xd9, 0xbf, + 0x5f, 0x80, 0x59, 0x13, 0x1d, 0x7d, 0x18, 0xa0, 0x15, 0xf8, 0x4d, 0x12, 0xed, 0x13, 0x15, 0x1e, + 0x7c, 0x6d, 0xd4, 0xf7, 0x84, 0x92, 0x9e, 0xbc, 0x23, 0xa7, 0x9a, 0x34, 0x2e, 0xc5, 0x1a, 0x47, + 0x14, 0xc0, 0xe4, 0x5d, 0xbe, 0xa7, 0x89, 0x2d, 0xfe, 0xa5, 0x4c, 0x0c, 0x12, 0xc1, 0x99, 0xc5, + 0xb5, 0x8a, 0x22, 0x2c, 0x19, 0xa1, 0x5d, 0xc8, 0xdf, 0x23, 0xbb, 0xd9, 0xbc, 0x7c, 0xbb, 0x4d, + 0xc4, 0x51, 0xa1, 0x3c, 0xd9, 0xed, 0x94, 0xf2, 0xb7, 0xc9, 0x2e, 0xa6, 0xc4, 0x69, 0xbf, 0x6a, + 0xfc, 0xb6, 0x4f, 0xa8, 0x8a, 0x11, 0xfb, 0x65, 0x5c, 0x1d, 0xf2, 0x7e, 0x89, 0x22, 0x2c, 0x19, + 0xa1, 0x57, 0x61, 0xea, 0x9e, 0x73, 0x40, 0xf6, 0x02, 0xdf, 0x8b, 0x44, 0x60, 0xc6, 0x88, 0x11, + 0xa8, 0xb7, 0x25, 0x39, 0xc1, 0x97, 0xed, 0xb6, 0xaa, 0x10, 0xc7, 0xec, 0xd0, 0x01, 0x14, 0x3c, + 0x72, 0x0f, 0x93, 0x86, 0x5b, 0x15, 0xc1, 0x7f, 0x23, 0x8a, 0xf5, 0x35, 0x41, 0x4d, 0x70, 0x66, + 0xdb, 0x90, 0x2c, 0xc3, 0x8a, 0x17, 0x9d, 0xcb, 0x3b, 0xfe, 0xae, 0x50, 0x54, 0x23, 0xce, 0xa5, + 0x3a, 0xf6, 0xf1, 0xb9, 0xbc, 0xea, 0xef, 0x62, 0x4a, 0x9c, 0xae, 0x91, 0xaa, 0x8a, 0x0a, 0x10, + 0x6a, 0xea, 0x5a, 0xb6, 0xd1, 0x10, 0x7c, 0x8d, 0xc4, 0xa5, 0x58, 0xe3, 0x48, 0xc7, 0xb6, 0x2e, + 0xbc, 0x4c, 0x42, 0x51, 0x8d, 0x38, 0xb6, 0xa6, 0xcf, 0x8a, 0x8f, 0xad, 0x2c, 0xc3, 0x8a, 0x97, + 0xfd, 0x27, 0x63, 0x30, 0xad, 0x67, 0x30, 0x18, 0x60, 0xaf, 0x56, 0xe6, 0x62, 0x6e, 0x18, 0x73, + 0x91, 0x5a, 0xfb, 0xcd, 0xd8, 0xb6, 0x91, 0x07, 0xfe, 0x8d, 0xcc, 0xac, 0xa5, 0xd8, 0xda, 0xd7, + 0x0a, 0x43, 0x6c, 0x30, 0x1d, 0xe2, 0x8a, 0x94, 0xda, 0x7f, 0xdc, 0x0c, 0xe0, 0x4f, 0xc4, 0x94, + 0xfd, 0x67, 0x6c, 0xec, 0x17, 0x01, 0xe2, 0x5c, 0x06, 0xc2, 0x4f, 0xae, 0x7c, 0xa4, 0x5a, 0x8e, + 0x05, 0x0d, 0x0b, 0x3d, 0x05, 0x13, 0x74, 0xa3, 0x24, 0x35, 0xf1, 0x76, 0x4b, 0x1d, 0xa9, 0x2e, + 0xb3, 0x52, 0x2c, 0xa0, 0xe8, 0x39, 0x6a, 0xd3, 0xc4, 0xdb, 0x9b, 0x78, 0x92, 0xb5, 0x18, 0xdb, + 0x34, 0x31, 0x0c, 0x1b, 0x98, 0xb4, 0xe9, 0x84, 0xee, 0x46, 0x4c, 0x92, 0xb4, 0xa6, 0xb3, 0x2d, + 0x0a, 0x73, 0x18, 0x3b, 0xe2, 0x27, 0x76, 0x2f, 0xb6, 0x59, 0x8d, 0x6b, 0x47, 0xfc, 0x04, 0x1c, + 0xf7, 0xd4, 0xb0, 0xdf, 0x0f, 0xb3, 0xe6, 0x2a, 0xa6, 0x43, 0xdc, 0x0a, 0xfc, 0x3d, 0xb7, 0x41, + 0x92, 0xce, 0x89, 0x6d, 0x5e, 0x8c, 0x25, 0x7c, 0x30, 0xef, 0xe8, 0x5f, 0xe6, 0xe1, 0xd4, 0xb5, + 0xba, 0xeb, 0xdd, 0x4f, 0xb8, 0x15, 0xd3, 0x52, 0x24, 0x59, 0xc3, 0xa6, 0x48, 0x8a, 0x83, 0xcf, + 0x45, 0xc2, 0xa7, 0xf4, 0xe0, 0x73, 0x99, 0x0d, 0xca, 0xc4, 0x45, 0xdf, 0xb5, 0xe0, 0x71, 0xa7, + 0xc6, 0xed, 0x2a, 0xa7, 0x21, 0x4a, 0x63, 0xa6, 0x52, 0xc6, 0xc3, 0x11, 0xb5, 0x64, 0x6f, 0xe7, + 0x57, 0x56, 0x8f, 0xe0, 0xca, 0x4f, 0x0b, 0x6f, 0x12, 0x3d, 0x78, 0xfc, 0x28, 0x54, 0x7c, 0x64, + 0xf3, 0x97, 0xaf, 0xc3, 0x1b, 0x1f, 0xc8, 0x68, 0xa8, 0x33, 0xc1, 0xc7, 0x2d, 0x98, 0xe2, 0x5e, + 0x33, 0x4c, 0xf6, 0xe8, 0xe2, 0x71, 0x5a, 0xee, 0x2d, 0x12, 0x84, 0x32, 0xcf, 0x81, 0x16, 0xea, + 0xb5, 0xba, 0xbd, 0x21, 0x20, 0x58, 0xc3, 0xa2, 0xea, 0xe9, 0xae, 0xeb, 0xd5, 0xc4, 0x34, 0x29, + 0xf5, 0xf4, 0x92, 0xeb, 0xd5, 0x30, 0x83, 0x28, 0x05, 0x96, 0xef, 0xa7, 0xc0, 0xec, 0xdf, 0xb1, + 0x60, 0x96, 0xbd, 0x2d, 0x89, 0x8d, 0xe2, 0x67, 0xd5, 0x8d, 0x30, 0x6f, 0xc6, 0x59, 0xf3, 0x46, + 0xf8, 0xf5, 0x4e, 0xa9, 0xc8, 0x5f, 0xa3, 0x98, 0x17, 0xc4, 0xef, 0x11, 0x07, 0x5b, 0x76, 0x6f, + 0x9d, 0x1b, 0xfa, 0xdc, 0xa5, 0xdc, 0x38, 0x15, 0x49, 0x04, 0xc7, 0xf4, 0xec, 0x3f, 0xcc, 0xc3, + 0xa9, 0x94, 0x20, 0x69, 0x7a, 0xe6, 0x9c, 0x60, 0x71, 0xa2, 0xf2, 0xd6, 0xf5, 0x95, 0xcc, 0x03, + 0xb1, 0x57, 0x58, 0x38, 0xaa, 0x90, 0x24, 0xa5, 0x9f, 0x78, 0x21, 0x16, 0xcc, 0xd1, 0x6f, 0x58, + 0x50, 0x74, 0x34, 0x61, 0xe7, 0x17, 0xd1, 0xbb, 0xd9, 0x37, 0xa6, 0x47, 0xb6, 0xb5, 0x00, 0x9a, + 0x58, 0x94, 0xf5, 0xb6, 0x2c, 0xff, 0x3c, 0x14, 0xb5, 0x2e, 0x0c, 0x23, 0xa3, 0xcb, 0x2f, 0xc0, + 0xfc, 0x48, 0x32, 0xfe, 0x6e, 0x18, 0x36, 0x71, 0x06, 0xdd, 0x11, 0xee, 0xe9, 0x4f, 0xae, 0xd4, + 0x88, 0x8b, 0x37, 0x57, 0x02, 0x6a, 0xef, 0xc2, 0x7c, 0xd2, 0xf0, 0xce, 0xfc, 0x32, 0xea, 0x6d, + 0x30, 0x64, 0xaa, 0x0b, 0xfb, 0xaf, 0x72, 0x30, 0x29, 0x5e, 0x5a, 0x3c, 0x84, 0xd8, 0xb3, 0xbb, + 0x86, 0x37, 0x7d, 0x23, 0x93, 0x07, 0x22, 0x7d, 0x03, 0xcf, 0xc2, 0x44, 0xe0, 0xd9, 0x4b, 0xd9, + 0xb0, 0x3b, 0x3a, 0xea, 0xec, 0xb3, 0x39, 0x98, 0x4b, 0xbc, 0x5c, 0x41, 0x9f, 0xb4, 0x7a, 0x83, + 0x2d, 0x6e, 0x66, 0xfa, 0x38, 0x46, 0x45, 0x36, 0x1e, 0x1d, 0x77, 0x11, 0x1a, 0xc9, 0x73, 0x6e, + 0x64, 0x96, 0x60, 0xed, 0xc8, 0x3c, 0x3a, 0xff, 0x6c, 0xc1, 0xa3, 0x7d, 0xdf, 0xf2, 0xb0, 0x47, + 0xca, 0x81, 0x09, 0x15, 0xb2, 0x97, 0xf1, 0xdb, 0x3c, 0xe5, 0xc5, 0x4d, 0xbe, 0x2b, 0x4d, 0xb2, + 0x47, 0xcf, 0xc0, 0x34, 0xd3, 0xe3, 0x74, 0xf9, 0x44, 0xa4, 0x25, 0x32, 0x63, 0x31, 0x8f, 0x49, + 0x45, 0x2b, 0xc7, 0x06, 0x96, 0xfd, 0x65, 0x0b, 0x96, 0xfa, 0x3d, 0x59, 0x1d, 0xc0, 0x2e, 0xff, + 0xb9, 0x44, 0x1c, 0x58, 0xa9, 0x27, 0x0e, 0x2c, 0x61, 0x99, 0xcb, 0x90, 0x2f, 0xcd, 0x28, 0xce, + 0x3f, 0x20, 0xcc, 0xe9, 0x33, 0x16, 0x9c, 0xe9, 0x23, 0x38, 0x3d, 0xf1, 0x80, 0xd6, 0xb1, 0xe3, + 0x01, 0x73, 0x83, 0xc6, 0x03, 0xda, 0x7f, 0x93, 0x87, 0x79, 0xd1, 0x9e, 0x78, 0x33, 0x7f, 0xce, + 0x88, 0xa6, 0x7b, 0x53, 0x22, 0x9a, 0x6e, 0x31, 0x89, 0xff, 0xff, 0xa1, 0x74, 0x3f, 0x59, 0xa1, + 0x74, 0x3f, 0xce, 0xc1, 0xe9, 0xd4, 0x97, 0xb9, 0xe8, 0x53, 0x29, 0x5a, 0xf0, 0x76, 0xc6, 0x4f, + 0x80, 0x07, 0xd4, 0x83, 0xa3, 0xc6, 0x9f, 0x7d, 0x41, 0x8f, 0xfb, 0xe2, 0xc7, 0x84, 0xbd, 0x13, + 0x78, 0xcc, 0x3c, 0x64, 0x08, 0x98, 0xfd, 0xab, 0x79, 0x38, 0x3f, 0x28, 0xa1, 0x9f, 0xd0, 0x10, + 0xe1, 0xd0, 0x08, 0x11, 0x7e, 0x38, 0x3b, 0xd4, 0xc9, 0x44, 0x0b, 0x7f, 0x25, 0xaf, 0xb6, 0xbd, + 0x5e, 0xf9, 0x1c, 0xe8, 0x52, 0x65, 0x92, 0x5a, 0x31, 0x32, 0x19, 0x56, 0xac, 0x0a, 0x27, 0x2b, + 0xbc, 0xf8, 0xf5, 0x4e, 0x69, 0x41, 0xe4, 0xdc, 0xa9, 0x90, 0x48, 0x14, 0x62, 0x59, 0x09, 0x9d, + 0x87, 0x42, 0xc0, 0xa1, 0x32, 0x28, 0x52, 0x5c, 0x14, 0xf1, 0x32, 0xac, 0xa0, 0xe8, 0x23, 0x9a, + 0xd9, 0x37, 0x76, 0x52, 0x8f, 0x43, 0x8f, 0xba, 0xff, 0x7a, 0x05, 0x0a, 0xa1, 0xcc, 0x94, 0xc5, + 0xbd, 0xa2, 0x4f, 0x0f, 0x18, 0x6b, 0x4b, 0x4f, 0x09, 0x32, 0x6d, 0x16, 0xef, 0x9f, 0x4a, 0xaa, + 0xa5, 0x48, 0x22, 0x5b, 0x19, 0xe8, 0xdc, 0xc5, 0x03, 0x29, 0xc6, 0xf9, 0x6b, 0x16, 0x14, 0xc5, + 0x6c, 0x3d, 0x84, 0xf0, 0xdf, 0x3b, 0x66, 0xf8, 0xef, 0xa5, 0x4c, 0x74, 0x47, 0x9f, 0xd8, 0xdf, + 0x3b, 0x30, 0xad, 0x27, 0x67, 0x40, 0x2f, 0x6b, 0xba, 0xcf, 0x1a, 0xe5, 0x11, 0xb8, 0xd4, 0x8e, + 0xb1, 0x5e, 0xb4, 0xbf, 0x54, 0x50, 0xa3, 0xc8, 0x82, 0x8c, 0x75, 0x19, 0xb4, 0x8e, 0x94, 0x41, + 0x5d, 0x04, 0x72, 0xd9, 0x8b, 0xc0, 0x0d, 0x28, 0x48, 0x05, 0x25, 0xb6, 0xf1, 0x27, 0xf5, 0x48, + 0x1e, 0x6a, 0x0b, 0x50, 0x62, 0x9a, 0xe0, 0xb2, 0x53, 0x85, 0x9a, 0x43, 0xa5, 0x38, 0x15, 0x19, + 0xf4, 0x2a, 0x14, 0xef, 0xf9, 0xc1, 0xdd, 0x86, 0xef, 0xb0, 0x84, 0x75, 0x90, 0x85, 0x7f, 0x5b, + 0x79, 0x57, 0x78, 0xc0, 0xe8, 0xed, 0x98, 0x3e, 0xd6, 0x99, 0xa1, 0x55, 0x98, 0x6b, 0xba, 0x1e, + 0x26, 0x4e, 0x4d, 0x45, 0xf9, 0x8e, 0xf1, 0x24, 0x5d, 0xd2, 0xc8, 0xdd, 0x32, 0xc1, 0x38, 0x89, + 0x8f, 0x3e, 0x08, 0x85, 0x50, 0x24, 0x80, 0xc8, 0xe6, 0x26, 0x42, 0x1d, 0x8f, 0x38, 0xd1, 0x78, + 0xec, 0x64, 0x09, 0x56, 0x0c, 0xd1, 0x26, 0x2c, 0x06, 0xe2, 0x89, 0xb5, 0x91, 0x83, 0x96, 0xaf, + 0x4f, 0x96, 0x0b, 0x0a, 0xa7, 0xc0, 0x71, 0x6a, 0x2d, 0x6a, 0xc5, 0xb0, 0x2c, 0x23, 0xdc, 0x25, + 0x5b, 0xd0, 0xde, 0x65, 0xb2, 0x52, 0x2c, 0xa0, 0x47, 0x45, 0x8d, 0x17, 0x46, 0x88, 0x1a, 0xaf, + 0xc0, 0xe9, 0x24, 0x88, 0x3d, 0x04, 0x67, 0x6f, 0xcf, 0xb5, 0xdd, 0x63, 0x3b, 0x0d, 0x09, 0xa7, + 0xd7, 0x45, 0xb7, 0x61, 0x2a, 0x20, 0xec, 0x7c, 0xb1, 0x2a, 0xef, 0x3e, 0x87, 0x0e, 0xba, 0xc0, + 0x92, 0x00, 0x8e, 0x69, 0xd1, 0x79, 0x77, 0xcc, 0x3c, 0x55, 0x37, 0x32, 0x4c, 0x97, 0x2e, 0xe6, + 0xbe, 0x4f, 0x82, 0x06, 0xfb, 0xbf, 0x66, 0x60, 0xc6, 0x38, 0x46, 0xa3, 0x27, 0x61, 0x9c, 0xbd, + 0x8c, 0x67, 0xea, 0xa1, 0x10, 0xab, 0x30, 0x3e, 0x38, 0x1c, 0x86, 0x3e, 0x6b, 0xc1, 0x5c, 0xcb, + 0x70, 0xf9, 0x49, 0xcd, 0x39, 0xe2, 0x35, 0x8b, 0xe9, 0x47, 0xd4, 0x32, 0x3c, 0x9a, 0xcc, 0x70, + 0x92, 0x3b, 0x5d, 0x80, 0x22, 0x0e, 0xa9, 0x41, 0x02, 0x86, 0x2d, 0x6c, 0x1c, 0x45, 0x62, 0xcd, + 0x04, 0xe3, 0x24, 0x3e, 0x9d, 0x61, 0xd6, 0xbb, 0x51, 0x92, 0x4b, 0xaf, 0x4a, 0x02, 0x38, 0xa6, + 0x85, 0x5e, 0x80, 0x59, 0x91, 0x9e, 0x68, 0xdb, 0xaf, 0x5d, 0x71, 0xc2, 0x7d, 0x61, 0xdc, 0xab, + 0xc3, 0xc8, 0x9a, 0x01, 0xc5, 0x09, 0x6c, 0xd6, 0xb7, 0x38, 0x07, 0x14, 0x23, 0x30, 0x61, 0x26, + 0xc0, 0x5c, 0x33, 0xc1, 0x38, 0x89, 0x8f, 0xde, 0xa2, 0xe9, 0x7d, 0x7e, 0x4d, 0xa2, 0xb4, 0x41, + 0x8a, 0xee, 0x5f, 0x85, 0xb9, 0x36, 0x3b, 0x0b, 0xd5, 0x24, 0x50, 0xac, 0x47, 0xc5, 0xf0, 0xa6, + 0x09, 0xc6, 0x49, 0x7c, 0xf4, 0x3c, 0xcc, 0x04, 0x54, 0xbb, 0x29, 0x02, 0xfc, 0xee, 0x44, 0x5d, + 0x04, 0x60, 0x1d, 0x88, 0x4d, 0x5c, 0xf4, 0x22, 0x2c, 0xc4, 0x39, 0x53, 0x24, 0x01, 0x7e, 0x99, + 0xa2, 0x92, 0x10, 0xac, 0x26, 0x11, 0x70, 0x6f, 0x1d, 0xf4, 0x0b, 0x30, 0xaf, 0x8d, 0xc4, 0x86, + 0x57, 0x23, 0xf7, 0x45, 0x5e, 0x8b, 0x45, 0x76, 0x21, 0x93, 0x80, 0xe1, 0x1e, 0x6c, 0xf4, 0x0e, + 0x98, 0xad, 0xfa, 0x8d, 0x06, 0xd3, 0x71, 0x3c, 0xf9, 0x22, 0x4f, 0x60, 0xc1, 0x53, 0x7d, 0x18, + 0x10, 0x9c, 0xc0, 0x44, 0x57, 0x01, 0xf9, 0xbb, 0x21, 0x09, 0x0e, 0x48, 0xed, 0x45, 0xfe, 0xfd, + 0x0c, 0xba, 0xc5, 0xcf, 0x98, 0x51, 0x90, 0xd7, 0x7b, 0x30, 0x70, 0x4a, 0x2d, 0xb4, 0x0b, 0xcb, + 0x72, 0xbf, 0xe9, 0xad, 0xb1, 0xb4, 0x64, 0x1c, 0x99, 0x96, 0x6f, 0xf7, 0xc5, 0xc4, 0x47, 0x50, + 0x61, 0x79, 0x12, 0xb4, 0x57, 0x0f, 0xb3, 0x59, 0xa4, 0xb3, 0x4e, 0x7a, 0x07, 0x1e, 0xf8, 0xe4, + 0x21, 0x80, 0x09, 0x1e, 0xf8, 0xba, 0x34, 0x97, 0x45, 0xae, 0x18, 0x3d, 0xd7, 0x5b, 0xbc, 0x0f, + 0xf1, 0x52, 0x2c, 0x38, 0xa1, 0x0f, 0xc3, 0xd4, 0xae, 0x4c, 0xfc, 0xb9, 0x34, 0x9f, 0xc5, 0xde, + 0x9b, 0xc8, 0x61, 0x1b, 0x9f, 0x7e, 0x15, 0x00, 0xc7, 0x2c, 0xd1, 0x53, 0x50, 0xbc, 0xb2, 0xbd, + 0xaa, 0x24, 0x7d, 0x81, 0x49, 0xd8, 0x18, 0xad, 0x82, 0x75, 0x00, 0x5d, 0xc5, 0xca, 0x26, 0x43, + 0x6c, 0xca, 0xe3, 0x3d, 0xbd, 0xd7, 0xc4, 0xa2, 0xd8, 0xec, 0x7e, 0x0d, 0x57, 0x96, 0x4e, 0x25, + 0xb0, 0x45, 0x39, 0x56, 0x18, 0xe8, 0x15, 0x28, 0x8a, 0x3d, 0x89, 0xe9, 0xbf, 0xc5, 0xe3, 0xbd, + 0xa8, 0xc1, 0x31, 0x09, 0xac, 0xd3, 0x43, 0xcf, 0x42, 0xb1, 0xc5, 0xf2, 0x21, 0x92, 0xcb, 0xed, + 0x46, 0x63, 0xe9, 0x34, 0xd3, 0xcd, 0xea, 0xe2, 0x61, 0x3b, 0x06, 0x61, 0x1d, 0x0f, 0x3d, 0x2d, + 0x2f, 0xc7, 0xdf, 0x60, 0xdc, 0x23, 0xa9, 0xcb, 0x71, 0x65, 0x49, 0xf7, 0x09, 0xa5, 0x3c, 0xf3, + 0x00, 0xe7, 0xc8, 0xc7, 0x62, 0xe7, 0xb0, 0xca, 0xbe, 0xf5, 0x21, 0x5d, 0x1a, 0xac, 0x2c, 0xbe, + 0xf2, 0xd1, 0x93, 0x55, 0x96, 0x6f, 0x16, 0xa9, 0xb2, 0xd0, 0x52, 0xf2, 0x9f, 0xc9, 0x73, 0x70, + 0x33, 0xb3, 0x18, 0x3f, 0x69, 0x99, 0xd2, 0x6f, 0x7f, 0x6f, 0x4c, 0x39, 0x88, 0x12, 0x77, 0xc2, + 0x01, 0x8c, 0xbb, 0x61, 0xe4, 0xfa, 0x19, 0x3e, 0x30, 0x49, 0xa4, 0xe4, 0x62, 0xb1, 0x7d, 0x0c, + 0x80, 0x39, 0x2b, 0xca, 0xd3, 0xab, 0xbb, 0xde, 0x7d, 0xd1, 0xfd, 0x1b, 0x99, 0x5f, 0xf6, 0x72, + 0x9e, 0x0c, 0x80, 0x39, 0x2b, 0x74, 0x07, 0xf2, 0x4e, 0x63, 0x37, 0xa3, 0x2f, 0xba, 0x24, 0xbf, + 0x8a, 0xc4, 0x23, 0x63, 0x56, 0x37, 0xcb, 0x98, 0x32, 0xa1, 0xbc, 0xc2, 0xa6, 0x2b, 0xec, 0x8b, + 0x11, 0x79, 0x55, 0xb6, 0x36, 0xd2, 0x78, 0x55, 0xb6, 0x36, 0x30, 0x65, 0x82, 0x3e, 0x69, 0x01, + 0x38, 0xea, 0x8b, 0x45, 0xd9, 0xa4, 0x60, 0xee, 0xf7, 0x05, 0x24, 0x1e, 0x8e, 0x13, 0x43, 0xb1, + 0xc6, 0xd9, 0xfe, 0x9c, 0x05, 0x0b, 0x3d, 0x8d, 0x4d, 0x7e, 0xcc, 0xc9, 0x1a, 0xfc, 0x63, 0x4e, + 0x22, 0x69, 0x5b, 0xa5, 0xd5, 0x70, 0x53, 0x1f, 0x69, 0xed, 0x24, 0xe0, 0xb8, 0xa7, 0x86, 0xfd, + 0x75, 0x0b, 0x8a, 0x5a, 0x4c, 0x39, 0xb5, 0x7b, 0x59, 0xec, 0xbd, 0x68, 0x46, 0x9c, 0xaf, 0x8e, + 0xf9, 0xc4, 0x38, 0x8c, 0xbb, 0x67, 0xeb, 0x5a, 0x5a, 0xa2, 0xd8, 0x3d, 0x4b, 0x4b, 0xb1, 0x80, + 0xf2, 0x84, 0x33, 0xa4, 0xc5, 0x24, 0x2a, 0xaf, 0x27, 0x9c, 0x21, 0x2d, 0xcc, 0x20, 0x8c, 0x1d, + 0x55, 0x8e, 0x22, 0x6e, 0x46, 0x4b, 0x8f, 0xe7, 0x50, 0x33, 0x9b, 0xc1, 0xd0, 0x59, 0xc8, 0x13, + 0xaf, 0x26, 0xac, 0xc5, 0xa2, 0x40, 0xc9, 0x5f, 0xf2, 0x6a, 0x98, 0x96, 0xdb, 0xd7, 0x61, 0xba, + 0x42, 0xaa, 0x01, 0x89, 0x5e, 0x22, 0x87, 0x83, 0x39, 0x10, 0xcf, 0xf2, 0x8b, 0xd7, 0x9c, 0x49, + 0x90, 0x56, 0xa7, 0xe5, 0xf6, 0xef, 0x59, 0x90, 0xc8, 0x56, 0xa8, 0xb9, 0x6a, 0xac, 0x7e, 0xae, + 0x1a, 0xc3, 0xa9, 0x90, 0x3b, 0xd2, 0xa9, 0x70, 0x15, 0x50, 0xd3, 0x89, 0xaa, 0xfb, 0x46, 0x2e, + 0x4d, 0x61, 0xa8, 0xc7, 0x2f, 0x58, 0x7a, 0x30, 0x70, 0x4a, 0x2d, 0xfb, 0x16, 0x14, 0xe4, 0x6b, + 0x24, 0x16, 0xd2, 0x2f, 0xcf, 0x2c, 0x7a, 0x48, 0x3f, 0x3d, 0xb2, 0x30, 0x08, 0x6d, 0x63, 0xe8, + 0xb9, 0x57, 0xfc, 0x30, 0x92, 0x4f, 0xa8, 0xb8, 0x67, 0xe2, 0xda, 0x06, 0x2b, 0xc3, 0x0a, 0x6a, + 0x2f, 0xc0, 0x9c, 0x72, 0x39, 0x70, 0x89, 0xb3, 0xbf, 0x91, 0x87, 0x69, 0xe3, 0x23, 0x1b, 0x0f, + 0x1e, 0xe9, 0xc1, 0xc7, 0x24, 0xc5, 0x75, 0x90, 0x1f, 0xd2, 0x75, 0xa0, 0xfb, 0x6a, 0xc6, 0x4e, + 0xd6, 0x57, 0x33, 0x9e, 0x8d, 0xaf, 0x26, 0x82, 0x49, 0xf1, 0x59, 0x37, 0x11, 0xfa, 0xb8, 0x95, + 0xd1, 0x53, 0x62, 0xf1, 0x26, 0x8f, 0x45, 0x7b, 0x4a, 0xed, 0x21, 0x59, 0xd9, 0x5f, 0x1b, 0x87, + 0x59, 0xf3, 0x71, 0xf1, 0x00, 0x33, 0xf9, 0x96, 0x9e, 0x99, 0x1c, 0xf2, 0xe8, 0x94, 0x1f, 0xf5, + 0xe8, 0x34, 0x36, 0xea, 0xd1, 0x69, 0xfc, 0x18, 0x47, 0xa7, 0xde, 0x83, 0xcf, 0xc4, 0xc0, 0x07, + 0x9f, 0x77, 0xaa, 0x7b, 0xbf, 0x49, 0xc3, 0x51, 0x1e, 0xdf, 0xfb, 0x21, 0x73, 0x1a, 0xd6, 0xfc, + 0x5a, 0xea, 0xfd, 0x69, 0xe1, 0x01, 0x41, 0x85, 0x41, 0xea, 0x35, 0xdd, 0xf0, 0xde, 0x99, 0x37, + 0x0c, 0x71, 0x45, 0x17, 0x7f, 0xb9, 0x90, 0xed, 0x3c, 0x60, 0xee, 0x5a, 0x95, 0x18, 0x84, 0x75, + 0x3c, 0xf6, 0x15, 0x0b, 0xf3, 0x1b, 0x1b, 0xec, 0x24, 0xaa, 0x7f, 0xc5, 0x22, 0xf1, 0x4d, 0x8e, + 0x24, 0xbe, 0xfd, 0xd5, 0x3c, 0xcc, 0x9a, 0x59, 0x88, 0xd1, 0x3d, 0x65, 0x2d, 0x66, 0x62, 0xa8, + 0x72, 0xb2, 0xda, 0xf3, 0xda, 0xbe, 0x47, 0x26, 0xfe, 0x89, 0xbf, 0x5d, 0xf5, 0xd6, 0xf7, 0xe4, + 0x18, 0x8b, 0xb3, 0x8a, 0x60, 0xc7, 0x12, 0x17, 0xc7, 0x51, 0x76, 0xe2, 0xae, 0x2f, 0x73, 0xee, + 0x71, 0xdc, 0x9c, 0x62, 0x85, 0x35, 0xb6, 0x54, 0xbd, 0x1f, 0x90, 0xc0, 0xdd, 0x73, 0xd5, 0x17, + 0x14, 0x98, 0xf2, 0xbc, 0x25, 0xca, 0xb0, 0x82, 0xda, 0x1f, 0xcd, 0x41, 0xfc, 0x71, 0x17, 0x96, + 0x10, 0x35, 0xd4, 0xf6, 0x6c, 0x31, 0x6d, 0x57, 0x47, 0xcd, 0x3a, 0x1c, 0x53, 0x14, 0x61, 0x11, + 0x5a, 0x09, 0x36, 0x38, 0xfe, 0x0f, 0x7c, 0xd4, 0xc5, 0x81, 0xb9, 0x44, 0x54, 0x7c, 0xe6, 0x61, + 0x56, 0x5f, 0xcf, 0xc1, 0x94, 0x7a, 0x57, 0x40, 0xcd, 0x9c, 0x76, 0x20, 0x33, 0x84, 0x29, 0x33, + 0xe7, 0x26, 0xde, 0xc4, 0xb4, 0x1c, 0xdd, 0x87, 0xc9, 0x7d, 0xe2, 0xd4, 0x48, 0x20, 0x9d, 0x96, + 0x5b, 0x19, 0x3d, 0x68, 0xb8, 0xc2, 0xa8, 0xc6, 0x7d, 0xe1, 0xff, 0x43, 0x2c, 0xd9, 0xa1, 0x17, + 0x60, 0x36, 0x72, 0x9b, 0x84, 0x9e, 0x36, 0xb5, 0xad, 0x3e, 0x1f, 0x7b, 0x02, 0x77, 0x0c, 0x28, + 0x4e, 0x60, 0xd3, 0xbd, 0xe8, 0x4e, 0xe8, 0x7b, 0x2c, 0xd9, 0xc2, 0x98, 0x79, 0xa4, 0xbf, 0x5a, + 0xb9, 0x7e, 0x8d, 0xe5, 0x5a, 0x50, 0x18, 0x14, 0xdb, 0x65, 0xf1, 0xc5, 0x01, 0x11, 0x17, 0xa7, + 0xf3, 0xf1, 0x2b, 0x30, 0x5e, 0x8e, 0x15, 0x86, 0x7d, 0x13, 0xe6, 0x12, 0x1d, 0x91, 0xe6, 0xa2, + 0x95, 0x6e, 0x2e, 0x0e, 0x96, 0xb1, 0xef, 0x8f, 0x2c, 0x58, 0xe8, 0x59, 0x5f, 0x83, 0x86, 0xe8, + 0x25, 0x95, 0x6d, 0xee, 0xf8, 0xca, 0x36, 0x3f, 0x9c, 0xb2, 0x2d, 0xaf, 0x7c, 0xf3, 0xfb, 0xe7, + 0x1e, 0xf9, 0xd6, 0xf7, 0xcf, 0x3d, 0xf2, 0xed, 0xef, 0x9f, 0x7b, 0xe4, 0xa3, 0xdd, 0x73, 0xd6, + 0x37, 0xbb, 0xe7, 0xac, 0x6f, 0x75, 0xcf, 0x59, 0xdf, 0xee, 0x9e, 0xb3, 0xbe, 0xd7, 0x3d, 0x67, + 0x7d, 0xee, 0x07, 0xe7, 0x1e, 0x79, 0xb9, 0x20, 0x85, 0xe0, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, + 0x17, 0xaa, 0x51, 0x5e, 0xea, 0x78, 0x00, 0x00, } func (m *ALBTrafficRouting) Marshal() (dAtA []byte, err error) { @@ -5001,16 +5001,18 @@ func (m *IstioTrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - { - size, err := m.VirtualService.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if m.VirtualService != nil { + { + size, err := m.VirtualService.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa } - i-- - dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -8400,8 +8402,10 @@ func (m *IstioTrafficRouting) Size() (n int) { } var l int _ = l - l = m.VirtualService.Size() - n += 1 + l + sovGenerated(uint64(l)) + if m.VirtualService != nil { + l = m.VirtualService.Size() + n += 1 + l + sovGenerated(uint64(l)) + } if m.DestinationRule != nil { l = m.DestinationRule.Size() n += 1 + l + sovGenerated(uint64(l)) @@ -9933,7 +9937,7 @@ func (this *IstioTrafficRouting) String() string { } repeatedStringForVirtualServices += "}" s := strings.Join([]string{`&IstioTrafficRouting{`, - `VirtualService:` + strings.Replace(strings.Replace(this.VirtualService.String(), "IstioVirtualService", "IstioVirtualService", 1), `&`, ``, 1) + `,`, + `VirtualService:` + strings.Replace(this.VirtualService.String(), "IstioVirtualService", "IstioVirtualService", 1) + `,`, `DestinationRule:` + strings.Replace(this.DestinationRule.String(), "IstioDestinationRule", "IstioDestinationRule", 1) + `,`, `VirtualServices:` + repeatedStringForVirtualServices + `,`, `}`, @@ -16906,6 +16910,9 @@ func (m *IstioTrafficRouting) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } + if m.VirtualService == nil { + m.VirtualService = &IstioVirtualService{} + } if err := m.VirtualService.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 11c0f0a1ca..94ed41ec2c 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -1884,7 +1884,6 @@ func schema_pkg_apis_rollouts_v1alpha1_IstioTrafficRouting(ref common.ReferenceC "virtualService": { SchemaProps: spec.SchemaProps{ Description: "VirtualService references an Istio VirtualService to modify to shape traffic", - Default: map[string]interface{}{}, Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioVirtualService"), }, }, From 7d6932fdd1766cc04409c05b14dc824438d43f60 Mon Sep 17 00:00:00 2001 From: Ilya Gorban Date: Sun, 14 Nov 2021 11:51:20 +0200 Subject: [PATCH 21/90] remove master from triggers of pipelines --- .github/workflows/docker-publish.yml | 14 ++++++++------ .github/workflows/e2e.yaml | 4 ++-- .github/workflows/go.yml | 7 ++++--- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 0821e01be3..cd06a9ecd3 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -3,7 +3,7 @@ name: Docker on: push: branches: - - master + # - master # commented due to Codefresh convention - release-* # Run tests for any PRs. @@ -40,8 +40,9 @@ jobs: # ghcr.io/codefresh-io/argo-rollouts tags: | type=ref,event=branch - flavor: | - latest=${{ github.ref == 'refs/heads/master' }} + # commented due to Codefresh convention + # flavor: | + # latest=${{ github.ref == 'refs/heads/master' }} - name: Docker meta (plugin) id: plugin-meta @@ -52,12 +53,13 @@ jobs: # ghcr.io/codefresh-io/kubectl-argo-rollouts tags: | type=ref,event=branch - flavor: | - latest=${{ github.ref == 'refs/heads/master' }} + # commented due to Codefresh convention + # flavor: | + # latest=${{ github.ref == 'refs/heads/master' }} # - name: Login to GitHub Container Registry # if: github.event_name != 'pull_request' - # uses: docker/login-action@v1 + # uses: docker/login-action@v1 # with: # registry: ghcr.io # username: ${{ github.repository_owner }} diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index d59956ceb7..029d34b92b 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -3,11 +3,11 @@ name: E2E Tests on: push: branches: - - 'master' + # - 'master' # commented due to Codefresh convention - 'release-*' pull_request: branches: - - 'master' + # - 'master' # commented due to Codefresh convention - 'release-*' workflow_dispatch: inputs: diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6ba4e33578..8d289fbcc7 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -2,11 +2,12 @@ name: Go on: push: branches: - - "master" - - "release-*" + # - "master" + - "release-*" # Codefresh convention pull_request: branches: - - "master" + # - "master" + - "release-*" # Codefresh convention jobs: lint-go: name: Lint Go code From 9cbc6eb12c2666c827ae13d3873582aef502ff67 Mon Sep 17 00:00:00 2001 From: Ilya Gorban Date: Sun, 14 Nov 2021 12:18:20 +0200 Subject: [PATCH 22/90] Retrigger CI pipeline From c22de3059cf6c7bd1394dc7f2ea384dff37a77c9 Mon Sep 17 00:00:00 2001 From: Ilya Gorban Date: Sun, 14 Nov 2021 17:18:53 +0200 Subject: [PATCH 23/90] add pr-check github action --- .github/workflows/default-branch-check.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/default-branch-check.yaml diff --git a/.github/workflows/default-branch-check.yaml b/.github/workflows/default-branch-check.yaml new file mode 100644 index 0000000000..5e4ac0a54a --- /dev/null +++ b/.github/workflows/default-branch-check.yaml @@ -0,0 +1,18 @@ +name: PR check + +on: + pull_request: + branches: + - "release-*" + +jobs: + test-default-branch: + name: base branch is a default branch + runs-on: ubuntu-latest + steps: + - name: fail if base branch is not default branch + if: ${{ github.event.pull_request.base.ref != github.event.repository.default_branch }} + uses: actions/github-script@v3 + with: + script: | + core.setFailed("Base branch of the PR - ${{ github.event.pull_request.base.ref }} is not a default branch. Please reopen your PR to ${{ github.event.repository.default_branch }}") From 89ce984581ce901635582a619462b1ccd74aa697 Mon Sep 17 00:00:00 2001 From: Leonardo Luz Almeida Date: Tue, 26 Oct 2021 04:12:10 -0400 Subject: [PATCH 24/90] feat: support Ingress from Networking API version (#1529) Signed-off-by: Leonardo Luz Almeida --- cmd/rollouts-controller/main.go | 9 +- controller/controller.go | 10 +- ingress/alb.go | 29 +- ingress/alb_test.go | 12 +- ingress/ingress.go | 25 +- ingress/ingress_test.go | 18 +- .../validation/validation_references.go | 11 +- .../validation/validation_references_test.go | 12 +- rollout/controller.go | 26 +- rollout/controller_test.go | 24 +- rollout/service_test.go | 4 + rollout/trafficrouting.go | 4 +- rollout/trafficrouting/alb/alb.go | 50 +- rollout/trafficrouting/alb/alb_test.go | 60 +- rollout/trafficrouting/nginx/nginx.go | 137 +++- rollout/trafficrouting/nginx/nginx_test.go | 289 +++++-- utils/ingress/ingress.go | 144 +++- utils/ingress/ingress_test.go | 348 ++++++++- utils/ingress/wrapper.go | 370 +++++++++ utils/ingress/wrapper_test.go | 738 ++++++++++++++++++ 20 files changed, 2106 insertions(+), 214 deletions(-) create mode 100644 utils/ingress/wrapper.go create mode 100644 utils/ingress/wrapper_test.go diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index f07726e762..b8db6153c6 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -26,6 +26,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/signals" controllerutil "github.com/argoproj/argo-rollouts/utils/controller" "github.com/argoproj/argo-rollouts/utils/defaults" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" istioutil "github.com/argoproj/argo-rollouts/utils/istio" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/tolerantinformer" @@ -54,6 +55,7 @@ func newCommand() *cobra.Command { istioVersion string trafficSplitVersion string ambassadorVersion string + ingressVersion string albIngressClasses []string nginxIngressClasses []string awsVerifyTargetGroup bool @@ -143,6 +145,10 @@ func newCommand() *cobra.Command { k8sRequestProvider := &metrics.K8sRequestsCountProvider{} kubeclientmetrics.AddMetricsTransportWrapper(config, k8sRequestProvider.IncKubernetesRequest) + mode, err := ingressutil.DetermineIngressMode(ingressVersion, kubeClient.DiscoveryClient) + checkError(err) + ingressWrapper, err := ingressutil.NewIngressWrapper(mode, kubeClient, kubeInformerFactory) + checkError(err) cm := controller.NewManager( namespace, @@ -153,7 +159,7 @@ func newCommand() *cobra.Command { discoveryClient, kubeInformerFactory.Apps().V1().ReplicaSets(), kubeInformerFactory.Core().V1().Services(), - kubeInformerFactory.Extensions().V1beta1().Ingresses(), + ingressWrapper, jobInformerFactory.Batch().V1().Jobs(), tolerantinformer.NewTolerantRolloutInformer(dynamicInformerFactory), tolerantinformer.NewTolerantExperimentInformer(dynamicInformerFactory), @@ -211,6 +217,7 @@ func newCommand() *cobra.Command { command.Flags().StringVar(&istioVersion, "istio-api-version", defaults.DefaultIstioVersion, "Set the default Istio apiVersion that controller should look when manipulating VirtualServices.") command.Flags().StringVar(&ambassadorVersion, "ambassador-api-version", defaults.DefaultAmbassadorVersion, "Set the Ambassador apiVersion that controller should look when manipulating Ambassador Mappings.") command.Flags().StringVar(&trafficSplitVersion, "traffic-split-api-version", defaults.DefaultSMITrafficSplitVersion, "Set the default TrafficSplit apiVersion that controller uses when creating TrafficSplits.") + command.Flags().StringVar(&ingressVersion, "ingress-api-version", "", "Set the Ingress apiVersion that the controller should use.") command.Flags().StringArrayVar(&albIngressClasses, "alb-ingress-classes", defaultALBIngressClass, "Defines all the ingress class annotations that the alb ingress controller operates on. Defaults to alb") command.Flags().StringArrayVar(&nginxIngressClasses, "nginx-ingress-classes", defaultNGINXIngressClass, "Defines all the ingress class annotations that the nginx ingress controller operates on. Defaults to nginx") command.Flags().BoolVar(&awsVerifyTargetGroup, "alb-verify-weight", false, "Verify ALB target group weights before progressing through steps (requires AWS privileges)") diff --git a/controller/controller.go b/controller/controller.go index 47ca955851..302a634074 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -20,7 +20,6 @@ import ( appsinformers "k8s.io/client-go/informers/apps/v1" batchinformers "k8s.io/client-go/informers/batch/v1" coreinformers "k8s.io/client-go/informers/core/v1" - extensionsinformers "k8s.io/client-go/informers/extensions/v1beta1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/cache" @@ -37,6 +36,7 @@ import ( "github.com/argoproj/argo-rollouts/rollout" "github.com/argoproj/argo-rollouts/service" "github.com/argoproj/argo-rollouts/utils/defaults" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" "github.com/argoproj/argo-rollouts/utils/queue" "github.com/argoproj/argo-rollouts/utils/record" ) @@ -107,7 +107,7 @@ func NewManager( discoveryClient discovery.DiscoveryInterface, replicaSetInformer appsinformers.ReplicaSetInformer, servicesInformer coreinformers.ServiceInformer, - ingressesInformer extensionsinformers.IngressInformer, + ingressWrap *ingressutil.IngressWrap, jobInformer batchinformers.JobInformer, rolloutsInformer informers.RolloutInformer, experimentsInformer informers.ExperimentInformer, @@ -181,7 +181,7 @@ func NewManager( IstioDestinationRuleInformer: istioDestinationRuleInformer, ReplicaSetInformer: replicaSetInformer, ServicesInformer: servicesInformer, - IngressInformer: ingressesInformer, + IngressWrapper: ingressWrap, RolloutsInformer: rolloutsInformer, ResyncPeriod: resyncPeriod, RolloutWorkQueue: rolloutWorkqueue, @@ -231,7 +231,7 @@ func NewManager( ingressController := ingress.NewController(ingress.ControllerConfig{ Client: kubeclientset, - IngressInformer: ingressesInformer, + IngressWrap: ingressWrap, IngressWorkQueue: ingressWorkqueue, RolloutsInformer: rolloutsInformer, @@ -247,7 +247,7 @@ func NewManager( metricsServer: metricsServer, rolloutSynced: rolloutsInformer.Informer().HasSynced, serviceSynced: servicesInformer.Informer().HasSynced, - ingressSynced: ingressesInformer.Informer().HasSynced, + ingressSynced: ingressWrap.HasSynced, jobSynced: jobInformer.Informer().HasSynced, experimentSynced: experimentsInformer.Informer().HasSynced, analysisRunSynced: analysisRunInformer.Informer().HasSynced, diff --git a/ingress/alb.go b/ingress/alb.go index b3454d3d8d..01288c86e7 100644 --- a/ingress/alb.go +++ b/ingress/alb.go @@ -7,8 +7,6 @@ import ( "strings" log "github.com/sirupsen/logrus" - extensionsv1beta1 "k8s.io/api/extensions/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" @@ -17,9 +15,10 @@ import ( logutil "github.com/argoproj/argo-rollouts/utils/log" ) -func (c *Controller) syncALBIngress(ingress *extensionsv1beta1.Ingress, rollouts []*v1alpha1.Rollout) error { +func (c *Controller) syncALBIngress(ingress *ingressutil.Ingress, rollouts []*v1alpha1.Rollout) error { ctx := context.TODO() - managedActions, err := ingressutil.NewManagedALBActions(ingress.Annotations[ingressutil.ManagedActionsAnnotation]) + annotations := ingress.GetAnnotations() + managedActions, err := ingressutil.NewManagedALBActions(annotations[ingressutil.ManagedActionsAnnotation]) if err != nil { return nil } @@ -40,32 +39,40 @@ func (c *Controller) syncALBIngress(ingress *extensionsv1beta1.Ingress, rollouts delete(managedActions, roName) resetALBAction, err := getResetALBActionStr(ingress, actionKey) if err != nil { - log.WithField(logutil.RolloutKey, roName).WithField(logutil.IngressKey, ingress.Name).WithField(logutil.NamespaceKey, ingress.Namespace).Error(err) + log.WithField(logutil.RolloutKey, roName). + WithField(logutil.IngressKey, ingress.GetName()). + WithField(logutil.NamespaceKey, ingress.GetNamespace()). + Error(err) return nil } - newIngress.Annotations[actionKey] = resetALBAction + annotations := newIngress.GetAnnotations() + annotations[actionKey] = resetALBAction + newIngress.SetAnnotations(annotations) } } if !modified { return nil } newManagedStr := managedActions.String() - newIngress.Annotations[ingressutil.ManagedActionsAnnotation] = newManagedStr + newAnnotations := newIngress.GetAnnotations() + newAnnotations[ingressutil.ManagedActionsAnnotation] = newManagedStr + newIngress.SetAnnotations(newAnnotations) if newManagedStr == "" { - delete(newIngress.Annotations, ingressutil.ManagedActionsAnnotation) + delete(newIngress.GetAnnotations(), ingressutil.ManagedActionsAnnotation) } - _, err = c.client.ExtensionsV1beta1().Ingresses(ingress.Namespace).Update(ctx, newIngress, metav1.UpdateOptions{}) + _, err = c.ingressWrapper.Update(ctx, ingress.GetNamespace(), newIngress) return err } -func getResetALBActionStr(ingress *extensionsv1beta1.Ingress, action string) (string, error) { +func getResetALBActionStr(ingress *ingressutil.Ingress, action string) (string, error) { parts := strings.Split(action, ingressutil.ALBActionPrefix) if len(parts) != 2 { return "", fmt.Errorf("unable to parse action to get the service %s", action) } service := parts[1] - previousActionStr := ingress.Annotations[action] + annotations := ingress.GetAnnotations() + previousActionStr := annotations[action] var previousAction ingressutil.ALBAction err := json.Unmarshal([]byte(previousActionStr), &previousAction) if err != nil { diff --git a/ingress/alb_test.go b/ingress/alb_test.go index 34582b32c8..a8ca3db64d 100644 --- a/ingress/alb_test.go +++ b/ingress/alb_test.go @@ -101,7 +101,7 @@ func TestInvalidManagedALBActions(t *testing.T) { ing := newALBIngress("test-ingress", 80, "stable-service", rollout.Name) ing.Annotations[ingressutil.ManagedActionsAnnotation] = "invalid-managed-by" - ctrl, kubeclient, enqueuedObjects := newFakeIngressController(ing, rollout) + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) err := ctrl.syncIngress("default/test-ingress") assert.Nil(t, err) @@ -113,7 +113,7 @@ func TestInvalidPreviousALBActionAnnotationValue(t *testing.T) { ing := newALBIngress("test-ingress", 80, "stable-service", "not-existing-rollout") ing.Annotations[albActionAnnotation("stable-service")] = "{" - ctrl, kubeclient, enqueuedObjects := newFakeIngressController(ing, nil) + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) err := ctrl.syncIngress("default/test-ingress") assert.Nil(t, err) @@ -124,7 +124,7 @@ func TestInvalidPreviousALBActionAnnotationValue(t *testing.T) { func TestInvalidPreviousALBActionAnnotationKey(t *testing.T) { ing := newALBIngress("test-ingress", 80, "stable-service", "not-existing-rollout") ing.Annotations[ingressutil.ManagedActionsAnnotation] = "invalid-action-key" - ctrl, kubeclient, enqueuedObjects := newFakeIngressController(ing, nil) + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) err := ctrl.syncIngress("default/test-ingress") assert.Nil(t, err) @@ -136,7 +136,7 @@ func TestResetActionFailureFindNoPort(t *testing.T) { ing := newALBIngress("test-ingress", 80, "stable-service", "not-existing-rollout") ing.Annotations[albActionAnnotation("stable-service")] = "{}" - ctrl, kubeclient, enqueuedObjects := newFakeIngressController(ing, nil) + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) err := ctrl.syncIngress("default/test-ingress") assert.Nil(t, err) @@ -148,7 +148,7 @@ func TestALBIngressNoModifications(t *testing.T) { rollout := rollout("rollout", "stable-service", "test-ingress") ing := newALBIngress("test-ingress", 80, "stable-service", rollout.Name) - ctrl, kubeclient, enqueuedObjects := newFakeIngressController(ing, rollout) + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) err := ctrl.syncIngress("default/test-ingress") assert.Nil(t, err) @@ -159,7 +159,7 @@ func TestALBIngressNoModifications(t *testing.T) { func TestALBIngressResetAction(t *testing.T) { ing := newALBIngress("test-ingress", 80, "stable-service", "non-existing-rollout") - ctrl, kubeclient, enqueuedObjects := newFakeIngressController(ing, nil) + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) err := ctrl.syncIngress("default/test-ingress") assert.Nil(t, err) assert.Len(t, enqueuedObjects, 0) diff --git a/ingress/ingress.go b/ingress/ingress.go index b026cc290a..bbe5f2f0d6 100644 --- a/ingress/ingress.go +++ b/ingress/ingress.go @@ -1,6 +1,7 @@ package ingress import ( + "context" "fmt" "strings" "time" @@ -8,9 +9,7 @@ import ( log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/util/wait" - extensionsinformers "k8s.io/client-go/informers/extensions/v1beta1" "k8s.io/client-go/kubernetes" - extentionslisters "k8s.io/client-go/listers/extensions/v1beta1" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" "k8s.io/kubernetes/cmd/kubeadm/app/util" @@ -32,7 +31,7 @@ const ( // ControllerConfig describes the data required to instantiate a new ingress controller type ControllerConfig struct { Client kubernetes.Interface - IngressInformer extensionsinformers.IngressInformer + IngressWrap *ingressutil.IngressWrap IngressWorkQueue workqueue.RateLimitingInterface RolloutsInformer informers.RolloutInformer @@ -47,7 +46,7 @@ type ControllerConfig struct { type Controller struct { client kubernetes.Interface rolloutsIndexer cache.Indexer - ingressLister extentionslisters.IngressLister + ingressWrapper IngressWrapper ingressWorkqueue workqueue.RateLimitingInterface metricServer *metrics.MetricsServer @@ -56,13 +55,18 @@ type Controller struct { nginxClasses []string } +type IngressWrapper interface { + GetCached(namespace, name string) (*ingressutil.Ingress, error) + Update(ctx context.Context, namespace string, ingress *ingressutil.Ingress) (*ingressutil.Ingress, error) +} + // NewController returns a new ingress controller func NewController(cfg ControllerConfig) *Controller { controller := &Controller{ client: cfg.Client, rolloutsIndexer: cfg.RolloutsInformer.Informer().GetIndexer(), - ingressLister: cfg.IngressInformer.Lister(), + ingressWrapper: cfg.IngressWrap, ingressWorkqueue: cfg.IngressWorkQueue, metricServer: cfg.MetricsServer, @@ -79,7 +83,7 @@ func NewController(cfg ControllerConfig) *Controller { }, })) - cfg.IngressInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + cfg.IngressWrap.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { controllerutil.Enqueue(obj, cfg.IngressWorkQueue) }, @@ -119,7 +123,7 @@ func (c *Controller) syncIngress(key string) error { if err != nil { return err } - ingress, err := c.ingressLister.Ingresses(namespace).Get(name) + ingress, err := c.ingressWrapper.GetCached(namespace, name) if err != nil { if !errors.IsNotFound(err) { // Unknown error occurred @@ -132,15 +136,16 @@ func (c *Controller) syncIngress(key string) error { } return nil } - rollouts, err := c.getRolloutsByIngress(ingress.Namespace, ingress.Name) + rollouts, err := c.getRolloutsByIngress(ingress.GetNamespace(), ingress.GetName()) if err != nil { return nil } // An ingress without annotations cannot be a alb or nginx ingress - if ingress.Annotations == nil { + if ingress.GetAnnotations() == nil { return nil } - class := ingress.Annotations["kubernetes.io/ingress.class"] + annotations := ingress.GetAnnotations() + class := annotations["kubernetes.io/ingress.class"] switch { case hasClass(c.albClasses, class): return c.syncALBIngress(ingress, rollouts) diff --git a/ingress/ingress_test.go b/ingress/ingress_test.go index 42c6edf0e4..e612aa597e 100644 --- a/ingress/ingress_test.go +++ b/ingress/ingress_test.go @@ -18,6 +18,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/fake" informers "github.com/argoproj/argo-rollouts/pkg/client/informers/externalversions" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" "k8s.io/client-go/tools/cache" ) @@ -53,7 +54,8 @@ func newNginxIngress(name string, port int, serviceName string) *extensionsv1bet } } -func newFakeIngressController(ing *extensionsv1beta1.Ingress, rollout *v1alpha1.Rollout) (*Controller, *k8sfake.Clientset, map[string]int) { +func newFakeIngressController(t *testing.T, ing *extensionsv1beta1.Ingress, rollout *v1alpha1.Rollout) (*Controller, *k8sfake.Clientset, map[string]int) { + t.Helper() client := fake.NewSimpleClientset() if rollout != nil { client = fake.NewSimpleClientset(rollout) @@ -64,13 +66,17 @@ func newFakeIngressController(ing *extensionsv1beta1.Ingress, rollout *v1alpha1. } i := informers.NewSharedInformerFactory(client, 0) k8sI := kubeinformers.NewSharedInformerFactory(kubeclient, 0) + ingressWrap, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, kubeclient, k8sI) + if err != nil { + t.Fatal(err) + } rolloutWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") ingressWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Ingresses") c := NewController(ControllerConfig{ Client: kubeclient, - IngressInformer: k8sI.Extensions().V1beta1().Ingresses(), + IngressWrap: ingressWrap, IngressWorkQueue: ingressWorkqueue, RolloutsInformer: i.Argoproj().V1alpha1().Rollouts(), @@ -110,7 +116,7 @@ func newFakeIngressController(ing *extensionsv1beta1.Ingress, rollout *v1alpha1. } func TestSyncMissingIngress(t *testing.T) { - ctrl, _, _ := newFakeIngressController(nil, nil) + ctrl, _, _ := newFakeIngressController(t, nil, nil) err := ctrl.syncIngress("default/test-ingress") assert.NoError(t, err) @@ -119,7 +125,7 @@ func TestSyncMissingIngress(t *testing.T) { func TestSyncIngressNotReferencedByRollout(t *testing.T) { ing := newNginxIngress("test-stable-ingress", 80, "test-stable-service") - ctrl, kubeclient, _ := newFakeIngressController(ing, nil) + ctrl, kubeclient, _ := newFakeIngressController(t, ing, nil) err := ctrl.syncIngress("default/test-stable-ingress") assert.NoError(t, err) @@ -150,7 +156,7 @@ func TestSyncIngressReferencedByRollout(t *testing.T) { }, } - ctrl, kubeclient, enqueuedObjects := newFakeIngressController(ing, rollout) + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) err := ctrl.syncIngress("default/test-stable-ingress") assert.NoError(t, err) @@ -182,7 +188,7 @@ func TestSkipIngressWithNoAnnotations(t *testing.T) { }, } - ctrl, kubeclient, enqueuedObjects := newFakeIngressController(ing, rollout) + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) err := ctrl.syncIngress("default/test-stable-ingress") assert.NoError(t, err) diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index 8e2765ec57..b3f256ec0d 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -12,7 +12,6 @@ import ( ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" corev1 "k8s.io/api/core/v1" - "k8s.io/api/extensions/v1beta1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/validation/field" @@ -58,7 +57,7 @@ type ServiceWithType struct { type ReferencedResources struct { AnalysisTemplatesWithType []AnalysisTemplatesWithType - Ingresses []v1beta1.Ingress + Ingresses []ingressutil.Ingress ServiceWithType []ServiceWithType VirtualServices []unstructured.Unstructured AmbassadorMappings []unstructured.Unstructured @@ -73,7 +72,7 @@ func ValidateRolloutReferencedResources(rollout *v1alpha1.Rollout, referencedRes allErrs = append(allErrs, ValidateAnalysisTemplatesWithType(rollout, templates)...) } for _, ingress := range referencedResources.Ingresses { - allErrs = append(allErrs, ValidateIngress(rollout, ingress)...) + allErrs = append(allErrs, ValidateIngress(rollout, &ingress)...) } for _, vsvc := range referencedResources.VirtualServices { allErrs = append(allErrs, ValidateVirtualService(rollout, vsvc)...) @@ -186,7 +185,7 @@ func setArgValuePlaceHolder(Args []v1alpha1.Argument) { } } -func ValidateIngress(rollout *v1alpha1.Rollout, ingress v1beta1.Ingress) field.ErrorList { +func ValidateIngress(rollout *v1alpha1.Rollout, ingress *ingressutil.Ingress) field.ErrorList { allErrs := field.ErrorList{} fldPath := field.NewPath("spec", "strategy", "canary", "trafficRouting") var ingressName string @@ -206,8 +205,8 @@ func ValidateIngress(rollout *v1alpha1.Rollout, ingress v1beta1.Ingress) field.E } else { return allErrs } - if !ingressutil.HasRuleWithService(&ingress, serviceName) { - msg := fmt.Sprintf("ingress `%s` has no rules using service %s backend", ingress.Name, serviceName) + if !ingressutil.HasRuleWithService(ingress, serviceName) { + msg := fmt.Sprintf("ingress `%s` has no rules using service %s backend", ingress.GetName(), serviceName) allErrs = append(allErrs, field.Invalid(fldPath, ingressName, msg)) } return allErrs diff --git a/pkg/apis/rollouts/validation/validation_references_test.go b/pkg/apis/rollouts/validation/validation_references_test.go index 482030bf21..82669247c3 100644 --- a/pkg/apis/rollouts/validation/validation_references_test.go +++ b/pkg/apis/rollouts/validation/validation_references_test.go @@ -7,6 +7,7 @@ import ( "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" "github.com/argoproj/argo-rollouts/utils/unstructured" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" @@ -180,8 +181,8 @@ func getRollout() *v1alpha1.Rollout { } } -func getIngress() v1beta1.Ingress { - return v1beta1.Ingress{ +func getIngress() *v1beta1.Ingress { + return &v1beta1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Name: "alb-ingress", }, @@ -218,7 +219,7 @@ func getServiceWithType() ServiceWithType { func TestValidateRolloutReferencedResources(t *testing.T) { refResources := ReferencedResources{ AnalysisTemplatesWithType: []AnalysisTemplatesWithType{getAnalysisTemplatesWithType()}, - Ingresses: []v1beta1.Ingress{getIngress()}, + Ingresses: []ingressutil.Ingress{*ingressutil.NewLegacyIngress(getIngress())}, ServiceWithType: []ServiceWithType{getServiceWithType()}, VirtualServices: nil, } @@ -372,7 +373,7 @@ func TestValidateAnalysisTemplateWithType(t *testing.T) { func TestValidateIngress(t *testing.T) { t.Run("validate ingress - success", func(t *testing.T) { - ingress := getIngress() + ingress := ingressutil.NewLegacyIngress(getIngress()) allErrs := ValidateIngress(getRollout(), ingress) assert.Empty(t, allErrs) }) @@ -380,7 +381,8 @@ func TestValidateIngress(t *testing.T) { t.Run("validate ingress - failure", func(t *testing.T) { ingress := getIngress() ingress.Spec.Rules[0].HTTP.Paths[0].Backend.ServiceName = "not-stable-service" - allErrs := ValidateIngress(getRollout(), ingress) + i := ingressutil.NewLegacyIngress(ingress) + allErrs := ValidateIngress(getRollout(), i) expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "alb", "ingress"), ingress.Name, "ingress `alb-ingress` has no rules using service stable-service-name backend") assert.Equal(t, expectedErr.Error(), allErrs[0].Error()) }) diff --git a/rollout/controller.go b/rollout/controller.go index 8103e4605c..790dac53b3 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -12,21 +12,19 @@ import ( log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - "k8s.io/api/extensions/v1beta1" 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" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/dynamic" appsinformers "k8s.io/client-go/informers/apps/v1" coreinformers "k8s.io/client-go/informers/core/v1" - extensionsinformers "k8s.io/client-go/informers/extensions/v1beta1" "k8s.io/client-go/kubernetes" appslisters "k8s.io/client-go/listers/apps/v1" v1 "k8s.io/client-go/listers/core/v1" - extensionslisters "k8s.io/client-go/listers/extensions/v1beta1" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" "k8s.io/kubectl/pkg/util/slice" @@ -48,6 +46,7 @@ import ( controllerutil "github.com/argoproj/argo-rollouts/utils/controller" "github.com/argoproj/argo-rollouts/utils/defaults" experimentutil "github.com/argoproj/argo-rollouts/utils/experiment" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" istioutil "github.com/argoproj/argo-rollouts/utils/istio" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" @@ -95,7 +94,7 @@ type ControllerConfig struct { ClusterAnalysisTemplateInformer informers.ClusterAnalysisTemplateInformer ReplicaSetInformer appsinformers.ReplicaSetInformer ServicesInformer coreinformers.ServiceInformer - IngressInformer extensionsinformers.IngressInformer + IngressWrapper IngressWrapper RolloutsInformer informers.RolloutInformer IstioPrimaryDynamicClient dynamic.Interface IstioVirtualServiceInformer cache.SharedIndexInformer @@ -129,7 +128,7 @@ type reconcilerBase struct { rolloutsSynced cache.InformerSynced rolloutsIndexer cache.Indexer servicesLister v1.ServiceLister - ingressesLister extensionslisters.IngressLister + ingressWrapper IngressWrapper experimentsLister listers.ExperimentLister analysisRunLister listers.AnalysisRunLister analysisTemplateLister listers.AnalysisTemplateLister @@ -148,6 +147,13 @@ type reconcilerBase struct { resyncPeriod time.Duration } +type IngressWrapper interface { + GetCached(namespace, name string) (*ingressutil.Ingress, error) + Get(ctx context.Context, namespace, name string, opts metav1.GetOptions) (*ingressutil.Ingress, error) + Patch(ctx context.Context, namespace, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*ingressutil.Ingress, error) + Create(ctx context.Context, namespace string, ingress *ingressutil.Ingress, opts metav1.CreateOptions) (*ingressutil.Ingress, error) +} + // NewController returns a new rollout controller func NewController(cfg ControllerConfig) *Controller { @@ -176,7 +182,7 @@ func NewController(cfg ControllerConfig) *Controller { rolloutsLister: cfg.RolloutsInformer.Lister(), rolloutsSynced: cfg.RolloutsInformer.Informer().HasSynced, servicesLister: cfg.ServicesInformer.Lister(), - ingressesLister: cfg.IngressInformer.Lister(), + ingressWrapper: cfg.IngressWrapper, experimentsLister: cfg.ExperimentInformer.Lister(), analysisRunLister: cfg.AnalysisRunInformer.Lister(), analysisTemplateLister: cfg.AnalysisTemplateInformer.Lister(), @@ -723,13 +729,13 @@ func (c *rolloutContext) getReferencedAnalysisTemplates(rollout *v1alpha1.Rollou }, nil } -func (c *rolloutContext) getReferencedIngresses() (*[]v1beta1.Ingress, error) { - ingresses := []v1beta1.Ingress{} +func (c *rolloutContext) getReferencedIngresses() (*[]ingressutil.Ingress, error) { + ingresses := []ingressutil.Ingress{} canary := c.rollout.Spec.Strategy.Canary fldPath := field.NewPath("spec", "strategy", "canary", "trafficRouting") if canary != nil && canary.TrafficRouting != nil { if canary.TrafficRouting.ALB != nil { - ingress, err := c.ingressesLister.Ingresses(c.rollout.Namespace).Get(canary.TrafficRouting.ALB.Ingress) + ingress, err := c.ingressWrapper.GetCached(c.rollout.Namespace, canary.TrafficRouting.ALB.Ingress) if k8serrors.IsNotFound(err) { return nil, field.Invalid(fldPath.Child("alb", "ingress"), canary.TrafficRouting.ALB.Ingress, err.Error()) } @@ -738,7 +744,7 @@ func (c *rolloutContext) getReferencedIngresses() (*[]v1beta1.Ingress, error) { } ingresses = append(ingresses, *ingress) } else if canary.TrafficRouting.Nginx != nil { - ingress, err := c.ingressesLister.Ingresses(c.rollout.Namespace).Get(canary.TrafficRouting.Nginx.StableIngress) + ingress, err := c.ingressWrapper.GetCached(c.rollout.Namespace, canary.TrafficRouting.Nginx.StableIngress) if k8serrors.IsNotFound(err) { return nil, field.Invalid(fldPath.Child("nginx", "stableIngress"), canary.TrafficRouting.Nginx.StableIngress, err.Error()) } diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 110af21c21..b22676b6f2 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -48,6 +48,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" istioutil "github.com/argoproj/argo-rollouts/utils/istio" "github.com/argoproj/argo-rollouts/utils/queue" "github.com/argoproj/argo-rollouts/utils/record" @@ -91,7 +92,7 @@ type fixture struct { analysisTemplateLister []*v1alpha1.AnalysisTemplate replicaSetLister []*appsv1.ReplicaSet serviceLister []*corev1.Service - ingressLister []*extensionsv1beta1.Ingress + ingressLister []*ingressutil.Ingress // Actions expected to happen on the client. kubeactions []core.Action actions []core.Action @@ -474,6 +475,7 @@ func getKey(rollout *v1alpha1.Rollout, t *testing.T) string { type resyncFunc func() time.Duration func (f *fixture) newController(resync resyncFunc) (*Controller, informers.SharedInformerFactory, kubeinformers.SharedInformerFactory) { + f.t.Helper() f.client = fake.NewSimpleClientset(f.objects...) f.kubeclient = k8sfake.NewSimpleClientset(f.kubeobjects...) @@ -505,6 +507,11 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, }) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, f.kubeclient, k8sI) + if err != nil { + f.t.Fatal(err) + } + c := NewController(ControllerConfig{ Namespace: metav1.NamespaceAll, KubeClientSet: f.kubeclient, @@ -516,7 +523,7 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share ClusterAnalysisTemplateInformer: i.Argoproj().V1alpha1().ClusterAnalysisTemplates(), ReplicaSetInformer: k8sI.Apps().V1().ReplicaSets(), ServicesInformer: k8sI.Core().V1().Services(), - IngressInformer: k8sI.Extensions().V1beta1().Ingresses(), + IngressWrapper: ingressWrapper, RolloutsInformer: i.Argoproj().V1alpha1().Rollouts(), IstioPrimaryDynamicClient: dynamicClient, IstioVirtualServiceInformer: istioVirtualServiceInformer, @@ -573,7 +580,11 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share k8sI.Core().V1().Services().Informer().GetIndexer().Add(s) } for _, i := range f.ingressLister { - k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ing, err := i.GetExtensionsIngress() + if err != nil { + log.Fatal(err) + } + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(ing) } for _, at := range f.analysisTemplateLister { i.Argoproj().V1alpha1().AnalysisTemplates().Informer().GetIndexer().Add(at) @@ -1618,12 +1629,13 @@ func TestGetReferencedIngressesALB(t *testing.T) { Namespace: metav1.NamespaceDefault, }, } - f.ingressLister = append(f.ingressLister, ingress) + f.ingressLister = append(f.ingressLister, ingressutil.NewLegacyIngress(ingress)) c, _, _ := f.newController(noResyncPeriodFunc) roCtx, err := c.newRolloutContext(r) assert.NoError(t, err) - _, err = roCtx.getReferencedIngresses() + i, err := roCtx.getReferencedIngresses() assert.NoError(t, err) + assert.NotNil(t, i) }) } @@ -1655,7 +1667,7 @@ func TestGetReferencedIngressesNginx(t *testing.T) { Namespace: metav1.NamespaceDefault, }, } - f.ingressLister = append(f.ingressLister, ingress) + f.ingressLister = append(f.ingressLister, ingressutil.NewLegacyIngress(ingress)) c, _, _ := f.newController(noResyncPeriodFunc) roCtx, err := c.newRolloutContext(r) assert.NoError(t, err) diff --git a/rollout/service_test.go b/rollout/service_test.go index 7e06972842..7dda838271 100644 --- a/rollout/service_test.go +++ b/rollout/service_test.go @@ -24,6 +24,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/aws/mocks" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" ) @@ -494,6 +495,7 @@ func TestCanaryAWSVerifyTargetGroupsNotYetReady(t *testing.T) { f.objects = append(f.objects, r2, tgb) f.kubeobjects = append(f.kubeobjects, rs1, rs2, ing, rootSvc, canarySvc, stableSvc, ep) f.serviceLister = append(f.serviceLister, rootSvc, canarySvc, stableSvc) + f.ingressLister = append(f.ingressLister, ingressutil.NewLegacyIngress(ing)) f.expectGetEndpointsAction(ep) f.run(getKey(r2, t)) @@ -587,6 +589,7 @@ func TestCanaryAWSVerifyTargetGroupsReady(t *testing.T) { f.objects = append(f.objects, r2, tgb) f.kubeobjects = append(f.kubeobjects, rs1, rs2, ing, rootSvc, canarySvc, stableSvc, ep) f.serviceLister = append(f.serviceLister, rootSvc, canarySvc, stableSvc) + f.ingressLister = append(f.ingressLister, ingressutil.NewLegacyIngress(ing)) f.expectGetEndpointsAction(ep) scaleDownRSIndex := f.expectPatchReplicaSetAction(rs1) @@ -645,6 +648,7 @@ func TestCanaryAWSVerifyTargetGroupsSkip(t *testing.T) { f.objects = append(f.objects, r2) f.kubeobjects = append(f.kubeobjects, rs1, rs2, ing, rootSvc, canarySvc, stableSvc) f.serviceLister = append(f.serviceLister, rootSvc, canarySvc, stableSvc) + f.ingressLister = append(f.ingressLister, ingressutil.NewLegacyIngress(ing)) f.run(getKey(r2, t)) // there should be no api calls f.assertEvents(nil) diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index 1162d8e865..ed77685a18 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -36,7 +36,7 @@ func (c *Controller) NewTrafficRoutingReconciler(roCtx *rolloutContext) (traffic Client: c.kubeclientset, Recorder: c.recorder, ControllerKind: controllerKind, - IngressLister: c.ingressesLister, + IngressWrapper: c.ingressWrapper, }), nil } if rollout.Spec.Strategy.Canary.TrafficRouting.ALB != nil { @@ -45,7 +45,7 @@ func (c *Controller) NewTrafficRoutingReconciler(roCtx *rolloutContext) (traffic Client: c.kubeclientset, Recorder: c.recorder, ControllerKind: controllerKind, - IngressLister: c.ingressesLister, + IngressWrapper: c.ingressWrapper, }) } if rollout.Spec.Strategy.Canary.TrafficRouting.SMI != nil { diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go index 6e9e2e3016..3a3111e0e3 100644 --- a/rollout/trafficrouting/alb/alb.go +++ b/rollout/trafficrouting/alb/alb.go @@ -6,19 +6,16 @@ import ( "strconv" "github.com/sirupsen/logrus" - extensionsv1beta1 "k8s.io/api/extensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" - extensionslisters "k8s.io/client-go/listers/extensions/v1beta1" "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/aws" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" - "github.com/argoproj/argo-rollouts/utils/diff" ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" jsonutil "github.com/argoproj/argo-rollouts/utils/json" logutil "github.com/argoproj/argo-rollouts/utils/log" @@ -36,10 +33,15 @@ type ReconcilerConfig struct { Client kubernetes.Interface Recorder record.EventRecorder ControllerKind schema.GroupVersionKind - IngressLister extensionslisters.IngressLister + IngressWrapper IngressWrapper VerifyWeight *bool } +type IngressWrapper interface { + GetCached(namespace, name string) (*ingressutil.Ingress, error) + Patch(ctx context.Context, namespace, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*ingressutil.Ingress, error) +} + // Reconciler holds required fields to reconcile ALB Ingress resources type Reconciler struct { cfg ReconcilerConfig @@ -71,7 +73,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 ctx := context.TODO() rollout := r.cfg.Rollout ingressName := rollout.Spec.Strategy.Canary.TrafficRouting.ALB.Ingress - ingress, err := r.cfg.IngressLister.Ingresses(rollout.Namespace).Get(ingressName) + ingress, err := r.cfg.IngressWrapper.GetCached(rollout.Namespace, ingressName) if err != nil { return err } @@ -84,11 +86,12 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return fmt.Errorf("ingress does not have service `%s` in rules", actionService) } - desired, err := getDesiredAnnotations(ingress, rollout, port, desiredWeight, additionalDestinations...) + desiredAnnotations, err := getDesiredAnnotations(ingress, rollout, port, desiredWeight, additionalDestinations...) if err != nil { return err } - patch, modified, err := calculatePatch(ingress, desired) + desiredIngress := ingressutil.NewIngressWithAnnotations(ingress.Mode(), desiredAnnotations) + patch, modified, err := ingressutil.BuildIngressPatch(ingress.Mode(), ingress, desiredIngress, ingressutil.WithAnnotations()) if err != nil { return nil } @@ -99,7 +102,8 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 r.log.WithField("patch", string(patch)).Debug("applying ALB Ingress patch") r.log.WithField("desiredWeight", desiredWeight).Info("updating ALB Ingress") r.cfg.Recorder.Eventf(r.cfg.Rollout, record.EventOptions{EventReason: "PatchingALBIngress"}, "Updating Ingress `%s` to desiredWeight '%d'", ingressName, desiredWeight) - _, err = r.cfg.Client.ExtensionsV1beta1().Ingresses(ingress.Namespace).Patch(ctx, ingress.Name, types.MergePatchType, patch, metav1.PatchOptions{}) + + _, err = r.cfg.IngressWrapper.Patch(ctx, ingress.GetNamespace(), ingress.GetName(), types.MergePatchType, patch, metav1.PatchOptions{}) if err != nil { r.log.WithField("err", err.Error()).Error("error patching alb ingress") return fmt.Errorf("error patching alb ingress `%s`: %v", ingressName, err) @@ -121,26 +125,27 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations .. ctx := context.TODO() rollout := r.cfg.Rollout ingressName := rollout.Spec.Strategy.Canary.TrafficRouting.ALB.Ingress - ingress, err := r.cfg.IngressLister.Ingresses(rollout.Namespace).Get(ingressName) + ingress, err := r.cfg.IngressWrapper.GetCached(rollout.Namespace, ingressName) if err != nil { return pointer.BoolPtr(false), err } resourceIDToDest := map[string]v1alpha1.WeightDestination{} canaryService := rollout.Spec.Strategy.Canary.CanaryService - canaryResourceID := aws.BuildTargetGroupResourceID(rollout.Namespace, ingress.Name, canaryService, rollout.Spec.Strategy.Canary.TrafficRouting.ALB.ServicePort) + canaryResourceID := aws.BuildTargetGroupResourceID(rollout.Namespace, ingress.GetName(), canaryService, rollout.Spec.Strategy.Canary.TrafficRouting.ALB.ServicePort) for _, dest := range additionalDestinations { - resourceID := aws.BuildTargetGroupResourceID(rollout.Namespace, ingress.Name, dest.ServiceName, rollout.Spec.Strategy.Canary.TrafficRouting.ALB.ServicePort) + resourceID := aws.BuildTargetGroupResourceID(rollout.Namespace, ingress.GetName(), dest.ServiceName, rollout.Spec.Strategy.Canary.TrafficRouting.ALB.ServicePort) resourceIDToDest[resourceID] = dest } - if len(ingress.Status.LoadBalancer.Ingress) == 0 { + loadBalancerStatus := ingress.GetLoadBalancerStatus() + if len(loadBalancerStatus.Ingress) == 0 { r.log.Infof("LoadBalancer not yet allocated") } numVerifiedWeights := 0 - for _, lbIngress := range ingress.Status.LoadBalancer.Ingress { + for _, lbIngress := range loadBalancerStatus.Ingress { if lbIngress.Hostname == "" { continue } @@ -190,21 +195,6 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations .. return pointer.BoolPtr(numVerifiedWeights == 1+len(additionalDestinations)), nil } -func calculatePatch(current *extensionsv1beta1.Ingress, desiredAnnotations map[string]string) ([]byte, bool, error) { - // only compare Annotations - return diff.CreateTwoWayMergePatch( - &extensionsv1beta1.Ingress{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: current.Annotations, - }, - }, - &extensionsv1beta1.Ingress{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: desiredAnnotations, - }, - }, extensionsv1beta1.Ingress{}) -} - func getForwardActionString(r *v1alpha1.Rollout, port int32, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) string { stableService := r.Spec.Strategy.Canary.StableService canaryService := r.Spec.Strategy.Canary.CanaryService @@ -247,8 +237,8 @@ func getForwardActionString(r *v1alpha1.Rollout, port int32, desiredWeight int32 return string(bytes) } -func getDesiredAnnotations(current *extensionsv1beta1.Ingress, r *v1alpha1.Rollout, port int32, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (map[string]string, error) { - desired := current.DeepCopy().Annotations +func getDesiredAnnotations(current *ingressutil.Ingress, r *v1alpha1.Rollout, port int32, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (map[string]string, error) { + desired := current.DeepCopy().GetAnnotations() key := ingressutil.ALBActionAnnotationKey(r) desired[key] = getForwardActionString(r, port, desiredWeight, additionalDestinations...) m, err := ingressutil.NewManagedALBActions(desired[ingressutil.ManagedActionsAnnotation]) diff --git a/rollout/trafficrouting/alb/alb_test.go b/rollout/trafficrouting/alb/alb_test.go index d5384679c7..62b6dfea0e 100644 --- a/rollout/trafficrouting/alb/alb_test.go +++ b/rollout/trafficrouting/alb/alb_test.go @@ -130,12 +130,16 @@ func TestIngressNotFound(t *testing.T) { ro := fakeRollout("stable-service", "canary-service", "stable-ingress", 443) client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) assert.NoError(t, err) err = r.SetWeight(10) @@ -149,12 +153,16 @@ func TestServiceNotFoundInIngress(t *testing.T) { client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) assert.NoError(t, err) err = r.SetWeight(10) @@ -167,12 +175,16 @@ func TestNoChanges(t *testing.T) { client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) assert.NoError(t, err) err = r.SetWeight(10) @@ -187,12 +199,16 @@ func TestErrorOnInvalidManagedBy(t *testing.T) { client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) assert.NoError(t, err) err = r.SetWeight(10) @@ -206,12 +222,16 @@ func TestSetInitialDesiredWeight(t *testing.T) { client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) assert.NoError(t, err) err = r.SetWeight(10) @@ -225,12 +245,16 @@ func TestUpdateDesiredWeight(t *testing.T) { client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) assert.NoError(t, err) err = r.SetWeight(10) @@ -253,12 +277,16 @@ func TestErrorPatching(t *testing.T) { client.ReactionChain = nil k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) assert.NoError(t, err) @@ -305,12 +333,16 @@ func TestVerifyWeight(t *testing.T) { client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, VerifyWeight: pointer.BoolPtr(true), }) assert.NoError(t, err) @@ -382,12 +414,16 @@ func TestSetWeightWithMultipleBackends(t *testing.T) { client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) assert.NoError(t, err) @@ -449,12 +485,16 @@ func TestVerifyWeightWithAdditionalDestinations(t *testing.T) { client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r, err := NewReconciler(ReconcilerConfig{ Rollout: ro, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, VerifyWeight: pointer.BoolPtr(true), }) assert.NoError(t, err) diff --git a/rollout/trafficrouting/nginx/nginx.go b/rollout/trafficrouting/nginx/nginx.go index d9de870b0d..cd55787fb2 100644 --- a/rollout/trafficrouting/nginx/nginx.go +++ b/rollout/trafficrouting/nginx/nginx.go @@ -2,21 +2,21 @@ package nginx import ( "context" + "errors" "fmt" "strings" "github.com/sirupsen/logrus" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + networkingv1 "k8s.io/api/networking/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" types "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" - extensionslisters "k8s.io/client-go/listers/extensions/v1beta1" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/defaults" - "github.com/argoproj/argo-rollouts/utils/diff" ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" @@ -31,7 +31,14 @@ type ReconcilerConfig struct { Client kubernetes.Interface Recorder record.EventRecorder ControllerKind schema.GroupVersionKind - IngressLister extensionslisters.IngressLister + IngressWrapper IngressWrapper +} + +type IngressWrapper interface { + Get(ctx context.Context, namespace, name string, opts metav1.GetOptions) (*ingressutil.Ingress, error) + GetCached(namespace, name string) (*ingressutil.Ingress, error) + Patch(ctx context.Context, namespace, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*ingressutil.Ingress, error) + Create(ctx context.Context, namespace string, ingress *ingressutil.Ingress, opts metav1.CreateOptions) (*ingressutil.Ingress, error) } // Reconciler holds required fields to reconcile Nginx resources @@ -53,8 +60,77 @@ func (r *Reconciler) Type() string { return Type } -// canaryIngress returns the desired state of the canary ingress -func (r *Reconciler) canaryIngress(stableIngress *extensionsv1beta1.Ingress, name string, desiredWeight int32) (*extensionsv1beta1.Ingress, error) { +func (r *Reconciler) buildCanaryIngress(stableIngress *networkingv1.Ingress, name string, desiredWeight int32) (*ingressutil.Ingress, error) { + stableIngressName := r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress + stableServiceName := r.cfg.Rollout.Spec.Strategy.Canary.StableService + canaryServiceName := r.cfg.Rollout.Spec.Strategy.Canary.CanaryService + annotationPrefix := defaults.GetCanaryIngressAnnotationPrefixOrDefault(r.cfg.Rollout) + + // Set up canary ingress resource, we do *not* have to duplicate `spec.tls` in a canary, only + // `spec.rules` + desiredCanaryIngress := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Annotations: map[string]string{}, + }, + Spec: networkingv1.IngressSpec{ + Rules: make([]networkingv1.IngressRule, 0), // We have no way of knowing yet how many rules there will be + }, + } + + // Preserve ingressClassName from stable ingress + if stableIngress.Spec.IngressClassName != nil { + desiredCanaryIngress.Spec.IngressClassName = stableIngress.Spec.IngressClassName + } + + // Must preserve ingress.class on canary ingress, no other annotations matter + // See: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary + if val, ok := stableIngress.Annotations["kubernetes.io/ingress.class"]; ok { + desiredCanaryIngress.Annotations["kubernetes.io/ingress.class"] = val + } + + // Ensure canaryIngress is owned by this Rollout for cleanup + desiredCanaryIngress.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(r.cfg.Rollout, r.cfg.ControllerKind)}) + + // Copy only the rules which reference the stableService from the stableIngress to the canaryIngress + // and change service backend to canaryService. Rules **not** referencing the stableIngress will be ignored. + for ir := 0; ir < len(stableIngress.Spec.Rules); ir++ { + var hasStableServiceBackendRule bool + ingressRule := stableIngress.Spec.Rules[ir].DeepCopy() + + // Update all backends pointing to the stableService to point to the canaryService now + for ip := 0; ip < len(ingressRule.HTTP.Paths); ip++ { + if ingressRule.HTTP.Paths[ip].Backend.Service.Name == stableServiceName { + hasStableServiceBackendRule = true + ingressRule.HTTP.Paths[ip].Backend.Service.Name = canaryServiceName + } + } + + // If this rule was using the specified stableService backend, append it to the canary Ingress spec + if hasStableServiceBackendRule { + desiredCanaryIngress.Spec.Rules = append(desiredCanaryIngress.Spec.Rules, *ingressRule) + } + } + + if len(desiredCanaryIngress.Spec.Rules) == 0 { + return nil, fmt.Errorf("ingress `%s` has no rules using service %s backend", stableIngressName, stableServiceName) + } + + // Process additional annotations, would commonly be things like `canary-by-header` or `load-balance` + for k, v := range r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalIngressAnnotations { + if !strings.HasPrefix(k, annotationPrefix) { + k = fmt.Sprintf("%s/%s", annotationPrefix, k) + } + desiredCanaryIngress.Annotations[k] = v + } + // Always set `canary` and `canary-weight` - `canary-by-header` and `canary-by-cookie`, if set, will always take precedence + desiredCanaryIngress.Annotations[fmt.Sprintf("%s/canary", annotationPrefix)] = "true" + desiredCanaryIngress.Annotations[fmt.Sprintf("%s/canary-weight", annotationPrefix)] = fmt.Sprintf("%d", desiredWeight) + + return ingressutil.NewIngress(desiredCanaryIngress), nil +} + +func (r *Reconciler) buildLegacyCanaryIngress(stableIngress *extensionsv1beta1.Ingress, name string, desiredWeight int32) (*ingressutil.Ingress, error) { stableIngressName := r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress stableServiceName := r.cfg.Rollout.Spec.Strategy.Canary.StableService canaryServiceName := r.cfg.Rollout.Spec.Strategy.Canary.CanaryService @@ -121,27 +197,27 @@ func (r *Reconciler) canaryIngress(stableIngress *extensionsv1beta1.Ingress, nam desiredCanaryIngress.Annotations[fmt.Sprintf("%s/canary", annotationPrefix)] = "true" desiredCanaryIngress.Annotations[fmt.Sprintf("%s/canary-weight", annotationPrefix)] = fmt.Sprintf("%d", desiredWeight) - return desiredCanaryIngress, nil + return ingressutil.NewLegacyIngress(desiredCanaryIngress), nil } -// compareCanaryIngresses compares the current canaryIngress with the desired one and returns a patch -func compareCanaryIngresses(current *extensionsv1beta1.Ingress, desired *extensionsv1beta1.Ingress) ([]byte, bool, error) { - // only compare Spec, Annotations, and Labels - return diff.CreateTwoWayMergePatch( - &extensionsv1beta1.Ingress{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: current.Annotations, - Labels: current.Labels, - }, - Spec: current.Spec, - }, - &extensionsv1beta1.Ingress{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: desired.Annotations, - Labels: desired.Labels, - }, - Spec: desired.Spec, - }, extensionsv1beta1.Ingress{}) +// canaryIngress returns the desired state of the canary ingress +func (r *Reconciler) canaryIngress(stableIngress *ingressutil.Ingress, name string, desiredWeight int32) (*ingressutil.Ingress, error) { + switch stableIngress.Mode() { + case ingressutil.IngressModeNetworking: + networkingIngress, err := stableIngress.GetNetworkingIngress() + if err != nil { + return nil, err + } + return r.buildCanaryIngress(networkingIngress, name, desiredWeight) + case ingressutil.IngressModeExtensions: + extensionsIngress, err := stableIngress.GetExtensionsIngress() + if err != nil { + return nil, err + } + return r.buildLegacyCanaryIngress(extensionsIngress, name, desiredWeight) + default: + return nil, errors.New("undefined ingress mode") + } } // SetWeight modifies Nginx Ingress resources to reach desired state @@ -151,13 +227,13 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 canaryIngressName := ingressutil.GetCanaryIngressName(r.cfg.Rollout) // Check if stable ingress exists (from lister, which has a cache), error if it does not - stableIngress, err := r.cfg.IngressLister.Ingresses(r.cfg.Rollout.Namespace).Get(stableIngressName) + stableIngress, err := r.cfg.IngressWrapper.GetCached(r.cfg.Rollout.Namespace, stableIngressName) if err != nil { r.log.WithField(logutil.IngressKey, stableIngressName).WithField("err", err.Error()).Error("error retrieving stableIngress") return fmt.Errorf("error retrieving stableIngress `%s` from cache: %v", stableIngressName, err) } // Check if canary ingress exists (from lister which has a cache), determines whether we later call Create() or Update() - canaryIngress, err := r.cfg.IngressLister.Ingresses(r.cfg.Rollout.Namespace).Get(canaryIngressName) + canaryIngress, err := r.cfg.IngressWrapper.GetCached(r.cfg.Rollout.Namespace, canaryIngressName) canaryIngressExists := true if err != nil { @@ -179,7 +255,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 if !canaryIngressExists { r.cfg.Recorder.Eventf(r.cfg.Rollout, record.EventOptions{EventReason: "CreatingCanaryIngress"}, "Creating canary ingress `%s` with weight `%d`", canaryIngressName, desiredWeight) - _, err = r.cfg.Client.ExtensionsV1beta1().Ingresses(r.cfg.Rollout.Namespace).Create(ctx, desiredCanaryIngress, metav1.CreateOptions{}) + _, err = r.cfg.IngressWrapper.Create(ctx, r.cfg.Rollout.Namespace, desiredCanaryIngress, metav1.CreateOptions{}) if err == nil { return nil } @@ -190,7 +266,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 // Canary ingress was created by a different reconcile call before this one could complete (race) // This means we just read it from the API now (instead of cache) and continue with the normal // flow we take when the canary already existed. - canaryIngress, err = r.cfg.Client.ExtensionsV1beta1().Ingresses(r.cfg.Rollout.Namespace).Get(ctx, canaryIngressName, metav1.GetOptions{}) + canaryIngress, err = r.cfg.IngressWrapper.Get(ctx, r.cfg.Rollout.Namespace, canaryIngressName, metav1.GetOptions{}) if err != nil { r.log.WithField(logutil.IngressKey, canaryIngressName).Error(err.Error()) return fmt.Errorf("error retrieving canary ingress `%s` from api: %v", canaryIngressName, err) @@ -200,13 +276,14 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 // Canary Ingress already exists, apply a patch if needed // Only modify canaryIngress if it is controlled by this Rollout - if !metav1.IsControlledBy(canaryIngress, r.cfg.Rollout) { + if !metav1.IsControlledBy(canaryIngress.GetObjectMeta(), r.cfg.Rollout) { r.log.WithField(logutil.IngressKey, canaryIngressName).Error("canary ingress controlled by different object") return fmt.Errorf("canary ingress `%s` controlled by different object", canaryIngressName) } // Make patches - patch, modified, err := compareCanaryIngresses(canaryIngress, desiredCanaryIngress) + patch, modified, err := ingressutil.BuildIngressPatch(canaryIngress.Mode(), canaryIngress, + desiredCanaryIngress, ingressutil.WithAnnotations(), ingressutil.WithLabels(), ingressutil.WithSpec()) if err != nil { r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error constructing canary ingress patch") diff --git a/rollout/trafficrouting/nginx/nginx_test.go b/rollout/trafficrouting/nginx/nginx_test.go index 04349bba42..6f72fe1a4b 100644 --- a/rollout/trafficrouting/nginx/nginx_test.go +++ b/rollout/trafficrouting/nginx/nginx_test.go @@ -8,7 +8,9 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + networkingv1 "k8s.io/api/networking/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -23,7 +25,64 @@ import ( "github.com/argoproj/argo-rollouts/utils/record" ) -func ingress(name string, port int, serviceName string) *extensionsv1beta1.Ingress { +func networkingIngress(name string, port int, serviceName string) *networkingv1.Ingress { + ingressClassName := "ingress-name" + return &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "some-namespace", + Annotations: map[string]string{ + "annotation-key1": "annotation-value1", + }, + Labels: map[string]string{ + "label-key1": "label-value1", + "label-key2": "label-value2", + }, + }, + Spec: networkingv1.IngressSpec{ + IngressClassName: &ingressClassName, + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: serviceName, + Port: networkingv1.ServiceBackendPort{ + Name: "http", + Number: int32(port), + }, + }, + }, + Rules: []networkingv1.IngressRule{ + { + Host: "fakehost.example.com", + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/foo", + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: serviceName, + Port: networkingv1.ServiceBackendPort{ + Name: "http", + Number: int32(port), + }, + }, + Resource: &corev1.TypedLocalObjectReference{ + APIGroup: new(string), + Kind: "", + Name: name, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func extensionsIngress(name string, port int, serviceName string) *extensionsv1beta1.Ingress { return &extensionsv1beta1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -78,7 +137,37 @@ func fakeRollout(stableSvc, canarySvc, stableIng string) *v1alpha1.Rollout { } } -func checkBackendService(t *testing.T, ing *extensionsv1beta1.Ingress, serviceName string) { +func checkBackendService(t *testing.T, ing *ingressutil.Ingress, serviceName string) { + t.Helper() + switch ing.Mode() { + case ingressutil.IngressModeNetworking: + networkingIngress, err := ing.GetNetworkingIngress() + if err != nil { + t.Error(err) + } + checkIngressBackendService(t, networkingIngress, serviceName) + case ingressutil.IngressModeExtensions: + extensionsIngress, err := ing.GetExtensionsIngress() + if err != nil { + t.Error(err) + } + checkBackendServiceLegacy(t, extensionsIngress, serviceName) + } +} + +func checkIngressBackendService(t *testing.T, ing *networkingv1.Ingress, serviceName string) { + t.Helper() + for ir := 0; ir < len(ing.Spec.Rules); ir++ { + for ip := 0; ip < len(ing.Spec.Rules[ir].HTTP.Paths); ip++ { + assert.Equal(t, serviceName, ing.Spec.Rules[ir].HTTP.Paths[ip].Backend.Service.Name) + return + } + } + msg := fmt.Sprintf("Service '%s' not found within backends of ingress '%s'", serviceName, ing.Name) + assert.Fail(t, msg) +} +func checkBackendServiceLegacy(t *testing.T, ing *extensionsv1beta1.Ingress, serviceName string) { + t.Helper() for ir := 0; ir < len(ing.Spec.Rules); ir++ { for ip := 0; ip < len(ing.Spec.Rules[ir].HTTP.Paths); ip++ { assert.Equal(t, serviceName, ing.Spec.Rules[ir].HTTP.Paths[ip].Backend.ServiceName) @@ -95,17 +184,23 @@ func TestCanaryIngressCreate(t *testing.T) { Rollout: fakeRollout("stable-service", "canary-service", "stable-ingress"), }, } - stableIngress := ingress("stable-ingress", 80, "stable-service") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") stableIngress.Spec.IngressClassName = pointer.StringPtr("nginx-ext") + i := ingressutil.NewLegacyIngress(stableIngress) - desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 10) + desiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 10) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") - assert.Equal(t, "true", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") - assert.Equal(t, "10", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") - assert.NotNil(t, desiredCanaryIngress.Spec.IngressClassName) - assert.Equal(t, "nginx-ext", *desiredCanaryIngress.Spec.IngressClassName) + desired, err := desiredCanaryIngress.GetExtensionsIngress() + if err != nil { + t.Error(err) + t.FailNow() + } + assert.Equal(t, "true", desired.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "10", desired.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.NotNil(t, desired.Spec.IngressClassName) + assert.Equal(t, "nginx-ext", *desired.Spec.IngressClassName) } func TestCanaryIngressPatchWeight(t *testing.T) { @@ -114,19 +209,22 @@ func TestCanaryIngressPatchWeight(t *testing.T) { Rollout: fakeRollout("stable-service", "canary-service", "stable-ingress"), }, } - stableIngress := ingress("stable-ingress", 80, "stable-service") - canaryIngress := ingress("canary-ingress", 80, "canary-service") - canaryIngress.SetAnnotations(map[string]string{ + stable := extensionsIngress("stable-ingress", 80, "stable-service") + canary := extensionsIngress("canary-ingress", 80, "canary-service") + canary.SetAnnotations(map[string]string{ "nginx.ingress.kubernetes.io/canary": "true", "nginx.ingress.kubernetes.io/canary-weight": "10", }) + stableIngress := ingressutil.NewLegacyIngress(stable) + canaryIngress := ingressutil.NewLegacyIngress(canary) desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 15) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") - patch, modified, err := compareCanaryIngresses(canaryIngress, desiredCanaryIngress) + patch, modified, err := ingressutil.BuildIngressPatch(canaryIngress.Mode(), canaryIngress, desiredCanaryIngress, + ingressutil.WithAnnotations(), ingressutil.WithLabels(), ingressutil.WithSpec()) assert.Nil(t, err, "compareCanaryIngresses returns no error") assert.True(t, modified, "compareCanaryIngresses returns modified=true") assert.Equal(t, "{\"metadata\":{\"annotations\":{\"nginx.ingress.kubernetes.io/canary-weight\":\"15\"}}}", string(patch), "compareCanaryIngresses returns expected patch") @@ -138,20 +236,23 @@ func TestCanaryIngressUpdatedRoute(t *testing.T) { Rollout: fakeRollout("stable-service", "canary-service", "stable-ingress"), }, } - stableIngress := ingress("stable-ingress", 80, "stable-service") - stableIngress.Spec.Rules[0].HTTP.Paths[0].Path = "/bar" - canaryIngress := ingress("canary-ingress", 80, "canary-service") - canaryIngress.SetAnnotations(map[string]string{ + stable := extensionsIngress("stable-ingress", 80, "stable-service") + stable.Spec.Rules[0].HTTP.Paths[0].Path = "/bar" + canary := extensionsIngress("canary-ingress", 80, "canary-service") + canary.SetAnnotations(map[string]string{ "nginx.ingress.kubernetes.io/canary": "true", "nginx.ingress.kubernetes.io/canary-weight": "15", }) + stableIngress := ingressutil.NewLegacyIngress(stable) + canaryIngress := ingressutil.NewLegacyIngress(canary) desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 15) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") - patch, modified, err := compareCanaryIngresses(canaryIngress, desiredCanaryIngress) + patch, modified, err := ingressutil.BuildIngressPatch(canaryIngress.Mode(), canaryIngress, desiredCanaryIngress, + ingressutil.WithAnnotations(), ingressutil.WithLabels(), ingressutil.WithSpec()) assert.Nil(t, err, "compareCanaryIngresses returns no error") assert.True(t, modified, "compareCanaryIngresses returns modified=true") assert.Equal(t, "{\"spec\":{\"rules\":[{\"host\":\"fakehost.example.com\",\"http\":{\"paths\":[{\"backend\":{\"serviceName\":\"canary-service\",\"servicePort\":80},\"path\":\"/bar\"}]}}]}}", string(patch), "compareCanaryIngresses returns expected patch") @@ -163,18 +264,21 @@ func TestCanaryIngressRetainIngressClass(t *testing.T) { Rollout: fakeRollout("stable-service", "canary-service", "stable-ingress"), }, } - stableIngress := ingress("stable-ingress", 80, "stable-service") - stableIngress.SetAnnotations(map[string]string{ + stable := extensionsIngress("stable-ingress", 80, "stable-service") + stable.SetAnnotations(map[string]string{ "kubernetes.io/ingress.class": "nginx-foo", }) + stableIngress := ingressutil.NewLegacyIngress(stable) + desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 15) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") - assert.Equal(t, "true", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") - assert.Equal(t, "15", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") - assert.Equal(t, "nginx-foo", desiredCanaryIngress.Annotations["kubernetes.io/ingress.class"], "ingress-class annotation retained") + annotations := desiredCanaryIngress.GetAnnotations() + assert.Equal(t, "true", annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "15", annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.Equal(t, "nginx-foo", annotations["kubernetes.io/ingress.class"], "ingress-class annotation retained") } func TestCanaryIngressAdditionalAnnotations(t *testing.T) { @@ -187,17 +291,49 @@ func TestCanaryIngressAdditionalAnnotations(t *testing.T) { "canary-by-header": "X-Foo", "canary-by-header-value": "DoCanary", } - stableIngress := ingress("stable-ingress", 80, "stable-service") + stable := extensionsIngress("stable-ingress", 80, "stable-service") + stableIngress := ingressutil.NewLegacyIngress(stable) desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 15) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") - assert.Equal(t, "true", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") - assert.Equal(t, "15", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") - assert.Equal(t, "X-Foo", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary-by-header"], "canary-by-header annotation set") - assert.Equal(t, "DoCanary", desiredCanaryIngress.Annotations["nginx.ingress.kubernetes.io/canary-by-header-value"], "canary-by-header-value annotation set") + annotations := desiredCanaryIngress.GetAnnotations() + assert.Equal(t, "true", annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "15", annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.Equal(t, "X-Foo", annotations["nginx.ingress.kubernetes.io/canary-by-header"], "canary-by-header annotation set") + assert.Equal(t, "DoCanary", annotations["nginx.ingress.kubernetes.io/canary-by-header-value"], "canary-by-header-value annotation set") +} + +func TestReconciler_canaryIngress(t *testing.T) { + t.Run("will build desired networking ingress successfully", func(t *testing.T) { + // given + t.Parallel() + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRollout("stable-service", "canary-service", "stable-ingress"), + }, + } + stableIngress := networkingIngress("stable-ingress", 80, "stable-service") + stableIngress.Spec.IngressClassName = pointer.StringPtr("nginx-ext") + i := ingressutil.NewIngress(stableIngress) + + // when + desiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 10) + + // then + assert.Nil(t, err, "No error returned when calling canaryIngress") + checkBackendService(t, desiredCanaryIngress, "canary-service") + desired, err := desiredCanaryIngress.GetNetworkingIngress() + if err != nil { + t.Fatal(err) + } + assert.Equal(t, "true", desired.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "10", desired.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.NotNil(t, desired.Spec.IngressClassName) + assert.Equal(t, "nginx-ext", *desired.Spec.IngressClassName) + }) } func TestType(t *testing.T) { @@ -216,34 +352,42 @@ func TestReconcileStableIngressNotFound(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) - err := r.SetWeight(10) + err = r.SetWeight(10) assert.NotNil(t, err, "Reconcile returns error") } func TestReconcileStableIngressFound(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") - stableIngress := ingress("stable-ingress", 80, "stable-service") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) - err := r.SetWeight(10) + err = r.SetWeight(10) assert.Nil(t, err, "Reconcile returns no error") actions := client.Actions() assert.Len(t, actions, 1) @@ -256,42 +400,50 @@ func TestReconcileStableIngressFound(t *testing.T) { func TestReconcileStableIngressFoundWrongBackend(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") - stableIngress := ingress("stable-ingress", 80, "other-service") + stableIngress := extensionsIngress("stable-ingress", 80, "other-service") client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) - err := r.SetWeight(10) + err = r.SetWeight(10) assert.NotNil(t, err, "Reconcile returns error") assert.Contains(t, err.Error(), "has no rules using service", "correct error is returned") } func TestReconcileStableAndCanaryIngressFoundNoOwner(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") - stableIngress := ingress("stable-ingress", 80, "stable-service") - canaryIngress := ingress("rollout-stable-ingress-canary", 80, "canary-service") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + canaryIngress := extensionsIngress("rollout-stable-ingress-canary", 80, "canary-service") client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(canaryIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) - err := r.SetWeight(10) + err = r.SetWeight(10) assert.NotNil(t, err, "Reconcile returns error") } @@ -299,30 +451,34 @@ func TestReconcileStableAndCanaryIngressFoundBadOwner(t *testing.T) { otherRollout := fakeRollout("stable-service2", "canary-service2", "stable-ingress2") otherRollout.SetUID("4b712b69-5de9-11ea-a10a-0a9ba5899dd2") rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") - stableIngress := ingress("stable-ingress", 80, "stable-service") - canaryIngress := ingress("rollout-stable-ingress-canary", 80, "canary-service") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + canaryIngress := extensionsIngress("rollout-stable-ingress-canary", 80, "canary-service") setIngressOwnerRef(canaryIngress, otherRollout) client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(canaryIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) - err := r.SetWeight(10) + err = r.SetWeight(10) assert.NotNil(t, err, "Reconcile returns error") } func TestReconcileStableAndCanaryIngressFoundPatch(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") - stableIngress := ingress("stable-ingress", 80, "stable-service") - canaryIngress := ingress("rollout-stable-ingress-canary", 80, "canary-service") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + canaryIngress := extensionsIngress("rollout-stable-ingress-canary", 80, "canary-service") canaryIngress.SetAnnotations(map[string]string{ "nginx.ingress.kubernetes.io/canary": "true", "nginx.ingress.kubernetes.io/canary-weight": "15", @@ -332,15 +488,19 @@ func TestReconcileStableAndCanaryIngressFoundPatch(t *testing.T) { k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(canaryIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) - err := r.SetWeight(10) + err = r.SetWeight(10) assert.Nil(t, err, "Reconcile returns no error") actions := client.Actions() assert.Len(t, actions, 1) @@ -353,8 +513,8 @@ func TestReconcileStableAndCanaryIngressFoundPatch(t *testing.T) { func TestReconcileStableAndCanaryIngressFoundNoChange(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") - stableIngress := ingress("stable-ingress", 80, "stable-service") - canaryIngress := ingress("rollout-stable-ingress-canary", 80, "canary-service") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + canaryIngress := extensionsIngress("rollout-stable-ingress-canary", 80, "canary-service") setIngressOwnerRef(canaryIngress, rollout) canaryIngress.SetAnnotations(map[string]string{ "nginx.ingress.kubernetes.io/canary": "true", @@ -364,16 +524,19 @@ func TestReconcileStableAndCanaryIngressFoundNoChange(t *testing.T) { k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(canaryIngress) - + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) - err := r.SetWeight(10) + err = r.SetWeight(10) assert.Nil(t, err, "Reconcile returns no error") actions := client.Actions() assert.Len(t, actions, 0) @@ -381,7 +544,7 @@ func TestReconcileStableAndCanaryIngressFoundNoChange(t *testing.T) { func TestReconcileCanaryCreateError(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") - stableIngress := ingress("stable-ingress", 80, "stable-service") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") client := fake.NewSimpleClientset() client.ReactionChain = nil @@ -389,13 +552,17 @@ func TestReconcileCanaryCreateError(t *testing.T) { // stableIngress exists k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) // Return with AlreadyExists error to create for canary @@ -403,7 +570,7 @@ func TestReconcileCanaryCreateError(t *testing.T) { return true, nil, errors.New("fake error") }) - err := r.SetWeight(10) + err = r.SetWeight(10) assert.NotNil(t, err, "Reconcile returns error") assert.Equal(t, "error creating canary ingress `rollout-stable-ingress-canary`: fake error", err.Error()) actions := client.Actions() @@ -417,8 +584,8 @@ func TestReconcileCanaryCreateError(t *testing.T) { func TestReconcileCanaryCreateErrorAlreadyExistsPatch(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") - stableIngress := ingress("stable-ingress", 80, "stable-service") - canaryIngress := ingress("rollout-stable-ingress-canary", 80, "canary-service") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + canaryIngress := extensionsIngress("rollout-stable-ingress-canary", 80, "canary-service") canaryIngress.SetAnnotations(map[string]string{ "nginx.ingress.kubernetes.io/canary": "true", "nginx.ingress.kubernetes.io/canary-weight": "15", @@ -431,13 +598,17 @@ func TestReconcileCanaryCreateErrorAlreadyExistsPatch(t *testing.T) { // stableIngress exists k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } r := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, Recorder: record.NewFakeEventRecorder(), ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, - IngressLister: k8sI.Extensions().V1beta1().Ingresses().Lister(), + IngressWrapper: ingressWrapper, }) // Return with AlreadyExists error to create for canary @@ -453,7 +624,7 @@ func TestReconcileCanaryCreateErrorAlreadyExistsPatch(t *testing.T) { return true, canaryIngress, nil }) - err := r.SetWeight(10) + err = r.SetWeight(10) assert.Nil(t, err, "Reconcile returns no error") actions := client.Actions() assert.Len(t, actions, 3) diff --git a/utils/ingress/ingress.go b/utils/ingress/ingress.go index 974e11961a..e2662e0ddb 100644 --- a/utils/ingress/ingress.go +++ b/utils/ingress/ingress.go @@ -1,12 +1,17 @@ package ingress import ( + "errors" "fmt" + "strconv" "strings" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + networkingv1 "k8s.io/api/networking/v1" + "k8s.io/client-go/discovery" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/utils/diff" ) const ( @@ -89,7 +94,32 @@ func GetCanaryIngressName(rollout *v1alpha1.Rollout) string { } // HasRuleWithService check if an Ingress has a service in one of it's rules -func HasRuleWithService(ingress *extensionsv1beta1.Ingress, svc string) bool { +func HasRuleWithService(i *Ingress, svc string) bool { + switch i.mode { + case IngressModeNetworking: + return hasIngressRuleWithService(i.ingress, svc) + case IngressModeExtensions: + return hasLegacyIngressRuleWithService(i.legacyIngress, svc) + default: + return false + } + +} + +func hasIngressRuleWithService(ingress *networkingv1.Ingress, svc string) bool { + for _, rule := range ingress.Spec.Rules { + if rule.HTTP != nil { + for _, path := range rule.HTTP.Paths { + if path.Backend.Service.Name == svc { + return true + } + } + } + } + return false +} + +func hasLegacyIngressRuleWithService(ingress *extensionsv1beta1.Ingress, svc string) bool { for _, rule := range ingress.Spec.Rules { if rule.HTTP != nil { for _, path := range rule.HTTP.Paths { @@ -146,3 +176,115 @@ func ALBActionAnnotationKey(r *v1alpha1.Rollout) string { } return fmt.Sprintf("%s%s%s", prefix, ALBActionPrefix, actionService) } + +type patchConfig struct { + withAnnotations bool + withLabels bool + withSpec bool +} + +type PatchOption func(p *patchConfig) + +func WithAnnotations() PatchOption { + return func(p *patchConfig) { + p.withAnnotations = true + } +} + +func WithLabels() PatchOption { + return func(p *patchConfig) { + p.withLabels = true + } +} + +func WithSpec() PatchOption { + return func(p *patchConfig) { + p.withSpec = true + } +} + +func BuildIngressPatch(mode IngressMode, current, desired *Ingress, opts ...PatchOption) ([]byte, bool, error) { + cfg := &patchConfig{} + for _, opt := range opts { + opt(cfg) + } + + switch mode { + case IngressModeNetworking: + return buildIngressPatch(current.ingress, desired.ingress, cfg) + case IngressModeExtensions: + return buildIngressPatchLegacy(current.legacyIngress, desired.legacyIngress, cfg) + default: + return nil, false, errors.New("error building annotations patch: undefined ingress mode") + } +} + +func buildIngressPatch(current, desired *networkingv1.Ingress, cfg *patchConfig) ([]byte, bool, error) { + cur := &networkingv1.Ingress{} + des := &networkingv1.Ingress{} + if cfg.withAnnotations { + cur.Annotations = current.Annotations + des.Annotations = desired.Annotations + } + if cfg.withLabels { + cur.Labels = current.Labels + des.Labels = desired.Labels + } + if cfg.withSpec { + cur.Spec = current.Spec + des.Spec = desired.Spec + } + return diff.CreateTwoWayMergePatch(cur, des, networkingv1.Ingress{}) +} + +func buildIngressPatchLegacy(current, desired *extensionsv1beta1.Ingress, cfg *patchConfig) ([]byte, bool, error) { + cur := &extensionsv1beta1.Ingress{} + des := &extensionsv1beta1.Ingress{} + if cfg.withAnnotations { + cur.Annotations = current.Annotations + des.Annotations = desired.Annotations + } + if cfg.withLabels { + cur.Labels = current.Labels + des.Labels = desired.Labels + } + if cfg.withSpec { + cur.Spec = current.Spec + des.Spec = desired.Spec + } + return diff.CreateTwoWayMergePatch(cur, des, extensionsv1beta1.Ingress{}) +} + +// DetermineIngressMode will first attempt to determine the ingress mode by checking +// the given apiVersion. If it is "extensions/v1beta1" will return IngressModeExtensions. +// If it is "networking/v1" will return IngressModeNetworking. Otherwise it will check +// the kubernetes server version to determine the ingress mode. +func DetermineIngressMode(apiVersion string, d discovery.ServerVersionInterface) (IngressMode, error) { + if apiVersion == "extensions/v1beta1" { + return IngressModeExtensions, nil + } + if apiVersion == "networking/v1" { + return IngressModeNetworking, nil + } + + ver, err := d.ServerVersion() + if err != nil { + return 0, err + } + major, err := strconv.Atoi(ver.Major) + if err != nil { + return 0, err + } + minor, err := strconv.Atoi(ver.Minor) + if err != nil { + return 0, err + } + if major > 1 { + return IngressModeNetworking, nil + } + if major == 1 && minor >= 19 { + return IngressModeNetworking, nil + } + return IngressModeExtensions, nil + +} diff --git a/utils/ingress/ingress_test.go b/utils/ingress/ingress_test.go index 4c3d24c8e9..36a013ee4a 100644 --- a/utils/ingress/ingress_test.go +++ b/utils/ingress/ingress_test.go @@ -1,13 +1,20 @@ package ingress import ( + "errors" "fmt" + "strconv" "strings" "testing" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/version" + "k8s.io/client-go/discovery" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" ) @@ -94,23 +101,136 @@ func TestGetCanaryIngressName(t *testing.T) { } func TestHasRuleWithService(t *testing.T) { - ingress := &extensionsv1beta1.Ingress{ - Spec: extensionsv1beta1.IngressSpec{ - Rules: []extensionsv1beta1.IngressRule{{ - IngressRuleValue: extensionsv1beta1.IngressRuleValue{ - HTTP: &extensionsv1beta1.HTTPIngressRuleValue{ - Paths: []extensionsv1beta1.HTTPIngressPath{{ - Backend: extensionsv1beta1.IngressBackend{ - ServiceName: "test", - }, - }}, + t.Run("will check rule with legacy ingress", func(t *testing.T) { + // given + t.Parallel() + ingress := &extensionsv1beta1.Ingress{ + Spec: extensionsv1beta1.IngressSpec{ + Rules: []extensionsv1beta1.IngressRule{{ + IngressRuleValue: extensionsv1beta1.IngressRuleValue{ + HTTP: &extensionsv1beta1.HTTPIngressRuleValue{ + Paths: []extensionsv1beta1.HTTPIngressPath{{ + Backend: extensionsv1beta1.IngressBackend{ + ServiceName: "test", + }, + }}, + }, }, - }, - }}, - }, - } - assert.False(t, HasRuleWithService(ingress, "not-found")) - assert.True(t, HasRuleWithService(ingress, "test")) + }}, + }, + } + i := NewLegacyIngress(ingress) + + // then + assert.False(t, HasRuleWithService(i, "not-found")) + assert.True(t, HasRuleWithService(i, "test")) + }) + t.Run("will check rule with networking ingress", func(t *testing.T) { + // given + t.Parallel() + ingress := &networkingv1.Ingress{ + Spec: networkingv1.IngressSpec{ + Rules: []networkingv1.IngressRule{{ + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{{ + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + }, + }, + }}, + }, + }, + }}, + }, + } + i := NewIngress(ingress) + + // then + assert.False(t, HasRuleWithService(i, "not-found")) + assert.True(t, HasRuleWithService(i, "test")) + }) + t.Run("will return false if invalid IngressMode passed", func(t *testing.T) { + // given + t.Parallel() + invalid_ingress := &Ingress{} + + // then + assert.False(t, HasRuleWithService(invalid_ingress, "test")) + }) +} + +func TestBuildIngressPath(t *testing.T) { + t.Run("will build network ingress patch successfully", func(t *testing.T) { + // given + t.Parallel() + i1 := getNetworkingIngress() + i2 := getNetworkingIngress() + annotations := i2.GetAnnotations() + annotations["annotation-key1"] = "changed-annotation1" + + labels := i2.GetLabels() + labels["label-key1"] = "changed-label1" + + i2.SetAnnotations(annotations) + i2.SetLabels(labels) + className := "modified-ingress-class" + i2.Spec.IngressClassName = &className + ingress1 := NewIngress(i1) + ingress2 := NewIngress(i2) + + expected_patch := `{"metadata":{"annotations":{"annotation-key1":"changed-annotation1"},"labels":{"label-key1":"changed-label1"}},"spec":{"ingressClassName":"modified-ingress-class"}}` + + // when + patch, ok, err := BuildIngressPatch(IngressModeNetworking, ingress1, ingress2, WithLabels(), WithAnnotations(), WithSpec()) + + // then + assert.NoError(t, err) + assert.True(t, ok) + assert.Equal(t, expected_patch, string(patch)) + }) + t.Run("will build extensions ingress patch successfully", func(t *testing.T) { + t.Parallel() + i1 := getExtensionsIngress() + i2 := getExtensionsIngress() + annotations := i2.GetAnnotations() + annotations["annotation-key1"] = "changed-annotation1" + + labels := i2.GetLabels() + labels["label-key1"] = "changed-label1" + + i2.SetAnnotations(annotations) + i2.SetLabels(labels) + className := "modified-ingress-class" + i2.Spec.IngressClassName = &className + ingress1 := NewLegacyIngress(i1) + ingress2 := NewLegacyIngress(i2) + + expected_patch := `{"metadata":{"annotations":{"annotation-key1":"changed-annotation1"},"labels":{"label-key1":"changed-label1"}},"spec":{"ingressClassName":"modified-ingress-class"}}` + + // when + patch, ok, err := BuildIngressPatch(IngressModeExtensions, ingress1, ingress2, WithLabels(), WithAnnotations(), WithSpec()) + + // then + assert.NoError(t, err) + assert.True(t, ok) + assert.Equal(t, expected_patch, string(patch)) + }) + t.Run("will return error if invalid ingress mode passed", func(t *testing.T) { + // given + t.Parallel() + ingress1 := NewLegacyIngress(getExtensionsIngress()) + ingress2 := NewLegacyIngress(getExtensionsIngress()) + + // when + patch, ok, err := BuildIngressPatch(9999, ingress1, ingress2, WithLabels(), WithAnnotations(), WithSpec()) + + // then + assert.Error(t, err) + assert.False(t, ok) + assert.Equal(t, "", string(patch)) + }) } func TestManagedALBActions(t *testing.T) { @@ -170,3 +290,199 @@ func TestALBActionAnnotationKey(t *testing.T) { assert.Equal(t, "alb.ingress.kubernetes.io/actions.root-svc", ALBActionAnnotationKey(r)) } + +func TestDetermineIngressMode(t *testing.T) { + type testCase struct { + name string + apiVersion string + faKeDiscovery discovery.ServerVersionInterface + expectedMode IngressMode + expectedError error + } + + cases := []*testCase{ + { + name: "will return extensions mode if apiVersion is extensions/v1beta1", + apiVersion: "extensions/v1beta1", + expectedMode: IngressModeExtensions, + }, + { + name: "will return networking mode if apiVersion is networking/v1", + apiVersion: "networking/v1", + expectedMode: IngressModeNetworking, + }, + { + name: "will return networking mode if server version is 1.19", + apiVersion: "", + faKeDiscovery: newFakeDiscovery("1", "19", nil), + expectedMode: IngressModeNetworking, + }, + { + name: "will return networking mode if server version is 2.0", + apiVersion: "", + faKeDiscovery: newFakeDiscovery("2", "0", nil), + expectedMode: IngressModeNetworking, + }, + { + name: "will return extensions mode if server version is 1.18", + apiVersion: "", + faKeDiscovery: newFakeDiscovery("1", "18", nil), + expectedMode: IngressModeExtensions, + }, + { + name: "will return error if fails to retrieve server version", + apiVersion: "", + faKeDiscovery: newFakeDiscovery("", "", errors.New("internal server error")), + expectedMode: 0, + expectedError: errors.New("internal server error"), + }, + { + name: "will return error if fails to parse major version", + apiVersion: "", + faKeDiscovery: newFakeDiscovery("wrong", "", nil), + expectedMode: 0, + expectedError: &strconv.NumError{ + Func: "Atoi", + Num: "wrong", + Err: errors.New("invalid syntax"), + }, + }, + { + name: "will return error if fails to parse minor version", + apiVersion: "", + faKeDiscovery: newFakeDiscovery("1", "wrong", nil), + expectedMode: 0, + expectedError: &strconv.NumError{ + Func: "Atoi", + Num: "wrong", + Err: errors.New("invalid syntax"), + }, + }, + } + for _, c := range cases { + c := c // necessary to ensure all test cases are executed when running in parallel mode + + t.Run(c.name, func(t *testing.T) { + // given + t.Parallel() + + // when + mode, err := DetermineIngressMode(c.apiVersion, c.faKeDiscovery) + + // then + assert.Equal(t, c.expectedError, err) + assert.Equal(t, c.expectedMode, mode) + }) + } +} + +type fakeDiscovery struct { + major, minor string + err error +} + +func newFakeDiscovery(major, minor string, err error) *fakeDiscovery { + return &fakeDiscovery{ + major: major, + minor: minor, + err: err, + } +} + +func (f *fakeDiscovery) ServerVersion() (*version.Info, error) { + if f.err != nil { + return nil, f.err + } + return &version.Info{ + Major: f.major, + Minor: f.minor, + }, nil +} + +func getNetworkingIngress() *networkingv1.Ingress { + ingressClassName := "ingress-name" + return &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "networking-ingress", + Namespace: "some-namespace", + Annotations: map[string]string{ + "annotation-key1": "annotation-value1", + }, + Labels: map[string]string{ + "label-key1": "label-value1", + "label-key2": "label-value2", + }, + }, + Spec: networkingv1.IngressSpec{ + IngressClassName: &ingressClassName, + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "backend", + Port: networkingv1.ServiceBackendPort{ + Name: "http", + Number: 8080, + }, + }, + }, + }, + Status: networkingv1.IngressStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + IP: "127.0.0.1", + Hostname: "localhost", + Ports: []corev1.PortStatus{ + { + Port: 8080, + Protocol: "http", + }, + }, + }, + }, + }, + }, + } +} + +func getExtensionsIngress() *extensionsv1beta1.Ingress { + ingressClassName := "ingress-name" + return &extensionsv1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "extensions-ingress", + Namespace: "some-namespace", + Annotations: map[string]string{ + "annotation-key1": "annotation-value1", + }, + Labels: map[string]string{ + "label-key1": "label-value1", + "label-key2": "label-value2", + }, + }, + Spec: extensionsv1beta1.IngressSpec{ + IngressClassName: &ingressClassName, + Backend: &extensionsv1beta1.IngressBackend{ + ServiceName: "some-service", + ServicePort: intstr.IntOrString{ + Type: intstr.String, + StrVal: "8080", + }, + }, + }, + Status: extensionsv1beta1.IngressStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + IP: "127.0.0.1", + Hostname: "localhost", + Ports: []corev1.PortStatus{ + { + Port: 8080, + Protocol: "http", + }, + }, + }, + }, + }, + }, + } +} diff --git a/utils/ingress/wrapper.go b/utils/ingress/wrapper.go new file mode 100644 index 0000000000..1d28c8021d --- /dev/null +++ b/utils/ingress/wrapper.go @@ -0,0 +1,370 @@ +package ingress + +import ( + "context" + "errors" + "sync" + + corev1 "k8s.io/api/core/v1" + "k8s.io/api/extensions/v1beta1" + v1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/informers" + extensionsv1beta1 "k8s.io/client-go/informers/extensions/v1beta1" + networkingv1 "k8s.io/client-go/informers/networking/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" +) + +// Ingress defines an Ingress resource abstraction used to allow Rollouts to +// work with the newer 'networking' package as well as with the legacy extensions +// package. +type Ingress struct { + ingress *v1.Ingress + legacyIngress *v1beta1.Ingress + mode IngressMode + mux *sync.Mutex +} + +// NewIngress will instantiate and return an Ingress with the given +// Ingress from networking/v1 package +func NewIngress(i *v1.Ingress) *Ingress { + return &Ingress{ + ingress: i, + mode: IngressModeNetworking, + mux: &sync.Mutex{}, + } +} + +// NewLegacyIngress will instantiate and return an Ingress with the given +// Ingress from extensions/v1beta1 package +func NewLegacyIngress(li *v1beta1.Ingress) *Ingress { + return &Ingress{ + legacyIngress: li, + mode: IngressModeExtensions, + mux: &sync.Mutex{}, + } +} + +func NewIngressWithAnnotations(mode IngressMode, annotations map[string]string) *Ingress { + switch mode { + case IngressModeNetworking: + i := &v1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: annotations, + }, + } + return NewIngress(i) + case IngressModeExtensions: + i := &v1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: annotations, + }, + } + return NewLegacyIngress(i) + default: + return nil + } +} + +func (i *Ingress) GetExtensionsIngress() (*v1beta1.Ingress, error) { + if i.legacyIngress == nil { + return nil, errors.New("extensions Ingress is nil in this wrapper") + } + return i.legacyIngress, nil +} + +func (i *Ingress) GetNetworkingIngress() (*v1.Ingress, error) { + if i.ingress == nil { + return nil, errors.New("networking Ingress is nil in this wrapper") + } + return i.ingress, nil +} + +func (i *Ingress) GetAnnotations() map[string]string { + i.mux.Lock() + defer i.mux.Unlock() + switch i.mode { + case IngressModeNetworking: + return i.ingress.GetAnnotations() + case IngressModeExtensions: + return i.legacyIngress.GetAnnotations() + default: + return make(map[string]string) + } +} + +func (i *Ingress) GetLabels() map[string]string { + switch i.mode { + case IngressModeNetworking: + return i.ingress.GetLabels() + case IngressModeExtensions: + return i.legacyIngress.GetLabels() + default: + return make(map[string]string) + } +} + +func (i *Ingress) GetObjectMeta() metav1.Object { + switch i.mode { + case IngressModeNetworking: + return i.ingress.GetObjectMeta() + case IngressModeExtensions: + return i.legacyIngress.GetObjectMeta() + default: + return nil + } +} + +func (i *Ingress) SetAnnotations(annotations map[string]string) { + i.mux.Lock() + defer i.mux.Unlock() + switch i.mode { + case IngressModeNetworking: + i.ingress.SetAnnotations(annotations) + case IngressModeExtensions: + i.legacyIngress.SetAnnotations(annotations) + } +} + +func (i *Ingress) DeepCopy() *Ingress { + switch i.mode { + case IngressModeNetworking: + ing := i.ingress.DeepCopy() + return NewIngress(ing) + case IngressModeExtensions: + ing := i.legacyIngress.DeepCopy() + return NewLegacyIngress(ing) + default: + return nil + } +} + +func (i *Ingress) GetName() string { + switch i.mode { + case IngressModeNetworking: + return i.ingress.GetName() + case IngressModeExtensions: + return i.legacyIngress.GetName() + default: + return "" + } +} + +func (i *Ingress) GetNamespace() string { + switch i.mode { + case IngressModeNetworking: + return i.ingress.GetNamespace() + case IngressModeExtensions: + return i.legacyIngress.GetNamespace() + default: + return "" + } +} + +func (i *Ingress) GetLoadBalancerStatus() corev1.LoadBalancerStatus { + switch i.mode { + case IngressModeNetworking: + return i.ingress.Status.LoadBalancer + case IngressModeExtensions: + return i.legacyIngress.Status.LoadBalancer + default: + return corev1.LoadBalancerStatus{} + } +} + +func (i *Ingress) Mode() IngressMode { + return i.mode +} + +// IngressWrap wraps the two ingress informers provided by the client-go. This is used +// to centralize the ingress informer operations to allow Rollouts to interact with +// both versions. +type IngressWrap struct { + client kubernetes.Interface + mode IngressMode + ingressInformer networkingv1.IngressInformer + legacyIngressInformer extensionsv1beta1.IngressInformer +} + +type IngressMode int + +const ( + IngressModeExtensions IngressMode = iota + 1 // start iota with 1 to avoid having this as default value + IngressModeNetworking +) + +func NewIngressWrapper(mode IngressMode, client kubernetes.Interface, informerFactory informers.SharedInformerFactory) (*IngressWrap, error) { + var ingressInformer networkingv1.IngressInformer + var legacyIngressInformer extensionsv1beta1.IngressInformer + switch mode { + case IngressModeNetworking: + ingressInformer = informerFactory.Networking().V1().Ingresses() + case IngressModeExtensions: + legacyIngressInformer = informerFactory.Extensions().V1beta1().Ingresses() + default: + return nil, errors.New("error creating ingress wrapper: undefined ingress mode") + } + return &IngressWrap{ + client: client, + mode: mode, + ingressInformer: ingressInformer, + legacyIngressInformer: legacyIngressInformer, + }, nil +} + +func (w *IngressWrap) Informer() cache.SharedIndexInformer { + switch w.mode { + case IngressModeNetworking: + return w.ingressInformer.Informer() + case IngressModeExtensions: + return w.legacyIngressInformer.Informer() + default: + return nil + } +} + +func (w *IngressWrap) Patch(ctx context.Context, namespace, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*Ingress, error) { + switch w.mode { + case IngressModeNetworking: + return w.patch(ctx, namespace, name, pt, data, opts, subresources...) + case IngressModeExtensions: + return w.patchLegacy(ctx, namespace, name, pt, data, opts, subresources...) + default: + return nil, errors.New("ingress patch error: undefined ingress mode") + } +} + +func (w *IngressWrap) patch(ctx context.Context, namespace, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*Ingress, error) { + i, err := w.client.NetworkingV1().Ingresses(namespace).Patch(ctx, name, pt, data, opts, subresources...) + if err != nil { + return nil, err + } + return NewIngress(i), nil +} + +func (w *IngressWrap) patchLegacy(ctx context.Context, namespace, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*Ingress, error) { + li, err := w.client.ExtensionsV1beta1().Ingresses(namespace).Patch(ctx, name, pt, data, opts, subresources...) + if err != nil { + return nil, err + } + return NewLegacyIngress(li), nil +} + +func (w *IngressWrap) Update(ctx context.Context, namespace string, ingress *Ingress) (*Ingress, error) { + switch w.mode { + case IngressModeNetworking: + return w.update(ctx, namespace, ingress) + case IngressModeExtensions: + return w.legacyUpdate(ctx, namespace, ingress) + default: + return nil, errors.New("error updating ingress: undefined ingress mode") + } +} + +func (w *IngressWrap) update(ctx context.Context, namespace string, ingress *Ingress) (*Ingress, error) { + i, err := w.client.NetworkingV1().Ingresses(namespace).Update(ctx, ingress.ingress, metav1.UpdateOptions{}) + if err != nil { + return nil, err + } + return NewIngress(i), nil +} + +func (w *IngressWrap) legacyUpdate(ctx context.Context, namespace string, ingress *Ingress) (*Ingress, error) { + li, err := w.client.ExtensionsV1beta1().Ingresses(namespace).Update(ctx, ingress.legacyIngress, metav1.UpdateOptions{}) + if err != nil { + return nil, err + } + return NewLegacyIngress(li), nil +} +func (w *IngressWrap) Get(ctx context.Context, namespace, name string, opts metav1.GetOptions) (*Ingress, error) { + switch w.mode { + case IngressModeNetworking: + return w.get(ctx, namespace, name, opts) + case IngressModeExtensions: + return w.getLegacy(ctx, namespace, name, opts) + default: + return nil, errors.New("error running IngressWrap.Get: undefined ingress mode") + } +} + +func (w *IngressWrap) get(ctx context.Context, namespace, name string, opts metav1.GetOptions) (*Ingress, error) { + ing, err := w.client.NetworkingV1().Ingresses(namespace).Get(ctx, name, opts) + if err != nil { + return nil, err + } + return NewIngress(ing), nil +} + +func (w *IngressWrap) getLegacy(ctx context.Context, namespace, name string, opts metav1.GetOptions) (*Ingress, error) { + ing, err := w.client.ExtensionsV1beta1().Ingresses(namespace).Get(ctx, name, opts) + if err != nil { + return nil, err + } + return NewLegacyIngress(ing), nil +} + +func (w *IngressWrap) GetCached(namespace, name string) (*Ingress, error) { + switch w.mode { + case IngressModeNetworking: + return w.getCached(namespace, name) + case IngressModeExtensions: + return w.getCachedLegacy(namespace, name) + default: + return nil, errors.New("error running IngressWrap.GetCached: undefined ingress mode") + } +} + +func (w *IngressWrap) getCached(namespace, name string) (*Ingress, error) { + ing, err := w.ingressInformer.Lister().Ingresses(namespace).Get(name) + if err != nil { + return nil, err + } + return NewIngress(ing), nil +} +func (w *IngressWrap) getCachedLegacy(namespace, name string) (*Ingress, error) { + li, err := w.legacyIngressInformer.Lister().Ingresses(namespace).Get(name) + if err != nil { + return nil, err + } + return NewLegacyIngress(li), nil +} + +func (w *IngressWrap) Create(ctx context.Context, namespace string, ingress *Ingress, opts metav1.CreateOptions) (*Ingress, error) { + switch w.mode { + case IngressModeNetworking: + return w.create(ctx, namespace, ingress.ingress, opts) + case IngressModeExtensions: + return w.createLegacy(ctx, namespace, ingress.legacyIngress, opts) + default: + return nil, errors.New("error creating ingress: undefined ingress mode") + } +} + +func (w *IngressWrap) create(ctx context.Context, namespace string, ingress *v1.Ingress, opts metav1.CreateOptions) (*Ingress, error) { + i, err := w.client.NetworkingV1().Ingresses(namespace).Create(ctx, ingress, opts) + if err != nil { + return nil, err + } + return NewIngress(i), nil +} + +func (w *IngressWrap) createLegacy(ctx context.Context, namespace string, ingress *v1beta1.Ingress, opts metav1.CreateOptions) (*Ingress, error) { + li, err := w.client.ExtensionsV1beta1().Ingresses(namespace).Create(ctx, ingress, opts) + if err != nil { + return nil, err + } + return NewLegacyIngress(li), nil +} + +func (w *IngressWrap) HasSynced() bool { + switch w.mode { + case IngressModeNetworking: + return w.ingressInformer.Informer().HasSynced() + case IngressModeExtensions: + return w.legacyIngressInformer.Informer().HasSynced() + default: + return false + } +} diff --git a/utils/ingress/wrapper_test.go b/utils/ingress/wrapper_test.go new file mode 100644 index 0000000000..eae08b4828 --- /dev/null +++ b/utils/ingress/wrapper_test.go @@ -0,0 +1,738 @@ +package ingress_test + +import ( + "context" + "testing" + + "github.com/argoproj/argo-rollouts/utils/ingress" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + "k8s.io/api/extensions/v1beta1" + v1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + kubeinformers "k8s.io/client-go/informers" + k8sfake "k8s.io/client-go/kubernetes/fake" +) + +func TestNewIngressWithAnnotations(t *testing.T) { + annotations := make(map[string]string) + annotations["some.annotation.key1"] = "some.annotation.value1" + annotations["some.annotation.key2"] = "some.annotation.value2" + getAnnotations := func() map[string]string { + annotations := make(map[string]string) + annotations["some.annotation.key1"] = "some.annotation.value1" + annotations["some.annotation.key2"] = "some.annotation.value2" + return annotations + } + t.Run("will instantiate an Ingress wrapped with an annotated networkingv1.Ingress", func(t *testing.T) { + // given + t.Parallel() + + // when + i := ingress.NewIngressWithAnnotations(ingress.IngressModeNetworking, getAnnotations()) + + // then + assert.NotNil(t, i) + a := i.GetAnnotations() + assert.Equal(t, 2, len(a)) + a["extra-annotation-key"] = "extra-annotation-value" + i.SetAnnotations(a) + assert.Equal(t, 3, len(a)) + }) + t.Run("will instantiate an Ingress wrapped with an annotated extensions/v1beta1.Ingress", func(t *testing.T) { + // given + t.Parallel() + + // when + i := ingress.NewIngressWithAnnotations(ingress.IngressModeExtensions, getAnnotations()) + + // then + assert.NotNil(t, i) + a := i.GetAnnotations() + assert.Equal(t, 2, len(a)) + a["extra-annotation-key"] = "extra-annotation-value" + i.SetAnnotations(a) + assert.Equal(t, 3, len(a)) + }) + t.Run("will return nil if ingress mode is undefined", func(t *testing.T) { + // given + t.Parallel() + + // when + i := ingress.NewIngressWithAnnotations(99999, getAnnotations()) + + // then + assert.Nil(t, i) + }) +} + +func TestGetExtensionsIngress(t *testing.T) { + extensionsIngress := &v1beta1.Ingress{} + t.Run("will get extensions ingress successfully", func(t *testing.T) { + // given + t.Parallel() + i := ingress.NewLegacyIngress(extensionsIngress) + + // when + result, err := i.GetExtensionsIngress() + + // then + assert.Nil(t, err) + assert.NotNil(t, result) + }) + t.Run("will return error if wrapper has nil reference to the extensionsIngress", func(t *testing.T) { + // given + t.Parallel() + i := ingress.NewLegacyIngress(nil) + + // when + result, err := i.GetExtensionsIngress() + + // then + assert.NotNil(t, err) + assert.Nil(t, result) + }) +} + +func TestGetNetworkingIngress(t *testing.T) { + networkingIngress := &v1.Ingress{} + t.Run("will get networkingv1 ingress successfully", func(t *testing.T) { + // given + t.Parallel() + i := ingress.NewIngress(networkingIngress) + + // when + result, err := i.GetNetworkingIngress() + + // then + assert.Nil(t, err) + assert.NotNil(t, result) + }) + t.Run("will return error if wrapper has nil reference to the networkingIngress", func(t *testing.T) { + // given + t.Parallel() + i := ingress.NewIngress(nil) + + // when + result, err := i.GetNetworkingIngress() + + // then + assert.NotNil(t, err) + assert.Nil(t, result) + }) +} + +func TestGetLabels(t *testing.T) { + t.Run("will get the labels from network Ingress successfully", func(t *testing.T) { + // given + t.Parallel() + i := getNetworkingIngress() + w := ingress.NewIngress(i) + + // when + labels := w.GetLabels() + + // then + assert.Equal(t, 2, len(labels)) + assert.Equal(t, "label-value1", labels["label-key1"]) + assert.Equal(t, "label-value2", labels["label-key2"]) + }) + t.Run("will get labels from extensions Ingress successfully", func(t *testing.T) { + // given + t.Parallel() + i := getExtensionsIngress() + + // when + w := ingress.NewLegacyIngress(i) + + // when + labels := w.GetLabels() + + // then + assert.Equal(t, 2, len(labels)) + assert.Equal(t, "label-value1", labels["label-key1"]) + assert.Equal(t, "label-value2", labels["label-key2"]) + }) +} + +func TestGetObjectMeta(t *testing.T) { + t.Run("will get object meta from wrapper with networking ingress", func(t *testing.T) { + // given + t.Parallel() + i := getNetworkingIngress() + ni := ingress.NewIngress(i) + + // when + om := ni.GetObjectMeta() + + // then + assert.Equal(t, "networking-ingress", om.GetName()) + assert.Equal(t, "some-namespace", om.GetNamespace()) + assert.Equal(t, 2, len(om.GetLabels())) + }) + t.Run("will get object meta from wrapper with extensions ingress", func(t *testing.T) { + // given + t.Parallel() + i := getExtensionsIngress() + li := ingress.NewLegacyIngress(i) + + // when + om := li.GetObjectMeta() + + // then + assert.Equal(t, "extensions-ingress", om.GetName()) + assert.Equal(t, "some-namespace", om.GetNamespace()) + assert.Equal(t, 2, len(om.GetLabels())) + }) +} + +func TestDeepCopy(t *testing.T) { + t.Run("will deepcopy ingress wrapped with networking.Ingress", func(t *testing.T) { + // given + t.Parallel() + ni := ingress.NewIngress(getNetworkingIngress()) + + // when + ni2 := ni.DeepCopy() + + // then + assert.Equal(t, ni, ni2) + assert.False(t, ni == ni2) + }) + t.Run("will deepcopy ingress wrapped with extensions.Ingress", func(t *testing.T) { + // given + t.Parallel() + li := ingress.NewLegacyIngress(getExtensionsIngress()) + + // when + ni2 := li.DeepCopy() + + // then + assert.Equal(t, li, ni2) + assert.False(t, li == ni2) + }) +} + +func TestGetLoadBalancerStatus(t *testing.T) { + t.Run("will get loadbalancer status from wrapped networking.Ingress", func(t *testing.T) { + // given + t.Parallel() + i := getNetworkingIngress() + ni := ingress.NewIngress(i) + + // when + lbs := ni.GetLoadBalancerStatus() + + // then + assert.Equal(t, i.Status.LoadBalancer, lbs) + }) + t.Run("will get loadbalancer status from wrapped extensions.Ingress", func(t *testing.T) { + // given + t.Parallel() + i := getExtensionsIngress() + li := ingress.NewLegacyIngress(i) + + // when + lbs := li.GetLoadBalancerStatus() + + // then + assert.Equal(t, i.Status.LoadBalancer, lbs) + }) +} + +func Test_IngressWrapNew(t *testing.T) { + t.Run("will return error if invalid ingress mode is passed", func(t *testing.T) { + // given + t.Parallel() + + // when + iw, err := ingress.NewIngressWrapper(9999, nil, nil) + + // then + assert.Error(t, err) + assert.Nil(t, iw) + }) +} + +func Test_IngressWrapPatch(t *testing.T) { + t.Run("will patch networking ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + + // when + ing, err := iw.Patch(context.Background(), "some-namespace", "networking-ingress", types.MergePatchType, []byte("{}"), metav1.PatchOptions{}) + + // then + assert.NoError(t, err) + assert.NotNil(t, ing) + ni, err := ing.GetNetworkingIngress() + assert.NoError(t, err) + assert.Equal(t, "backend", ni.Spec.DefaultBackend.Service.Name) + }) + t.Run("will return error if fails to patch networking ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + + // when + ing, err := iw.Patch(context.Background(), "not_found", "not_found", types.MergePatchType, []byte("{}"), metav1.PatchOptions{}) + + // then + assert.Error(t, err) + assert.Nil(t, ing) + }) + t.Run("will patch extensions ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + + // when + ing, err := iw.Patch(context.Background(), "some-namespace", "extensions-ingress", types.MergePatchType, []byte("{}"), metav1.PatchOptions{}) + + // then + assert.NoError(t, err) + assert.NotNil(t, ing) + li, err := ing.GetExtensionsIngress() + assert.NoError(t, err) + assert.Equal(t, "some-service", li.Spec.Backend.ServiceName) + }) + t.Run("will return error if fails to patch extensions ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + + // when + ing, err := iw.Patch(context.Background(), "not_found", "not_found", types.MergePatchType, []byte("{}"), metav1.PatchOptions{}) + + // then + assert.Error(t, err) + assert.Nil(t, ing) + }) +} + +func Test_IngressWrapUpdate(t *testing.T) { + t.Run("will update networking ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + i := ingress.NewIngress(getNetworkingIngress()) + ctx := context.Background() + + // when + result, err := iw.Update(ctx, "some-namespace", i) + + // then + assert.NoError(t, err) + assert.NotNil(t, result) + }) + t.Run("will return error if fails to update networking ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + wrongIngressVersion := ingress.NewLegacyIngress(getExtensionsIngress()) + ctx := context.Background() + + // when + result, err := iw.Update(ctx, "some-namespace", wrongIngressVersion) + + // then + assert.Error(t, err) + assert.Nil(t, result) + }) + t.Run("will update extensions ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + i := ingress.NewLegacyIngress(getExtensionsIngress()) + ctx := context.Background() + + // when + result, err := iw.Update(ctx, "some-namespace", i) + + // then + assert.NoError(t, err) + assert.NotNil(t, result) + }) + t.Run("will return error if fails to update extensions ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + wrongIngressVersion := ingress.NewIngress(getNetworkingIngress()) + ctx := context.Background() + + // when + result, err := iw.Update(ctx, "some-namespace", wrongIngressVersion) + + // then + assert.Error(t, err) + assert.Nil(t, result) + }) + t.Run("will return error if wrapper has invalid IngressMode", func(t *testing.T) { + // given + t.Parallel() + invalidIngressWrap := ingress.IngressWrap{} + ctx := context.Background() + + // when + i, err := invalidIngressWrap.Update(ctx, "some-namespace", nil) + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) +} + +func Test_IngressWrapGet(t *testing.T) { + t.Run("will get network ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + ctx := context.Background() + + // when + i, err := iw.Get(ctx, "some-namespace", "networking-ingress", metav1.GetOptions{}) + + // then + assert.NoError(t, err) + assert.NotNil(t, i) + assert.Equal(t, "networking-ingress", i.GetName()) + assert.Equal(t, "some-namespace", i.GetNamespace()) + }) + t.Run("will return error if fails to get networking ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + ctx := context.Background() + + // when + i, err := iw.Get(ctx, "not_found", "not_found", metav1.GetOptions{}) + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) + t.Run("will get extensions ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + ctx := context.Background() + + // when + i, err := iw.Get(ctx, "some-namespace", "extensions-ingress", metav1.GetOptions{}) + + // then + assert.NoError(t, err) + assert.NotNil(t, i) + assert.Equal(t, "extensions-ingress", i.GetName()) + assert.Equal(t, "some-namespace", i.GetNamespace()) + }) + t.Run("will return error if fails to get extensions ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + ctx := context.Background() + + // when + i, err := iw.Get(ctx, "not_found", "not_found", metav1.GetOptions{}) + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) + t.Run("will return error if wrapper has invalid IngressMode", func(t *testing.T) { + // given + t.Parallel() + invalidIngressWrap := ingress.IngressWrap{} + ctx := context.Background() + + // when + i, err := invalidIngressWrap.Get(ctx, "some-namespace", "extensions-ingress", metav1.GetOptions{}) + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) +} + +func Test_IngressWrapGetCached(t *testing.T) { + t.Run("will get cached network ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + + // when + i, err := iw.GetCached("some-namespace", "networking-ingress") + + // then + assert.NoError(t, err) + assert.NotNil(t, i) + assert.Equal(t, "networking-ingress", i.GetName()) + assert.Equal(t, "some-namespace", i.GetNamespace()) + }) + t.Run("will return error if fails to get cached networking ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + + // when + i, err := iw.GetCached("not_found", "not_found") + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) + t.Run("will get cached extensions ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + + // when + i, err := iw.GetCached("some-namespace", "extensions-ingress") + + // then + assert.NoError(t, err) + assert.NotNil(t, i) + assert.Equal(t, "extensions-ingress", i.GetName()) + assert.Equal(t, "some-namespace", i.GetNamespace()) + }) + t.Run("will return error if fails to get extensions ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + + // when + i, err := iw.GetCached("not_found", "not_found") + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) + t.Run("will return error if wrapper has invalid IngressMode", func(t *testing.T) { + // given + t.Parallel() + invalidIngressWrap := ingress.IngressWrap{} + + // when + i, err := invalidIngressWrap.GetCached("some-namespace", "extensions-ingress") + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) +} + +func Test_IngressWrapCreate(t *testing.T) { + t.Run("will create network ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + ctx := context.Background() + ni := getNetworkingIngress() + ni.SetNamespace("different-namespace") + i := ingress.NewIngress(ni) + + // when + i, err := iw.Create(ctx, "different-namespace", i, metav1.CreateOptions{}) + + // then + assert.NoError(t, err) + assert.NotNil(t, i) + assert.Equal(t, "networking-ingress", i.GetName()) + assert.Equal(t, "different-namespace", i.GetNamespace()) + }) + t.Run("will return error if fails to create networking ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + ctx := context.Background() + i := ingress.NewIngress(getNetworkingIngress()) + + // when + i, err := iw.Create(ctx, "some-namespace", i, metav1.CreateOptions{}) + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) + t.Run("will create extensions ingress successfully", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + ctx := context.Background() + li := getExtensionsIngress() + li.SetNamespace("different-namespace") + i := ingress.NewLegacyIngress(li) + + // when + i, err := iw.Create(ctx, "different-namespace", i, metav1.CreateOptions{}) + + // then + assert.NoError(t, err) + assert.NotNil(t, i) + assert.Equal(t, "extensions-ingress", i.GetName()) + assert.Equal(t, "different-namespace", i.GetNamespace()) + }) + t.Run("will return error if fails to create extensions ingress", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + ctx := context.Background() + i := ingress.NewLegacyIngress(getExtensionsIngress()) + + // when + i, err := iw.Create(ctx, "some-namespace", i, metav1.CreateOptions{}) + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) + t.Run("will return error if wrapper has invalid IngressMode", func(t *testing.T) { + // given + t.Parallel() + invalidIngressWrap := ingress.IngressWrap{} + i := ingress.NewLegacyIngress(getExtensionsIngress()) + ctx := context.Background() + + // when + i, err := invalidIngressWrap.Create(ctx, "some-namespace", i, metav1.CreateOptions{}) + + // then + assert.Error(t, err) + assert.Nil(t, i) + }) +} + +func Test_IngressWrapHasSynced(t *testing.T) { + t.Run("will check networking ingress HasSynced", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeNetworking) + + // when + synced := iw.HasSynced() + + // then + assert.False(t, synced) + }) + t.Run("will check extensions ingress HasSynced", func(t *testing.T) { + // given + t.Parallel() + iw := newMockedIngressWrapper(t, ingress.IngressModeExtensions) + + // when + synced := iw.HasSynced() + + // then + assert.False(t, synced) + }) + t.Run("will return false if wrapper has invalid IngressMode", func(t *testing.T) { + // given + t.Parallel() + iw := ingress.IngressWrap{} + + // when + synced := iw.HasSynced() + + // then + assert.False(t, synced) + }) +} + +func newMockedIngressWrapper(t *testing.T, mode ingress.IngressMode) *ingress.IngressWrap { + t.Helper() + kubeclient := k8sfake.NewSimpleClientset(getNetworkingIngress(), getExtensionsIngress()) + informer := kubeinformers.NewSharedInformerFactory(kubeclient, 0) + informer.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(getExtensionsIngress()) + informer.Networking().V1().Ingresses().Informer().GetIndexer().Add(getNetworkingIngress()) + + i, err := ingress.NewIngressWrapper(mode, kubeclient, informer) + if err != nil { + t.Fatal(err) + } + return i +} + +func getNetworkingIngress() *v1.Ingress { + ingressClassName := "ingress-name" + return &v1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "networking-ingress", + Namespace: "some-namespace", + Labels: map[string]string{ + "label-key1": "label-value1", + "label-key2": "label-value2", + }, + }, + Spec: v1.IngressSpec{ + IngressClassName: &ingressClassName, + DefaultBackend: &v1.IngressBackend{ + Service: &v1.IngressServiceBackend{ + Name: "backend", + Port: v1.ServiceBackendPort{ + Name: "http", + Number: 8080, + }, + }, + }, + }, + Status: v1.IngressStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + IP: "127.0.0.1", + Hostname: "localhost", + Ports: []corev1.PortStatus{ + { + Port: 8080, + Protocol: "http", + }, + }, + }, + }, + }, + }, + } +} + +func getExtensionsIngress() *v1beta1.Ingress { + ingressClassName := "ingress-name" + return &v1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "extensions-ingress", + Namespace: "some-namespace", + Labels: map[string]string{ + "label-key1": "label-value1", + "label-key2": "label-value2", + }, + }, + Spec: v1beta1.IngressSpec{ + IngressClassName: &ingressClassName, + Backend: &v1beta1.IngressBackend{ + ServiceName: "some-service", + ServicePort: intstr.IntOrString{ + Type: intstr.String, + StrVal: "8080", + }, + }, + }, + Status: v1beta1.IngressStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + IP: "127.0.0.1", + Hostname: "localhost", + Ports: []corev1.PortStatus{ + { + Port: 8080, + Protocol: "http", + }, + }, + }, + }, + }, + }, + } +} From d6131a63df547feaa5ea188d5f1983f12031e93b Mon Sep 17 00:00:00 2001 From: cskh Date: Tue, 4 Jan 2022 12:03:14 -0500 Subject: [PATCH 25/90] fix: e2e istio crd; deprecated apiextensions/v1beta1 (#1740) Signed-off-by: Hui Kang --- .../rollout-alb-experiment-no-setweight.yaml | 102 + test/e2e/alb/rollout-alb-experiment.yaml | 9 +- test/e2e/crds/istio.yaml | 8327 +++++++++++------ test/e2e/crds/split.yaml | 258 +- .../e2e/functional/alb-bluegreen-rollout.yaml | 9 +- test/e2e/functional/alb-canary-rollout.yaml | 9 +- .../canary-dynamic-stable-scale.yaml | 9 +- .../e2e/functional/canary-scaledowndelay.yaml | 9 +- .../functional/canary-scaledownonabort.yaml | 9 +- .../functional/canary-unscaledownonabort.yaml | 9 +- test/e2e/functional/nginx-template.yaml | 9 +- test/e2e/smi/rollout-smi-experiment.yaml | 9 +- .../rollout-smi-ingress-canary.yaml | 92 + test/fixtures/common.go | 22 +- test/kustomize/rollout/expected.yaml | 8 +- test/kustomize/rollout/rollout.yaml | 8 +- 16 files changed, 5936 insertions(+), 2962 deletions(-) create mode 100644 test/e2e/alb/rollout-alb-experiment-no-setweight.yaml create mode 100644 test/e2e/smi_ingress/rollout-smi-ingress-canary.yaml diff --git a/test/e2e/alb/rollout-alb-experiment-no-setweight.yaml b/test/e2e/alb/rollout-alb-experiment-no-setweight.yaml new file mode 100644 index 0000000000..544da2799d --- /dev/null +++ b/test/e2e/alb/rollout-alb-experiment-no-setweight.yaml @@ -0,0 +1,102 @@ +apiVersion: v1 +kind: Service +metadata: + name: alb-rollout-root +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: alb-rollout-canary +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: alb-rollout-stable +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: alb-rollout-ingress + annotations: + kubernetes.io/ingress.class: alb +spec: + rules: + - http: + paths: + - path: /* + pathType: ImplementationSpecific + backend: + service: + name: alb-rollout-root + port: + name: use-annotation +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: alb-rollout +spec: + selector: + matchLabels: + app: alb-rollout + template: + metadata: + labels: + app: alb-rollout + spec: + containers: + - name: alb-rollout + image: nginx:1.19-alpine + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + strategy: + canary: + canaryService: alb-rollout-canary + stableService: alb-rollout-stable + trafficRouting: + alb: + ingress: alb-rollout-ingress + rootService: alb-rollout-root + servicePort: 80 + steps: + - experiment: + templates: + - name: experiment-alb-canary + specRef: canary + weight: 20 + - name: experiment-alb-stable + specRef: stable + weight: 20 diff --git a/test/e2e/alb/rollout-alb-experiment.yaml b/test/e2e/alb/rollout-alb-experiment.yaml index e7b975701c..c718e11069 100644 --- a/test/e2e/alb/rollout-alb-experiment.yaml +++ b/test/e2e/alb/rollout-alb-experiment.yaml @@ -40,7 +40,7 @@ spec: selector: app: alb-rollout --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: alb-rollout-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: ImplementationSpecific backend: - serviceName: alb-rollout-root - servicePort: use-annotation + service: + name: alb-rollout-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/crds/istio.yaml b/test/e2e/crds/istio.yaml index 7491f5b3d5..c2999ea163 100644 --- a/test/e2e/crds/istio.yaml +++ b/test/e2e/crds/istio.yaml @@ -1,5 +1,102 @@ # DO NOT EDIT - Generated by Cue OpenAPI generator based on Istio APIs. -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: wasmplugins.extensions.istio.io +spec: + group: extensions.istio.io + names: + categories: + - istio-io + - extensions-istio-io + kind: WasmPlugin + listKind: WasmPluginList + plural: wasmplugins + singular: wasmplugin + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Extend the functionality provided by the Istio proxy through + WebAssembly filters. See more details at: https://istio.io/docs/reference/config/proxy_extensions/wasm-plugin.html' + properties: + imagePullPolicy: + description: The pull behaviour to be applied when fetching an OCI + image. + enum: + - UNSPECIFIED_POLICY + - IfNotPresent + - Always + type: string + imagePullSecret: + description: Credentials to use for OCI image pulling. + type: string + phase: + description: Determines where in the filter chain this `WasmPlugin` + is to be injected. + enum: + - UNSPECIFIED_PHASE + - AUTHN + - AUTHZ + - STATS + type: string + pluginConfig: + description: The configuration that will be passed on to the plugin. + type: object + x-kubernetes-preserve-unknown-fields: true + pluginName: + type: string + priority: + description: Determines ordering of `WasmPlugins` in the same `phase`. + nullable: true + type: integer + selector: + properties: + matchLabels: + additionalProperties: + type: string + type: object + type: object + sha256: + description: SHA256 checksum that will be used to verify Wasm module + or OCI container. + type: string + url: + description: URL of a Wasm module or OCI container. + type: string + verificationKey: + type: string + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -11,19 +108,6 @@ metadata: release: istio name: destinationrules.networking.istio.io spec: - additionalPrinterColumns: - - JSONPath: .spec.host - description: The name of a service from the service registry - name: Host - type: string - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date group: networking.istio.io names: categories: @@ -35,376 +119,122 @@ spec: shortNames: - dr singular: destinationrule - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting load balancing, outlier detection, - etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html' - properties: - exportTo: - description: A list of namespaces to which this destination rule is - exported. - items: - format: string + versions: + - additionalPrinterColumns: + - description: The name of a service from the service registry + jsonPath: .spec.host + name: Host + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting load balancing, outlier detection, + etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html' + properties: + exportTo: + description: A list of namespaces to which this destination rule is + exported. + items: + type: string + type: array + host: + description: The name of a service from the service registry. type: string - type: array - host: - description: The name of a service from the service registry. - format: string - type: string - subsets: - items: - properties: - labels: - additionalProperties: - format: string + subsets: + items: + properties: + labels: + additionalProperties: + type: string + type: object + name: + description: Name of the subset. type: string - type: object - name: - description: Name of the subset. - format: string - type: string - trafficPolicy: - description: Traffic policies that apply to this subset. - properties: - connectionPool: - properties: - http: - description: HTTP connection pool settings. - properties: - h2UpgradePolicy: - description: Specify if http1.1 connection should - be upgraded to http2 for the associated destination. - enum: - - DEFAULT - - DO_NOT_UPGRADE - - UPGRADE - type: string - http1MaxPendingRequests: - description: Maximum number of pending HTTP requests - to a destination. - format: int32 - type: integer - http2MaxRequests: - description: Maximum number of requests to a backend. - format: int32 - type: integer - idleTimeout: - description: The idle timeout for upstream connection - pool connections. - type: string - maxRequestsPerConnection: - description: Maximum number of requests per connection - to a backend. - format: int32 - type: integer - maxRetries: - format: int32 - type: integer - useClientProtocol: - description: If set to true, client protocol will - be preserved while initiating connection to backend. - type: boolean - type: object - tcp: - description: Settings common to both HTTP and TCP upstream - connections. - properties: - connectTimeout: - description: TCP connection timeout. - type: string - maxConnections: - description: Maximum number of HTTP1 /TCP connections - to a destination host. - format: int32 - type: integer - tcpKeepalive: - description: If set then set SO_KEEPALIVE on the socket - to enable TCP Keepalives. - properties: - interval: - description: The time duration between keep-alive - probes. - type: string - probes: - type: integer - time: - type: string - type: object - type: object - type: object - loadBalancer: - description: Settings controlling the load balancer algorithms. - oneOf: - - not: - anyOf: - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - properties: - consistentHash: - properties: - httpCookie: - description: Hash based on HTTP cookie. - properties: - name: - description: Name of the cookie. - format: string - type: string - path: - description: Path to set for the cookie. - format: string - type: string - ttl: - description: Lifetime of the cookie. - type: string - type: object - httpHeaderName: - description: Hash based on a specific HTTP header. - format: string - type: string - httpQueryParameterName: - description: Hash based on a specific HTTP query parameter. - format: string - type: string - minimumRingSize: - type: integer - useSourceIp: - description: Hash based on the source IP address. - type: boolean - type: object - localityLbSetting: - properties: - distribute: - description: 'Optional: only one of distribute or - failover can be set.' - items: - properties: - from: - description: Originating locality, '/' separated, - e.g. - format: string - type: string - to: - additionalProperties: - type: integer - description: Map of upstream localities to traffic - distribution weights. - type: object - type: object - type: array - enabled: - description: enable locality load balancing, this - is DestinationRule-level and will override mesh - wide settings in entirety. - nullable: true - type: boolean - failover: - description: 'Optional: only failover or distribute - can be set.' - items: - properties: - from: - description: Originating region. - format: string - type: string - to: - format: string - type: string - type: object - type: array - type: object - simple: - enum: - - ROUND_ROBIN - - LEAST_CONN - - RANDOM - - PASSTHROUGH - type: string - type: object - outlierDetection: - properties: - baseEjectionTime: - description: Minimum ejection duration. - type: string - consecutive5xxErrors: - description: Number of 5xx errors before a host is ejected - from the connection pool. - nullable: true - type: integer - consecutiveErrors: - format: int32 - type: integer - consecutiveGatewayErrors: - description: Number of gateway errors before a host is - ejected from the connection pool. - nullable: true - type: integer - interval: - description: Time interval between ejection sweep analysis. - type: string - maxEjectionPercent: - format: int32 - type: integer - minHealthPercent: - format: int32 - type: integer - type: object - portLevelSettings: - description: Traffic policies specific to individual ports. - items: + trafficPolicy: + description: Traffic policies that apply to this subset. + properties: + connectionPool: properties: - connectionPool: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will + be preserved while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. properties: - http: - description: HTTP connection pool settings. + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the + socket to enable TCP Keepalives. properties: - h2UpgradePolicy: - description: Specify if http1.1 connection should - be upgraded to http2 for the associated destination. - enum: - - DEFAULT - - DO_NOT_UPGRADE - - UPGRADE - type: string - http1MaxPendingRequests: - description: Maximum number of pending HTTP - requests to a destination. - format: int32 - type: integer - http2MaxRequests: - description: Maximum number of requests to a - backend. - format: int32 - type: integer - idleTimeout: - description: The idle timeout for upstream connection - pool connections. + interval: + description: The time duration between keep-alive + probes. type: string - maxRequestsPerConnection: - description: Maximum number of requests per - connection to a backend. - format: int32 + probes: type: integer - maxRetries: - format: int32 - type: integer - useClientProtocol: - description: If set to true, client protocol - will be preserved while initiating connection - to backend. - type: boolean - type: object - tcp: - description: Settings common to both HTTP and TCP - upstream connections. - properties: - connectTimeout: - description: TCP connection timeout. + time: type: string - maxConnections: - description: Maximum number of HTTP1 /TCP connections - to a destination host. - format: int32 - type: integer - tcpKeepalive: - description: If set then set SO_KEEPALIVE on - the socket to enable TCP Keepalives. - properties: - interval: - description: The time duration between keep-alive - probes. - type: string - probes: - type: integer - time: - type: string - type: object type: object type: object - loadBalancer: - description: Settings controlling the load balancer - algorithms. - oneOf: - - not: - anyOf: - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: - required: - simple - properties: @@ -430,510 +260,267 @@ spec: - httpQueryParameterName required: - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: properties: - consistentHash: + httpCookie: + description: Hash based on HTTP cookie. properties: - httpCookie: - description: Hash based on HTTP cookie. - properties: - name: - description: Name of the cookie. - format: string - type: string - path: - description: Path to set for the cookie. - format: string - type: string - ttl: - description: Lifetime of the cookie. - type: string - type: object - httpHeaderName: - description: Hash based on a specific HTTP header. - format: string + name: + description: Name of the cookie. type: string - httpQueryParameterName: - description: Hash based on a specific HTTP query - parameter. - format: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. type: string - minimumRingSize: - type: integer - useSourceIp: - description: Hash based on the source IP address. - type: boolean - type: object - localityLbSetting: - properties: - distribute: - description: 'Optional: only one of distribute - or failover can be set.' - items: - properties: - from: - description: Originating locality, '/' - separated, e.g. - format: string - type: string - to: - additionalProperties: - type: integer - description: Map of upstream localities - to traffic distribution weights. - type: object - type: object - type: array - enabled: - description: enable locality load balancing, - this is DestinationRule-level and will override - mesh wide settings in entirety. - nullable: true - type: boolean - failover: - description: 'Optional: only failover or distribute - can be set.' - items: - properties: - from: - description: Originating region. - format: string - type: string - to: - format: string - type: string - type: object - type: array type: object - simple: - enum: - - ROUND_ROBIN - - LEAST_CONN - - RANDOM - - PASSTHROUGH + httpHeaderName: + description: Hash based on a specific HTTP header. type: string - type: object - outlierDetection: - properties: - baseEjectionTime: - description: Minimum ejection duration. - type: string - consecutive5xxErrors: - description: Number of 5xx errors before a host - is ejected from the connection pool. - nullable: true - type: integer - consecutiveErrors: - format: int32 - type: integer - consecutiveGatewayErrors: - description: Number of gateway errors before a host - is ejected from the connection pool. - nullable: true - type: integer - interval: - description: Time interval between ejection sweep - analysis. + httpQueryParameterName: + description: Hash based on a specific HTTP query + parameter. type: string - maxEjectionPercent: - format: int32 - type: integer - minHealthPercent: - format: int32 + minimumRingSize: type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean type: object - port: + localityLbSetting: properties: - number: - type: integer - type: object - tls: - description: TLS related settings for connections to - the upstream service. - properties: - caCertificates: - format: string - type: string - clientCertificate: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - credentialName: - format: string - type: string - mode: - enum: - - DISABLE - - SIMPLE - - MUTUAL - - ISTIO_MUTUAL - type: string - privateKey: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - sni: - description: SNI string to present to the server - during TLS handshake. - format: string - type: string - subjectAltNames: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to + traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list + of labels used to sort endpoints to do priority + based load balancing. items: - format: string type: string type: array type: object - type: object - type: array - tls: - description: TLS related settings for connections to the upstream - service. - properties: - caCertificates: - format: string - type: string - clientCertificate: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - credentialName: - format: string - type: string - mode: - enum: - - DISABLE - - SIMPLE - - MUTUAL - - ISTIO_MUTUAL - type: string - privateKey: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - sni: - description: SNI string to present to the server during - TLS handshake. - format: string - type: string - subjectAltNames: - items: - format: string - type: string - type: array - type: object - type: object - type: object - type: array - trafficPolicy: - properties: - connectionPool: - properties: - http: - description: HTTP connection pool settings. - properties: - h2UpgradePolicy: - description: Specify if http1.1 connection should be upgraded - to http2 for the associated destination. - enum: - - DEFAULT - - DO_NOT_UPGRADE - - UPGRADE - type: string - http1MaxPendingRequests: - description: Maximum number of pending HTTP requests to - a destination. - format: int32 - type: integer - http2MaxRequests: - description: Maximum number of requests to a backend. - format: int32 - type: integer - idleTimeout: - description: The idle timeout for upstream connection pool - connections. - type: string - maxRequestsPerConnection: - description: Maximum number of requests per connection to - a backend. - format: int32 - type: integer - maxRetries: - format: int32 - type: integer - useClientProtocol: - description: If set to true, client protocol will be preserved - while initiating connection to backend. - type: boolean - type: object - tcp: - description: Settings common to both HTTP and TCP upstream connections. - properties: - connectTimeout: - description: TCP connection timeout. - type: string - maxConnections: - description: Maximum number of HTTP1 /TCP connections to - a destination host. - format: int32 - type: integer - tcpKeepalive: - description: If set then set SO_KEEPALIVE on the socket - to enable TCP Keepalives. - properties: - interval: - description: The time duration between keep-alive probes. - type: string - probes: - type: integer - time: + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH type: string type: object - type: object - type: object - loadBalancer: - description: Settings controlling the load balancer algorithms. - oneOf: - - not: - anyOf: - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - properties: - consistentHash: - properties: - httpCookie: - description: Hash based on HTTP cookie. + outlierDetection: properties: - name: - description: Name of the cookie. - format: string - type: string - path: - description: Path to set for the cookie. - format: string + baseEjectionTime: + description: Minimum ejection duration. type: string - ttl: - description: Lifetime of the cookie. + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local + origin failures from external errors. + type: boolean type: object - httpHeaderName: - description: Hash based on a specific HTTP header. - format: string - type: string - httpQueryParameterName: - description: Hash based on a specific HTTP query parameter. - format: string - type: string - minimumRingSize: - type: integer - useSourceIp: - description: Hash based on the source IP address. - type: boolean - type: object - localityLbSetting: - properties: - distribute: - description: 'Optional: only one of distribute or failover - can be set.' - items: - properties: - from: - description: Originating locality, '/' separated, - e.g. - format: string - type: string - to: - additionalProperties: - type: integer - description: Map of upstream localities to traffic - distribution weights. - type: object - type: object - type: array - enabled: - description: enable locality load balancing, this is DestinationRule-level - and will override mesh wide settings in entirety. - nullable: true - type: boolean - failover: - description: 'Optional: only failover or distribute can - be set.' + portLevelSettings: + description: Traffic policies specific to individual ports. items: properties: - from: - description: Originating region. - format: string - type: string - to: - format: string - type: string - type: object - type: array - type: object - simple: - enum: - - ROUND_ROBIN - - LEAST_CONN - - RANDOM - - PASSTHROUGH - type: string - type: object - outlierDetection: - properties: - baseEjectionTime: - description: Minimum ejection duration. - type: string - consecutive5xxErrors: - description: Number of 5xx errors before a host is ejected from - the connection pool. - nullable: true - type: integer - consecutiveErrors: - format: int32 - type: integer - consecutiveGatewayErrors: - description: Number of gateway errors before a host is ejected - from the connection pool. - nullable: true - type: integer - interval: - description: Time interval between ejection sweep analysis. - type: string - maxEjectionPercent: - format: int32 - type: integer - minHealthPercent: - format: int32 - type: integer - type: object - portLevelSettings: - description: Traffic policies specific to individual ports. - items: - properties: - connectionPool: - properties: - http: - description: HTTP connection pool settings. - properties: - h2UpgradePolicy: - description: Specify if http1.1 connection should - be upgraded to http2 for the associated destination. - enum: - - DEFAULT - - DO_NOT_UPGRADE - - UPGRADE - type: string - http1MaxPendingRequests: - description: Maximum number of pending HTTP requests - to a destination. - format: int32 - type: integer - http2MaxRequests: - description: Maximum number of requests to a backend. - format: int32 - type: integer - idleTimeout: - description: The idle timeout for upstream connection - pool connections. - type: string - maxRequestsPerConnection: - description: Maximum number of requests per connection - to a backend. - format: int32 - type: integer - maxRetries: - format: int32 - type: integer - useClientProtocol: - description: If set to true, client protocol will - be preserved while initiating connection to backend. - type: boolean - type: object - tcp: - description: Settings common to both HTTP and TCP upstream - connections. - properties: - connectTimeout: - description: TCP connection timeout. - type: string - maxConnections: - description: Maximum number of HTTP1 /TCP connections - to a destination host. - format: int32 - type: integer - tcpKeepalive: - description: If set then set SO_KEEPALIVE on the socket - to enable TCP Keepalives. + connectionPool: properties: - interval: - description: The time duration between keep-alive - probes. - type: string - probes: - type: integer - time: - type: string + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection + should be upgraded to http2 for the associated + destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP + requests to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to + a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream + connection pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per + connection to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol + will be preserved while initiating connection + to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and + TCP upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP + connections to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE + on the socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between + keep-alive probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object type: object - type: object - type: object - loadBalancer: - description: Settings controlling the load balancer algorithms. - oneOf: - - not: - anyOf: - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: + loadBalancer: + description: Settings controlling the load balancer + algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName - required: - httpHeaderName - required: @@ -942,976 +529,2957 @@ spec: - useSourceIp - required: - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - properties: - consistentHash: - properties: - httpCookie: - description: Hash based on HTTP cookie. + required: + - consistentHash properties: - name: - description: Name of the cookie. - format: string + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP + header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP + query parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' + separated, e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities + to traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, + this is DestinationRule-level and will override + mesh wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered + list of labels used to sort endpoints to + do priority based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH type: string - path: - description: Path to set for the cookie. - format: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. type: string - ttl: - description: Lifetime of the cookie. + consecutive5xxErrors: + description: Number of 5xx errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a + host is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep + analysis. type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish + local origin failures from external errors. + type: boolean type: object - httpHeaderName: - description: Hash based on a specific HTTP header. - format: string - type: string - httpQueryParameterName: - description: Hash based on a specific HTTP query parameter. - format: string - type: string - minimumRingSize: - type: integer - useSourceIp: - description: Hash based on the source IP address. - type: boolean - type: object - localityLbSetting: - properties: - distribute: - description: 'Optional: only one of distribute or - failover can be set.' - items: - properties: - from: - description: Originating locality, '/' separated, - e.g. - format: string - type: string - to: - additionalProperties: - type: integer - description: Map of upstream localities to traffic - distribution weights. - type: object - type: object - type: array - enabled: - description: enable locality load balancing, this - is DestinationRule-level and will override mesh - wide settings in entirety. - nullable: true - type: boolean - failover: - description: 'Optional: only failover or distribute - can be set.' - items: - properties: - from: - description: Originating region. - format: string - type: string - to: - format: string + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections + to the upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server + during TLS handshake. + type: string + subjectAltNames: + items: type: string - type: object - type: array + type: array + type: object type: object - simple: - enum: - - ROUND_ROBIN - - LEAST_CONN - - RANDOM - - PASSTHROUGH - type: string - type: object - outlierDetection: + type: array + tls: + description: TLS related settings for connections to the + upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: object + type: array + trafficPolicy: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. properties: - baseEjectionTime: - description: Minimum ejection duration. + h2UpgradePolicy: + description: Specify if http1.1 connection should be upgraded + to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE type: string - consecutive5xxErrors: - description: Number of 5xx errors before a host is ejected - from the connection pool. - nullable: true - type: integer - consecutiveErrors: + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests to + a destination. format: int32 type: integer - consecutiveGatewayErrors: - description: Number of gateway errors before a host is - ejected from the connection pool. - nullable: true + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 type: integer - interval: - description: Time interval between ejection sweep analysis. + idleTimeout: + description: The idle timeout for upstream connection + pool connections. type: string - maxEjectionPercent: + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. format: int32 type: integer - minHealthPercent: + maxRetries: format: int32 type: integer + useClientProtocol: + description: If set to true, client protocol will be preserved + while initiating connection to backend. + type: boolean type: object - port: - properties: - number: - type: integer - type: object - tls: - description: TLS related settings for connections to the upstream - service. + tcp: + description: Settings common to both HTTP and TCP upstream + connections. properties: - caCertificates: - format: string + connectTimeout: + description: TCP connection timeout. type: string - clientCertificate: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - credentialName: - format: string - type: string - mode: - enum: - - DISABLE - - SIMPLE - - MUTUAL - - ISTIO_MUTUAL - type: string - privateKey: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - sni: - description: SNI string to present to the server during - TLS handshake. - format: string - type: string - subjectAltNames: - items: - format: string - type: string - type: array + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object type: object type: object - type: array - tls: - description: TLS related settings for connections to the upstream - service. - properties: - caCertificates: - format: string - type: string - clientCertificate: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - credentialName: - format: string - type: string - mode: - enum: - - DISABLE - - SIMPLE - - MUTUAL - - ISTIO_MUTUAL - type: string - privateKey: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - sni: - description: SNI string to present to the server during TLS - handshake. - format: string - type: string - subjectAltNames: - items: - format: string - type: string - type: array - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - - name: v1beta1 - served: true - storage: false - ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - app: istio-pilot - chart: istio - heritage: Tiller - release: istio - name: envoyfilters.networking.istio.io -spec: - group: networking.istio.io - names: - categories: - - istio-io - - networking-istio-io - kind: EnvoyFilter - listKind: EnvoyFilterList - plural: envoyfilters - singular: envoyfilter - preserveUnknownFields: true - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Customizing Envoy configuration generated by Istio. See more - details at: https://istio.io/docs/reference/config/networking/envoy-filter.html' - properties: - configPatches: - description: One or more patches with match conditions. - items: - properties: - applyTo: - enum: - - INVALID - - LISTENER - - FILTER_CHAIN - - NETWORK_FILTER - - HTTP_FILTER - - ROUTE_CONFIGURATION - - VIRTUAL_HOST - - HTTP_ROUTE - - CLUSTER - - EXTENSION_CONFIG - type: string - match: - description: Match on listener/route configuration/cluster. + loadBalancer: + description: Settings controlling the load balancer algorithms. oneOf: - not: anyOf: - required: - - listener - - required: - - routeConfiguration - - required: - - cluster - - required: - - listener - - required: - - routeConfiguration + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash - required: - - cluster + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash properties: - cluster: - description: Match on envoy cluster attributes. - properties: - name: - description: The exact name of the cluster to match. - format: string - type: string - portNumber: - description: The service port for which this cluster was - generated. - type: integer - service: - description: The fully qualified service name for this - cluster. - format: string - type: string - subset: - description: The subset associated with the service. - format: string - type: string - type: object - context: - description: The specific config generation context to match - on. - enum: - - ANY - - SIDECAR_INBOUND - - SIDECAR_OUTBOUND - - GATEWAY - type: string - listener: - description: Match on envoy listener attributes. + consistentHash: properties: - filterChain: - description: Match a specific filter chain in a listener. + httpCookie: + description: Hash based on HTTP cookie. properties: - applicationProtocols: - description: Applies only to sidecars. - format: string - type: string - destinationPort: - description: The destination_port value used by a - filter chain's match condition. - type: integer - filter: - description: The name of a specific filter to apply - the patch to. - properties: - name: - description: The filter name to match on. - format: string - type: string - subFilter: - properties: - name: - description: The filter name to match on. - format: string - type: string - type: object - type: object name: - description: The name assigned to the filter chain. - format: string + description: Name of the cookie. type: string - sni: - description: The SNI value used by a filter chain's - match condition. - format: string + path: + description: Path to set for the cookie. type: string - transportProtocol: - description: Applies only to `SIDECAR_INBOUND` context. - format: string + ttl: + description: Lifetime of the cookie. type: string type: object - name: - description: Match a specific listener by its name. - format: string + httpHeaderName: + description: Hash based on a specific HTTP header. type: string - portName: - format: string + httpQueryParameterName: + description: Hash based on a specific HTTP query parameter. type: string - portNumber: + minimumRingSize: type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean type: object - proxy: - description: Match on properties associated with a proxy. + localityLbSetting: properties: - metadata: - additionalProperties: - format: string + distribute: + description: 'Optional: only one of distribute, failover + or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this is DestinationRule-level + and will override mesh wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, failover + or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list of labels + used to sort endpoints to do priority based load balancing. + items: type: string - type: object - proxyVersion: - format: string - type: string - type: object - routeConfiguration: - description: Match on envoy HTTP route configuration attributes. - properties: - gateway: - format: string - type: string - name: - description: Route configuration name to match on. - format: string - type: string - portName: - description: Applicable only for GATEWAY context. - format: string - type: string - portNumber: - type: integer - vhost: - properties: - name: - format: string - type: string - route: - description: Match a specific route within the virtual - host. - properties: - action: - description: Match a route with specific action - type. - enum: - - ANY - - ROUTE - - REDIRECT - - DIRECT_RESPONSE - type: string - name: - format: string - type: string - type: object - type: object + type: array type: object - type: object - patch: - description: The patch to apply along with the operation. - properties: - filterClass: - description: Determines the filter insertion order. - enum: - - UNSPECIFIED - - AUTHN - - AUTHZ - - STATS - type: string - operation: - description: Determines how the patch should be applied. + simple: enum: - - INVALID - - MERGE - - ADD - - REMOVE - - INSERT_BEFORE - - INSERT_AFTER - - INSERT_FIRST - - REPLACE + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH type: string - value: - description: The JSON config of the object being patched. - type: object type: object - type: object - type: array - workloadSelector: - properties: - labels: - additionalProperties: - format: string - type: string - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - app: istio-pilot - chart: istio - heritage: Tiller - release: istio - name: gateways.networking.istio.io -spec: - group: networking.istio.io - names: - categories: - - istio-io - - networking-istio-io - kind: Gateway - listKind: GatewayList - plural: gateways - shortNames: - - gw - singular: gateway - preserveUnknownFields: false - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting edge load balancer. See more details - at: https://istio.io/docs/reference/config/networking/gateway.html' - properties: - selector: - additionalProperties: - format: string - type: string - type: object - servers: - description: A list of server specifications. - items: - properties: - bind: - format: string - type: string - defaultEndpoint: - format: string - type: string - hosts: - description: One or more hosts exposed by this gateway. - items: - format: string - type: string - type: array - name: - description: An optional name of the server, when set must be - unique across all servers. - format: string - type: string - port: + outlierDetection: properties: - name: - description: Label assigned to the port. - format: string + baseEjectionTime: + description: Minimum ejection duration. type: string - number: - description: A valid non-negative integer port number. + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true type: integer - protocol: - description: The protocol exposed on the port. - format: string + interval: + description: Time interval between ejection sweep analysis. type: string - targetPort: + maxEjectionPercent: + format: int32 type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local origin + failures from external errors. + type: boolean type: object - tls: - description: Set of TLS related options that govern the server's - behavior. - properties: - caCertificates: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - cipherSuites: - description: 'Optional: If specified, only support the specified - cipher list.' - items: - format: string - type: string - type: array - credentialName: - format: string + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will + be preserved while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the + socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP query + parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to + traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list + of labels used to sort endpoints to do priority + based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local + origin failures from external errors. + type: boolean + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to the + upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: type: string - httpsRedirect: - type: boolean - maxProtocolVersion: - description: 'Optional: Maximum TLS protocol version.' - enum: - - TLS_AUTO - - TLSV1_0 - - TLSV1_1 - - TLSV1_2 - - TLSV1_3 + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. type: string - minProtocolVersion: - description: 'Optional: Minimum TLS protocol version.' - enum: - - TLS_AUTO - - TLSV1_0 - - TLSV1_1 - - TLSV1_2 - - TLSV1_3 + credentialName: type: string + insecureSkipVerify: + nullable: true + type: boolean mode: enum: - - PASSTHROUGH + - DISABLE - SIMPLE - MUTUAL - - AUTO_PASSTHROUGH - ISTIO_MUTUAL type: string privateKey: - description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. - format: string + description: REQUIRED if mode is `MUTUAL`. type: string - serverCertificate: - description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. - format: string + sni: + description: SNI string to present to the server during TLS + handshake. type: string subjectAltNames: items: - format: string - type: string - type: array - verifyCertificateHash: - items: - format: string - type: string - type: array - verifyCertificateSpki: - items: - format: string type: string type: array type: object type: object - type: array - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true - - name: v1beta1 - served: true - storage: false - ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - app: istio-pilot - chart: istio - heritage: Tiller - release: istio - name: serviceentries.networking.istio.io -spec: - additionalPrinterColumns: - - JSONPath: .spec.hosts - description: The hosts associated with the ServiceEntry - name: Hosts - type: string - - JSONPath: .spec.location - description: Whether the service is external to the mesh or part of the mesh (MESH_EXTERNAL - or MESH_INTERNAL) - name: Location - type: string - - JSONPath: .spec.resolution - description: Service discovery mode for the hosts (NONE, STATIC, or DNS) - name: Resolution - type: string - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date - group: networking.istio.io - names: - categories: - - istio-io - - networking-istio-io - kind: ServiceEntry - listKind: ServiceEntryList - plural: serviceentries - shortNames: - - se - singular: serviceentry - preserveUnknownFields: false - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting service registry. See more details - at: https://istio.io/docs/reference/config/networking/service-entry.html' - properties: - addresses: - description: The virtual IP addresses associated with the service. - items: - format: string + subresources: + status: {} + - additionalPrinterColumns: + - description: The name of a service from the service registry + jsonPath: .spec.host + name: Host + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting load balancing, outlier detection, + etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html' + properties: + exportTo: + description: A list of namespaces to which this destination rule is + exported. + items: + type: string + type: array + host: + description: The name of a service from the service registry. type: string - type: array - endpoints: - description: One or more endpoints associated with the service. - items: - properties: - address: - format: string - type: string - labels: - additionalProperties: - format: string + subsets: + items: + properties: + labels: + additionalProperties: + type: string + type: object + name: + description: Name of the subset. type: string - description: One or more labels associated with the endpoint. - type: object - locality: - description: The locality associated with the endpoint. - format: string - type: string - network: - format: string - type: string - ports: - additionalProperties: - type: integer - description: Set of ports associated with the endpoint. - type: object - serviceAccount: - format: string - type: string - weight: - description: The load balancing weight associated with the endpoint. - type: integer - type: object - type: array - exportTo: - description: A list of namespaces to which this service is exported. - items: - format: string - type: string - type: array - hosts: - description: The hosts associated with the ServiceEntry. - items: - format: string - type: string - type: array - location: - enum: - - MESH_EXTERNAL - - MESH_INTERNAL - type: string - ports: - description: The ports associated with the external service. - items: - properties: - name: - description: Label assigned to the port. - format: string - type: string - number: - description: A valid non-negative integer port number. - type: integer - protocol: - description: The protocol exposed on the port. - format: string - type: string - targetPort: - type: integer - type: object - type: array - resolution: - description: Service discovery mode for the hosts. - enum: - - NONE - - STATIC - - DNS - type: string - subjectAltNames: - items: - format: string - type: string - type: array - workloadSelector: - description: Applicable only for MESH_INTERNAL services. - properties: - labels: - additionalProperties: - format: string - type: string - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - - name: v1beta1 - served: true - storage: false - ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - app: istio-pilot - chart: istio - heritage: Tiller - release: istio - name: sidecars.networking.istio.io -spec: - group: networking.istio.io - names: - categories: - - istio-io - - networking-istio-io - kind: Sidecar - listKind: SidecarList - plural: sidecars - singular: sidecar - preserveUnknownFields: false - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting network reachability of a sidecar. - See more details at: https://istio.io/docs/reference/config/networking/sidecar.html' - properties: - egress: - items: - properties: - bind: - format: string - type: string - captureMode: - enum: - - DEFAULT - - IPTABLES - - NONE - type: string - hosts: + trafficPolicy: + description: Traffic policies that apply to this subset. + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will + be preserved while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the + socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP query + parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to + traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list + of labels used to sort endpoints to do priority + based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local + origin failures from external errors. + type: boolean + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection + should be upgraded to http2 for the associated + destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP + requests to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to + a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream + connection pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per + connection to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol + will be preserved while initiating connection + to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and + TCP upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP + connections to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE + on the socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between + keep-alive probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer + algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP + header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP + query parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' + separated, e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities + to traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, + this is DestinationRule-level and will override + mesh wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered + list of labels used to sort endpoints to + do priority based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a + host is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep + analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish + local origin failures from external errors. + type: boolean + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections + to the upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server + during TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the + upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: object + type: array + trafficPolicy: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should be upgraded + to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests to + a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will be preserved + while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP query parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, failover + or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this is DestinationRule-level + and will override mesh wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, failover + or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list of labels + used to sort endpoints to do priority based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local origin + failures from external errors. + type: boolean + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. items: - format: string + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will + be preserved while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the + socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP query + parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to + traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list + of labels used to sort endpoints to do priority + based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local + origin failures from external errors. + type: boolean + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to the + upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during TLS + handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: envoyfilters.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: EnvoyFilter + listKind: EnvoyFilterList + plural: envoyfilters + singular: envoyfilter + scope: Namespaced + versions: + - name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Customizing Envoy configuration generated by Istio. See + more details at: https://istio.io/docs/reference/config/networking/envoy-filter.html' + properties: + configPatches: + description: One or more patches with match conditions. + items: + properties: + applyTo: + enum: + - INVALID + - LISTENER + - FILTER_CHAIN + - NETWORK_FILTER + - HTTP_FILTER + - ROUTE_CONFIGURATION + - VIRTUAL_HOST + - HTTP_ROUTE + - CLUSTER + - EXTENSION_CONFIG + - BOOTSTRAP + type: string + match: + description: Match on listener/route configuration/cluster. + oneOf: + - not: + anyOf: + - required: + - listener + - required: + - routeConfiguration + - required: + - cluster + - required: + - listener + - required: + - routeConfiguration + - required: + - cluster + properties: + cluster: + description: Match on envoy cluster attributes. + properties: + name: + description: The exact name of the cluster to match. + type: string + portNumber: + description: The service port for which this cluster + was generated. + type: integer + service: + description: The fully qualified service name for this + cluster. + type: string + subset: + description: The subset associated with the service. + type: string + type: object + context: + description: The specific config generation context to match + on. + enum: + - ANY + - SIDECAR_INBOUND + - SIDECAR_OUTBOUND + - GATEWAY + type: string + listener: + description: Match on envoy listener attributes. + properties: + filterChain: + description: Match a specific filter chain in a listener. + properties: + applicationProtocols: + description: Applies only to sidecars. + type: string + destinationPort: + description: The destination_port value used by + a filter chain's match condition. + type: integer + filter: + description: The name of a specific filter to apply + the patch to. + properties: + name: + description: The filter name to match on. + type: string + subFilter: + properties: + name: + description: The filter name to match on. + type: string + type: object + type: object + name: + description: The name assigned to the filter chain. + type: string + sni: + description: The SNI value used by a filter chain's + match condition. + type: string + transportProtocol: + description: Applies only to `SIDECAR_INBOUND` context. + type: string + type: object + name: + description: Match a specific listener by its name. + type: string + portName: + type: string + portNumber: + type: integer + type: object + proxy: + description: Match on properties associated with a proxy. + properties: + metadata: + additionalProperties: + type: string + type: object + proxyVersion: + type: string + type: object + routeConfiguration: + description: Match on envoy HTTP route configuration attributes. + properties: + gateway: + type: string + name: + description: Route configuration name to match on. + type: string + portName: + description: Applicable only for GATEWAY context. + type: string + portNumber: + type: integer + vhost: + properties: + name: + type: string + route: + description: Match a specific route within the virtual + host. + properties: + action: + description: Match a route with specific action + type. + enum: + - ANY + - ROUTE + - REDIRECT + - DIRECT_RESPONSE + type: string + name: + type: string + type: object + type: object + type: object + type: object + patch: + description: The patch to apply along with the operation. + properties: + filterClass: + description: Determines the filter insertion order. + enum: + - UNSPECIFIED + - AUTHN + - AUTHZ + - STATS + type: string + operation: + description: Determines how the patch should be applied. + enum: + - INVALID + - MERGE + - ADD + - REMOVE + - INSERT_BEFORE + - INSERT_AFTER + - INSERT_FIRST + - REPLACE + type: string + value: + description: The JSON config of the object being patched. + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array + priority: + description: Priority defines the order in which patch sets are applied + within a context. + format: int32 + type: integer + workloadSelector: + properties: + labels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: gateways.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Gateway + listKind: GatewayList + plural: gateways + shortNames: + - gw + singular: gateway + scope: Namespaced + versions: + - name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting edge load balancer. See more details + at: https://istio.io/docs/reference/config/networking/gateway.html' + properties: + selector: + additionalProperties: + type: string + type: object + servers: + description: A list of server specifications. + items: + properties: + bind: + type: string + defaultEndpoint: + type: string + hosts: + description: One or more hosts exposed by this gateway. + items: + type: string + type: array + name: + description: An optional name of the server, when set must be + unique across all servers. + type: string + port: + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + tls: + description: Set of TLS related options that govern the server's + behavior. + properties: + caCertificates: + description: REQUIRED if mode is `MUTUAL`. + type: string + cipherSuites: + description: 'Optional: If specified, only support the specified + cipher list.' + items: + type: string + type: array + credentialName: + type: string + httpsRedirect: + type: boolean + maxProtocolVersion: + description: 'Optional: Maximum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + minProtocolVersion: + description: 'Optional: Minimum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + mode: + enum: + - PASSTHROUGH + - SIMPLE + - MUTUAL + - AUTO_PASSTHROUGH + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + type: string + serverCertificate: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + type: string + subjectAltNames: + items: + type: string + type: array + verifyCertificateHash: + items: + type: string + type: array + verifyCertificateSpki: + items: + type: string + type: array + type: object + type: object + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + - name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting edge load balancer. See more details + at: https://istio.io/docs/reference/config/networking/gateway.html' + properties: + selector: + additionalProperties: + type: string + type: object + servers: + description: A list of server specifications. + items: + properties: + bind: + type: string + defaultEndpoint: + type: string + hosts: + description: One or more hosts exposed by this gateway. + items: + type: string + type: array + name: + description: An optional name of the server, when set must be + unique across all servers. + type: string + port: + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + tls: + description: Set of TLS related options that govern the server's + behavior. + properties: + caCertificates: + description: REQUIRED if mode is `MUTUAL`. + type: string + cipherSuites: + description: 'Optional: If specified, only support the specified + cipher list.' + items: + type: string + type: array + credentialName: + type: string + httpsRedirect: + type: boolean + maxProtocolVersion: + description: 'Optional: Maximum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + minProtocolVersion: + description: 'Optional: Minimum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + mode: + enum: + - PASSTHROUGH + - SIMPLE + - MUTUAL + - AUTO_PASSTHROUGH + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + type: string + serverCertificate: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + type: string + subjectAltNames: + items: + type: string + type: array + verifyCertificateHash: + items: + type: string + type: array + verifyCertificateSpki: + items: + type: string + type: array + type: object + type: object + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: serviceentries.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: ServiceEntry + listKind: ServiceEntryList + plural: serviceentries + shortNames: + - se + singular: serviceentry + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The hosts associated with the ServiceEntry + jsonPath: .spec.hosts + name: Hosts + type: string + - description: Whether the service is external to the mesh or part of the mesh + (MESH_EXTERNAL or MESH_INTERNAL) + jsonPath: .spec.location + name: Location + type: string + - description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + jsonPath: .spec.resolution + name: Resolution + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting service registry. See more details + at: https://istio.io/docs/reference/config/networking/service-entry.html' + properties: + addresses: + description: The virtual IP addresses associated with the service. + items: + type: string + type: array + endpoints: + description: One or more endpoints associated with the service. + items: + properties: + address: + type: string + labels: + additionalProperties: + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + serviceAccount: + type: string + weight: + description: The load balancing weight associated with the endpoint. + type: integer + type: object + type: array + exportTo: + description: A list of namespaces to which this service is exported. + items: + type: string + type: array + hosts: + description: The hosts associated with the ServiceEntry. + items: + type: string + type: array + location: + enum: + - MESH_EXTERNAL + - MESH_INTERNAL + type: string + ports: + description: The ports associated with the external service. + items: + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + type: array + resolution: + description: Service discovery mode for the hosts. + enum: + - NONE + - STATIC + - DNS + - DNS_ROUND_ROBIN + type: string + subjectAltNames: + items: + type: string + type: array + workloadSelector: + description: Applicable only for MESH_INTERNAL services. + properties: + labels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - description: The hosts associated with the ServiceEntry + jsonPath: .spec.hosts + name: Hosts + type: string + - description: Whether the service is external to the mesh or part of the mesh + (MESH_EXTERNAL or MESH_INTERNAL) + jsonPath: .spec.location + name: Location + type: string + - description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + jsonPath: .spec.resolution + name: Resolution + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting service registry. See more details + at: https://istio.io/docs/reference/config/networking/service-entry.html' + properties: + addresses: + description: The virtual IP addresses associated with the service. + items: + type: string + type: array + endpoints: + description: One or more endpoints associated with the service. + items: + properties: + address: + type: string + labels: + additionalProperties: + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + serviceAccount: + type: string + weight: + description: The load balancing weight associated with the endpoint. + type: integer + type: object + type: array + exportTo: + description: A list of namespaces to which this service is exported. + items: + type: string + type: array + hosts: + description: The hosts associated with the ServiceEntry. + items: + type: string + type: array + location: + enum: + - MESH_EXTERNAL + - MESH_INTERNAL + type: string + ports: + description: The ports associated with the external service. + items: + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + type: array + resolution: + description: Service discovery mode for the hosts. + enum: + - NONE + - STATIC + - DNS + - DNS_ROUND_ROBIN + type: string + subjectAltNames: + items: + type: string + type: array + workloadSelector: + description: Applicable only for MESH_INTERNAL services. + properties: + labels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: sidecars.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Sidecar + listKind: SidecarList + plural: sidecars + singular: sidecar + scope: Namespaced + versions: + - name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting network reachability of a sidecar. + See more details at: https://istio.io/docs/reference/config/networking/sidecar.html' + properties: + egress: + items: + properties: + bind: type: string - type: array - port: - description: The port associated with the listener. + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + hosts: + items: + type: string + type: array + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + type: object + type: array + ingress: + items: + properties: + bind: + description: The IP to which the listener should be bound. + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + defaultEndpoint: + type: string + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + type: object + type: array + outboundTrafficPolicy: + description: Configuration for the outbound traffic policy. + properties: + egressProxy: properties: - name: - description: Label assigned to the port. - format: string + host: + description: The name of a service from the service registry. type: string - number: - description: A valid non-negative integer port number. - type: integer - protocol: - description: The protocol exposed on the port. - format: string + port: + description: Specifies the port on the host that is being + addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. type: string - targetPort: - type: integer type: object - type: object - type: array - ingress: - items: - properties: - bind: - description: The IP to which the listener should be bound. - format: string - type: string - captureMode: + mode: enum: - - DEFAULT - - IPTABLES - - NONE + - REGISTRY_ONLY + - ALLOW_ANY type: string - defaultEndpoint: - format: string - type: string - port: - description: The port associated with the listener. - properties: - name: - description: Label assigned to the port. - format: string - type: string - number: - description: A valid non-negative integer port number. - type: integer - protocol: - description: The protocol exposed on the port. - format: string - type: string - targetPort: - type: integer + type: object + workloadSelector: + properties: + labels: + additionalProperties: + type: string type: object type: object - type: array - outboundTrafficPolicy: - description: Configuration for the outbound traffic policy. - properties: - egressProxy: + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + - name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting network reachability of a sidecar. + See more details at: https://istio.io/docs/reference/config/networking/sidecar.html' + properties: + egress: + items: properties: - host: - description: The name of a service from the service registry. - format: string + bind: type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + hosts: + items: + type: string + type: array port: - description: Specifies the port on the host that is being addressed. + description: The port associated with the listener. properties: + name: + description: Label assigned to the port. + type: string number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: type: integer type: object - subset: - description: The name of a subset within the service. - format: string + type: object + type: array + ingress: + items: + properties: + bind: + description: The IP to which the listener should be bound. + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + defaultEndpoint: type: string + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object type: object - mode: - enum: - - REGISTRY_ONLY - - ALLOW_ANY - type: string - type: object - workloadSelector: - properties: - labels: - additionalProperties: - format: string + type: array + outboundTrafficPolicy: + description: Configuration for the outbound traffic policy. + properties: + egressProxy: + properties: + host: + description: The name of a service from the service registry. + type: string + port: + description: Specifies the port on the host that is being + addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + mode: + enum: + - REGISTRY_ONLY + - ALLOW_ANY type: string - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - - name: v1beta1 + type: object + workloadSelector: + properties: + labels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: false + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -1923,23 +3491,6 @@ metadata: release: istio name: virtualservices.networking.istio.io spec: - additionalPrinterColumns: - - JSONPath: .spec.gateways - description: The names of gateways and sidecars that should apply these routes - name: Gateways - type: string - - JSONPath: .spec.hosts - description: The destination hosts to which traffic is being sent - name: Hosts - type: string - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date group: networking.istio.io names: categories: @@ -1951,268 +3502,974 @@ spec: shortNames: - vs singular: virtualservice - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting label/content routing, sni routing, - etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html' - properties: - exportTo: - description: A list of namespaces to which this virtual service is exported. - items: - format: string - type: string - type: array - gateways: - description: The names of gateways and sidecars that should apply these - routes. - items: - format: string - type: string - type: array - hosts: - description: The destination hosts to which traffic is being sent. - items: - format: string - type: string - type: array - http: - description: An ordered list of route rules for HTTP traffic. - items: - properties: - corsPolicy: - description: Cross-Origin Resource Sharing policy (CORS). - properties: - allowCredentials: - nullable: true - type: boolean - allowHeaders: - items: - format: string + versions: + - additionalPrinterColumns: + - description: The names of gateways and sidecars that should apply these routes + jsonPath: .spec.gateways + name: Gateways + type: string + - description: The destination hosts to which traffic is being sent + jsonPath: .spec.hosts + name: Hosts + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting label/content routing, sni routing, + etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html' + properties: + exportTo: + description: A list of namespaces to which this virtual service is + exported. + items: + type: string + type: array + gateways: + description: The names of gateways and sidecars that should apply + these routes. + items: + type: string + type: array + hosts: + description: The destination hosts to which traffic is being sent. + items: + type: string + type: array + http: + description: An ordered list of route rules for HTTP traffic. + items: + properties: + corsPolicy: + description: Cross-Origin Resource Sharing policy (CORS). + properties: + allowCredentials: + nullable: true + type: boolean + allowHeaders: + items: + type: string + type: array + allowMethods: + description: List of HTTP methods allowed to access the + resource. + items: + type: string + type: array + allowOrigin: + description: The list of origins that are allowed to perform + CORS requests. + items: + type: string + type: array + allowOrigins: + description: String patterns that match allowed origins. + items: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + type: array + exposeHeaders: + items: + type: string + type: array + maxAge: type: string - type: array - allowMethods: - description: List of HTTP methods allowed to access the resource. - items: - format: string + type: object + delegate: + properties: + name: + description: Name specifies the name of the delegate VirtualService. type: string - type: array - allowOrigin: - description: The list of origins that are allowed to perform - CORS requests. - items: - format: string + namespace: + description: Namespace specifies the namespace where the + delegate VirtualService resides. type: string - type: array - allowOrigins: - description: String patterns that match allowed origins. - items: + type: object + fault: + description: Fault injection policy to apply on HTTP traffic + at the client side. + properties: + abort: + oneOf: + - not: + anyOf: + - required: + - httpStatus + - required: + - grpcStatus + - required: + - http2Error + - required: + - httpStatus + - required: + - grpcStatus + - required: + - http2Error + properties: + grpcStatus: + type: string + http2Error: + type: string + httpStatus: + description: HTTP status code to use to abort the Http + request. + format: int32 + type: integer + percentage: + description: Percentage of requests to be aborted with + the error code provided. + properties: + value: + format: double + type: number + type: object + type: object + delay: oneOf: - not: anyOf: + - required: + - fixedDelay + - required: + - exponentialDelay + - required: + - fixedDelay + - required: + - exponentialDelay + properties: + exponentialDelay: + type: string + fixedDelay: + description: Add a fixed delay before forwarding the + request. + type: string + percent: + description: Percentage of requests on which the delay + will be injected (0-100). + format: int32 + type: integer + percentage: + description: Percentage of requests on which the delay + will be injected. + properties: + value: + format: double + type: number + type: object + type: object + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + type: object + match: + items: + properties: + authority: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + headers: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex - required: - exact - required: - prefix - required: - regex - - required: - - exact - - required: - - prefix - - required: - - regex - properties: - exact: - format: string - type: string - prefix: - format: string - type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string - type: string - type: object - type: array - exposeHeaders: - items: - format: string - type: string - type: array - maxAge: - type: string - type: object - delegate: - properties: - name: - description: Name specifies the name of the delegate VirtualService. - format: string - type: string - namespace: - description: Namespace specifies the namespace where the delegate - VirtualService resides. - format: string - type: string - type: object - fault: - description: Fault injection policy to apply on HTTP traffic at - the client side. - properties: - abort: - oneOf: - - not: - anyOf: + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + type: object + ignoreUriCase: + description: Flag to specify whether the URI matching + should be case-insensitive. + type: boolean + method: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex - required: - - httpStatus + - exact - required: - - grpcStatus + - prefix - required: - - http2Error - - required: - - httpStatus - - required: - - grpcStatus - - required: - - http2Error - properties: - grpcStatus: - format: string - type: string - http2Error: - format: string + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + name: + description: The name assigned to a match. type: string - httpStatus: - description: HTTP status code to use to abort the Http - request. - format: int32 + port: + description: Specifies the ports on the host that is being + addressed. type: integer - percentage: - description: Percentage of requests to be aborted with - the error code provided. + queryParams: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + description: Query parameters for matching. + type: object + scheme: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex properties: - value: - format: double - type: number + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + sourceLabels: + additionalProperties: + type: string + type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string + uri: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + withoutHeaders: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + description: withoutHeader has the same syntax with the + header, but has opposite meaning. + type: object + type: object + type: array + mirror: + properties: + host: + description: The name of a service from the service registry. + type: string + port: + description: Specifies the port on the host that is being + addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + mirror_percent: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + nullable: true + type: integer + mirrorPercent: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + nullable: true + type: integer + mirrorPercentage: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + properties: + value: + format: double + type: number + type: object + name: + description: The name assigned to the route for debugging purposes. + type: string + redirect: + description: A HTTP rule can either redirect or forward (default) + traffic. + oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort + properties: + authority: + type: string + derivePort: + enum: + - FROM_PROTOCOL_DEFAULT + - FROM_REQUEST_PORT + type: string + port: + description: On a redirect, overwrite the port portion of + the URL with this value. + type: integer + redirectCode: + type: integer + scheme: + description: On a redirect, overwrite the scheme portion + of the URL with this value. + type: string + uri: + type: string + type: object + retries: + description: Retry policy for HTTP requests. + properties: + attempts: + description: Number of retries to be allowed for a given + request. + format: int32 + type: integer + perTryTimeout: + description: Timeout per attempt for a given request, including + the initial call and any retries. + type: string + retryOn: + description: Specifies the conditions under which retry + takes place. + type: string + retryRemoteLocalities: + description: Flag to specify whether the retries should + retry to other localities. + nullable: true + type: boolean + type: object + rewrite: + description: Rewrite HTTP URIs and Authority headers. + properties: + authority: + description: rewrite the Authority/Host header with this + value. + type: string + uri: + type: string + type: object + route: + description: A HTTP rule can either redirect or forward (default) + traffic. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object type: object - type: object - delay: - oneOf: - - not: - anyOf: - - required: - - fixedDelay - - required: - - exponentialDelay - - required: - - fixedDelay - - required: - - exponentialDelay - properties: - exponentialDelay: - type: string - fixedDelay: - description: Add a fixed delay before forwarding the request. - type: string - percent: - description: Percentage of requests on which the delay - will be injected (0-100). + weight: format: int32 type: integer - percentage: - description: Percentage of requests on which the delay - will be injected. - properties: - value: - format: double - type: number - type: object type: object - type: object - headers: - properties: - request: + type: array + timeout: + description: Timeout for HTTP requests, default is disabled. + type: string + type: object + type: array + tcp: + description: An ordered list of route rules for opaque TCP traffic. + items: + properties: + match: + items: properties: - add: - additionalProperties: - format: string + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination + with optional subnet. + items: type: string - type: object - remove: + type: array + gateways: + description: Names of gateways where the rule should be + applied. items: - format: string type: string type: array - set: + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sourceLabels: additionalProperties: - format: string type: string type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string + sourceSubnet: + description: IPv4 or IPv6 ip address of source with optional + subnet. + type: string type: object - response: + type: array + route: + description: The destination to which the connection should + be forwarded to. + items: properties: - add: - additionalProperties: - format: string - type: string + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string type: object - remove: + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + tls: + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination + with optional subnet. + items: + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sniHosts: + description: SNI (server name indicator) to match on. items: - format: string type: string type: array - set: + sourceLabels: additionalProperties: - format: string type: string type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string type: object - type: object - match: - items: + type: array + route: + description: The destination to which the connection should + be forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - description: The names of gateways and sidecars that should apply these routes + jsonPath: .spec.gateways + name: Gateways + type: string + - description: The destination hosts to which traffic is being sent + jsonPath: .spec.hosts + name: Hosts + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting label/content routing, sni routing, + etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html' + properties: + exportTo: + description: A list of namespaces to which this virtual service is + exported. + items: + type: string + type: array + gateways: + description: The names of gateways and sidecars that should apply + these routes. + items: + type: string + type: array + hosts: + description: The destination hosts to which traffic is being sent. + items: + type: string + type: array + http: + description: An ordered list of route rules for HTTP traffic. + items: + properties: + corsPolicy: + description: Cross-Origin Resource Sharing policy (CORS). properties: - authority: + allowCredentials: + nullable: true + type: boolean + allowHeaders: + items: + type: string + type: array + allowMethods: + description: List of HTTP methods allowed to access the + resource. + items: + type: string + type: array + allowOrigin: + description: The list of origins that are allowed to perform + CORS requests. + items: + type: string + type: array + allowOrigins: + description: String patterns that match allowed origins. + items: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + type: array + exposeHeaders: + items: + type: string + type: array + maxAge: + type: string + type: object + delegate: + properties: + name: + description: Name specifies the name of the delegate VirtualService. + type: string + namespace: + description: Namespace specifies the namespace where the + delegate VirtualService resides. + type: string + type: object + fault: + description: Fault injection policy to apply on HTTP traffic + at the client side. + properties: + abort: oneOf: - not: anyOf: - required: - - exact + - httpStatus - required: - - prefix + - grpcStatus - required: - - regex + - http2Error - required: - - exact + - httpStatus - required: - - prefix + - grpcStatus - required: - - regex + - http2Error properties: - exact: - format: string + grpcStatus: + type: string + http2Error: type: string - prefix: - format: string + httpStatus: + description: HTTP status code to use to abort the Http + request. + format: int32 + type: integer + percentage: + description: Percentage of requests to be aborted with + the error code provided. + properties: + value: + format: double + type: number + type: object + type: object + delay: + oneOf: + - not: + anyOf: + - required: + - fixedDelay + - required: + - exponentialDelay + - required: + - fixedDelay + - required: + - exponentialDelay + properties: + exponentialDelay: type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string + fixedDelay: + description: Add a fixed delay before forwarding the + request. type: string + percent: + description: Percentage of requests on which the delay + will be injected (0-100). + format: int32 + type: integer + percentage: + description: Percentage of requests on which the delay + will be injected. + properties: + value: + format: double + type: number + type: object type: object - gateways: - description: Names of gateways where the rule should be - applied. - items: - format: string - type: string - type: array - headers: - additionalProperties: + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + type: object + match: + items: + properties: + authority: oneOf: - not: anyOf: @@ -2230,59 +4487,51 @@ spec: - regex properties: exact: - format: string type: string prefix: - format: string type: string regex: description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string type: string type: object - type: object - ignoreUriCase: - description: Flag to specify whether the URI matching should - be case-insensitive. - type: boolean - method: - oneOf: - - not: - anyOf: + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + headers: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex - required: - exact - required: - prefix - required: - regex - - required: - - exact - - required: - - prefix - - required: - - regex - properties: - exact: - format: string - type: string - prefix: - format: string - type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string - type: string - type: object - name: - description: The name assigned to a match. - format: string - type: string - port: - description: Specifies the ports on the host that is being - addressed. - type: integer - queryParams: - additionalProperties: + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + type: object + ignoreUriCase: + description: Flag to specify whether the URI matching + should be case-insensitive. + type: boolean + method: oneOf: - not: anyOf: @@ -2300,86 +4549,82 @@ spec: - regex properties: exact: - format: string type: string prefix: - format: string type: string regex: description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string type: string type: object - description: Query parameters for matching. - type: object - scheme: - oneOf: - - not: - anyOf: + name: + description: The name assigned to a match. + type: string + port: + description: Specifies the ports on the host that is being + addressed. + type: integer + queryParams: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex - required: - exact - required: - prefix - required: - regex - - required: - - exact - - required: - - prefix - - required: - - regex - properties: - exact: - format: string - type: string - prefix: - format: string - type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + description: Query parameters for matching. + type: object + scheme: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + sourceLabels: + additionalProperties: type: string - type: object - sourceLabels: - additionalProperties: - format: string + type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. type: string - type: object - sourceNamespace: - description: Source namespace constraining the applicability - of a rule to workloads in that namespace. - format: string - type: string - uri: - oneOf: - - not: - anyOf: - - required: - - exact - - required: - - prefix - - required: - - regex - - required: - - exact - - required: - - prefix - - required: - - regex - properties: - exact: - format: string - type: string - prefix: - format: string - type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string - type: string - type: object - withoutHeaders: - additionalProperties: + uri: oneOf: - not: anyOf: @@ -2397,340 +4642,357 @@ spec: - regex properties: exact: - format: string type: string prefix: - format: string type: string regex: description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string type: string type: object - description: withoutHeader has the same syntax with the - header, but has opposite meaning. - type: object - type: object - type: array - mirror: - properties: - host: - description: The name of a service from the service registry. - format: string - type: string - port: - description: Specifies the port on the host that is being - addressed. - properties: - number: - type: integer - type: object - subset: - description: The name of a subset within the service. - format: string - type: string - type: object - mirror_percent: - description: Percentage of the traffic to be mirrored by the `mirror` - field. - nullable: true - type: integer - mirrorPercent: - description: Percentage of the traffic to be mirrored by the `mirror` - field. - nullable: true - type: integer - mirrorPercentage: - description: Percentage of the traffic to be mirrored by the `mirror` - field. - properties: - value: - format: double - type: number - type: object - name: - description: The name assigned to the route for debugging purposes. - format: string - type: string - redirect: - description: A HTTP rule can either redirect or forward (default) - traffic. - properties: - authority: - format: string - type: string - redirectCode: - type: integer - uri: - format: string - type: string - type: object - retries: - description: Retry policy for HTTP requests. - properties: - attempts: - description: Number of retries to be allowed for a given request. - format: int32 - type: integer - perTryTimeout: - description: Timeout per retry attempt for a given request. - type: string - retryOn: - description: Specifies the conditions under which retry takes - place. - format: string - type: string - retryRemoteLocalities: - description: Flag to specify whether the retries should retry - to other localities. - nullable: true - type: boolean - type: object - rewrite: - description: Rewrite HTTP URIs and Authority headers. - properties: - authority: - description: rewrite the Authority/Host header with this value. - format: string - type: string - uri: - format: string - type: string - type: object - route: - description: A HTTP rule can either redirect or forward (default) - traffic. - items: - properties: - destination: - properties: - host: - description: The name of a service from the service - registry. - format: string - type: string - port: - description: Specifies the port on the host that is - being addressed. + withoutHeaders: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex properties: - number: - type: integer + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string type: object - subset: - description: The name of a subset within the service. - format: string - type: string - type: object - headers: + description: withoutHeader has the same syntax with the + header, but has opposite meaning. + type: object + type: object + type: array + mirror: + properties: + host: + description: The name of a service from the service registry. + type: string + port: + description: Specifies the port on the host that is being + addressed. properties: - request: - properties: - add: - additionalProperties: - format: string - type: string - type: object - remove: - items: - format: string - type: string - type: array - set: - additionalProperties: - format: string - type: string - type: object - type: object - response: - properties: - add: - additionalProperties: - format: string - type: string - type: object - remove: - items: - format: string - type: string - type: array - set: - additionalProperties: - format: string - type: string - type: object - type: object + number: + type: integer type: object - weight: - format: int32 - type: integer + subset: + description: The name of a subset within the service. + type: string type: object - type: array - timeout: - description: Timeout for HTTP requests, default is disabled. - type: string - type: object - type: array - tcp: - description: An ordered list of route rules for opaque TCP traffic. - items: - properties: - match: - items: + mirror_percent: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + nullable: true + type: integer + mirrorPercent: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + nullable: true + type: integer + mirrorPercentage: + description: Percentage of the traffic to be mirrored by the + `mirror` field. properties: - destinationSubnets: - description: IPv4 or IPv6 ip addresses of destination with - optional subnet. - items: - format: string - type: string - type: array - gateways: - description: Names of gateways where the rule should be - applied. - items: - format: string - type: string - type: array + value: + format: double + type: number + type: object + name: + description: The name assigned to the route for debugging purposes. + type: string + redirect: + description: A HTTP rule can either redirect or forward (default) + traffic. + oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort + properties: + authority: + type: string + derivePort: + enum: + - FROM_PROTOCOL_DEFAULT + - FROM_REQUEST_PORT + type: string port: - description: Specifies the port on the host that is being - addressed. + description: On a redirect, overwrite the port portion of + the URL with this value. type: integer - sourceLabels: - additionalProperties: - format: string - type: string - type: object - sourceNamespace: - description: Source namespace constraining the applicability - of a rule to workloads in that namespace. - format: string + redirectCode: + type: integer + scheme: + description: On a redirect, overwrite the scheme portion + of the URL with this value. type: string - sourceSubnet: - description: IPv4 or IPv6 ip address of source with optional - subnet. - format: string + uri: type: string type: object - type: array - route: - description: The destination to which the connection should be - forwarded to. - items: + retries: + description: Retry policy for HTTP requests. properties: - destination: - properties: - host: - description: The name of a service from the service - registry. - format: string - type: string - port: - description: Specifies the port on the host that is - being addressed. - properties: - number: - type: integer - type: object - subset: - description: The name of a subset within the service. - format: string - type: string - type: object - weight: + attempts: + description: Number of retries to be allowed for a given + request. format: int32 type: integer + perTryTimeout: + description: Timeout per attempt for a given request, including + the initial call and any retries. + type: string + retryOn: + description: Specifies the conditions under which retry + takes place. + type: string + retryRemoteLocalities: + description: Flag to specify whether the retries should + retry to other localities. + nullable: true + type: boolean type: object - type: array - type: object - type: array - tls: - items: - properties: - match: - items: + rewrite: + description: Rewrite HTTP URIs and Authority headers. properties: - destinationSubnets: - description: IPv4 or IPv6 ip addresses of destination with - optional subnet. - items: - format: string - type: string - type: array - gateways: - description: Names of gateways where the rule should be - applied. - items: - format: string - type: string - type: array - port: - description: Specifies the port on the host that is being - addressed. - type: integer - sniHosts: - description: SNI (server name indicator) to match on. - items: - format: string - type: string - type: array - sourceLabels: - additionalProperties: - format: string - type: string - type: object - sourceNamespace: - description: Source namespace constraining the applicability - of a rule to workloads in that namespace. - format: string + authority: + description: rewrite the Authority/Host header with this + value. + type: string + uri: type: string type: object - type: array - route: - description: The destination to which the connection should be - forwarded to. - items: - properties: - destination: - properties: - host: - description: The name of a service from the service - registry. - format: string - type: string - port: - description: Specifies the port on the host that is - being addressed. - properties: - number: - type: integer - type: object - subset: - description: The name of a subset within the service. - format: string + route: + description: A HTTP rule can either redirect or forward (default) + traffic. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + type: object + weight: + format: int32 + type: integer + type: object + type: array + timeout: + description: Timeout for HTTP requests, default is disabled. + type: string + type: object + type: array + tcp: + description: An ordered list of route rules for opaque TCP traffic. + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination + with optional subnet. + items: + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sourceLabels: + additionalProperties: + type: string + type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string + sourceSubnet: + description: IPv4 or IPv6 ip address of source with optional + subnet. + type: string + type: object + type: array + route: + description: The destination to which the connection should + be forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + tls: + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination + with optional subnet. + items: type: string - type: object - weight: - format: int32 - type: integer - type: object - type: array - type: object - type: array - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - - name: v1beta1 + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sniHosts: + description: SNI (server name indicator) to match on. + items: + type: string + type: array + sourceLabels: + additionalProperties: + type: string + type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string + type: object + type: array + route: + description: The destination to which the connection should + be forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: false + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -2742,19 +5004,6 @@ metadata: release: istio name: workloadentries.networking.istio.io spec: - additionalPrinterColumns: - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date - - JSONPath: .spec.address - description: Address associated with the network endpoint. - name: Address - type: string group: networking.istio.io names: categories: @@ -2766,59 +5015,115 @@ spec: shortNames: - we singular: workloadentry - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting VMs onboarded into the mesh. See more - details at: https://istio.io/docs/reference/config/networking/workload-entry.html' - properties: - address: - format: string - type: string - labels: - additionalProperties: - format: string + versions: + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Address associated with the network endpoint. + jsonPath: .spec.address + name: Address + type: string + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting VMs onboarded into the mesh. See + more details at: https://istio.io/docs/reference/config/networking/workload-entry.html' + properties: + address: + type: string + labels: + additionalProperties: + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + serviceAccount: type: string - description: One or more labels associated with the endpoint. - type: object - locality: - description: The locality associated with the endpoint. - format: string - type: string - network: - format: string - type: string - ports: - additionalProperties: + weight: + description: The load balancing weight associated with the endpoint. type: integer - description: Set of ports associated with the endpoint. - type: object - serviceAccount: - format: string - type: string - weight: - description: The load balancing weight associated with the endpoint. - type: integer - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true - - name: v1beta1 + subresources: + status: {} + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Address associated with the network endpoint. + jsonPath: .spec.address + name: Address + type: string + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting VMs onboarded into the mesh. See + more details at: https://istio.io/docs/reference/config/networking/workload-entry.html' + properties: + address: + type: string + labels: + additionalProperties: + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + serviceAccount: + type: string + weight: + description: The load balancing weight associated with the endpoint. + type: integer + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: false + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: labels: @@ -2828,15 +5133,6 @@ metadata: release: istio name: workloadgroups.networking.istio.io spec: - additionalPrinterColumns: - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date group: networking.istio.io names: categories: @@ -2848,167 +5144,162 @@ spec: shortNames: - wg singular: workloadgroup - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Describes a collection of workload instances. See more details - at: https://istio.io/docs/reference/config/networking/workload-group.html' - properties: - metadata: - description: Metadata that will be used for all corresponding `WorkloadEntries`. - properties: - annotations: - additionalProperties: - format: string - type: string - type: object - labels: - additionalProperties: - format: string - type: string - type: object - type: object - probe: - description: '`ReadinessProbe` describes the configuration the user - must provide for healthchecking on their workload.' - oneOf: - - not: - anyOf: - - required: - - httpGet - - required: - - tcpSocket - - required: - - exec - - required: - - httpGet - - required: - - tcpSocket - - required: - - exec - properties: - exec: - description: Health is determined by how the command that is executed - exited. - properties: - command: - description: Command to run. - items: - format: string - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the probe to be considered - failed after having succeeded. - format: int32 - type: integer - httpGet: - properties: - host: - description: Host name to connect to, defaults to the pod IP. - format: string - type: string - httpHeaders: - description: Headers the proxy will pass on to make the request. - items: - properties: - name: - format: string - type: string - value: - format: string - type: string - type: object - type: array - path: - description: Path to access on the HTTP server. - format: string + versions: + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Describes a collection of workload instances. See more details + at: https://istio.io/docs/reference/config/networking/workload-group.html' + properties: + metadata: + description: Metadata that will be used for all corresponding `WorkloadEntries`. + properties: + annotations: + additionalProperties: type: string - port: - description: Port on which the endpoint lives. - type: integer - scheme: - format: string + type: object + labels: + additionalProperties: type: string - type: object - initialDelaySeconds: - description: Number of seconds after the container has started before - readiness probes are initiated. - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the probe. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the probe to be considered - successful after having failed. - format: int32 - type: integer - tcpSocket: - description: Health is determined by if the proxy is able to connect. - properties: - host: - format: string + type: object + type: object + probe: + description: '`ReadinessProbe` describes the configuration the user + must provide for healthchecking on their workload.' + oneOf: + - not: + anyOf: + - required: + - httpGet + - required: + - tcpSocket + - required: + - exec + - required: + - httpGet + - required: + - tcpSocket + - required: + - exec + properties: + exec: + description: Health is determined by how the command that is executed + exited. + properties: + command: + description: Command to run. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe to be + considered failed after having succeeded. + format: int32 + type: integer + httpGet: + properties: + host: + description: Host name to connect to, defaults to the pod + IP. + type: string + httpHeaders: + description: Headers the proxy will pass on to make the request. + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + description: Port on which the endpoint lives. + type: integer + scheme: + type: string + type: object + initialDelaySeconds: + description: Number of seconds after the container has started + before readiness probes are initiated. + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe to be + considered successful after having failed. + format: int32 + type: integer + tcpSocket: + description: Health is determined by if the proxy is able to connect. + properties: + host: + type: string + port: + type: integer + type: object + timeoutSeconds: + description: Number of seconds after which the probe times out. + format: int32 + type: integer + type: object + template: + description: Template to be used for the generation of `WorkloadEntry` + resources that belong to this `WorkloadGroup`. + properties: + address: + type: string + labels: + additionalProperties: type: string - port: + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: type: integer - type: object - timeoutSeconds: - description: Number of seconds after which the probe times out. - format: int32 - type: integer - type: object - template: - description: Template to be used for the generation of `WorkloadEntry` - resources that belong to this `WorkloadGroup`. - properties: - address: - format: string - type: string - labels: - additionalProperties: - format: string + description: Set of ports associated with the endpoint. + type: object + serviceAccount: type: string - description: One or more labels associated with the endpoint. - type: object - locality: - description: The locality associated with the endpoint. - format: string - type: string - network: - format: string - type: string - ports: - additionalProperties: + weight: + description: The load balancing weight associated with the endpoint. type: integer - description: Set of ports associated with the endpoint. - type: object - serviceAccount: - format: string - type: string - weight: - description: The load balancing weight associated with the endpoint. - type: integer - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -3026,221 +5317,197 @@ spec: categories: - istio-io - security-istio-io - kind: AuthorizationPolicy - listKind: AuthorizationPolicyList - plural: authorizationpolicies - singular: authorizationpolicy - preserveUnknownFields: false - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration for access control on workloads. See more details - at: https://istio.io/docs/reference/config/security/authorization-policy.html' - oneOf: - - not: - anyOf: - - required: - - provider - - required: - - provider - properties: - action: - description: Optional. - enum: - - ALLOW - - DENY - - AUDIT - - CUSTOM - type: string - provider: - description: Specifies detailed configuration of the CUSTOM action. - properties: - name: - description: Specifies the name of the extension provider. - format: string - type: string - type: object - rules: - description: Optional. - items: - properties: - from: - description: Optional. - items: - properties: - source: - description: Source specifies the source of a request. - properties: - ipBlocks: - description: Optional. - items: - format: string - type: string - type: array - namespaces: - description: Optional. - items: - format: string - type: string - type: array - notIpBlocks: - description: Optional. - items: - format: string - type: string - type: array - notNamespaces: - description: Optional. - items: - format: string - type: string - type: array - notPrincipals: - description: Optional. - items: - format: string - type: string - type: array - notRemoteIpBlocks: - description: Optional. - items: - format: string - type: string - type: array - notRequestPrincipals: - description: Optional. - items: - format: string - type: string - type: array - principals: - description: Optional. - items: - format: string - type: string - type: array - remoteIpBlocks: - description: Optional. - items: - format: string - type: string - type: array - requestPrincipals: - description: Optional. - items: - format: string - type: string - type: array - type: object - type: object - type: array - to: - description: Optional. - items: - properties: - operation: - description: Operation specifies the operation of a request. - properties: - hosts: - description: Optional. - items: - format: string - type: string - type: array - methods: - description: Optional. - items: - format: string - type: string - type: array - notHosts: - description: Optional. - items: - format: string - type: string - type: array - notMethods: - description: Optional. - items: - format: string - type: string - type: array - notPaths: - description: Optional. - items: - format: string - type: string - type: array - notPorts: - description: Optional. - items: - format: string - type: string - type: array - paths: - description: Optional. - items: - format: string - type: string - type: array - ports: - description: Optional. - items: - format: string - type: string - type: array - type: object - type: object - type: array - when: - description: Optional. - items: - properties: - key: - description: The name of an Istio attribute. - format: string - type: string - notValues: - description: Optional. - items: - format: string - type: string - type: array - values: - description: Optional. - items: - format: string - type: string - type: array - type: object - type: array - type: object - type: array - selector: - description: Optional. - properties: - matchLabels: - additionalProperties: - format: string - type: string - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object + kind: AuthorizationPolicy + listKind: AuthorizationPolicyList + plural: authorizationpolicies + singular: authorizationpolicy + scope: Namespaced versions: - name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for access control on workloads. See more + details at: https://istio.io/docs/reference/config/security/authorization-policy.html' + oneOf: + - not: + anyOf: + - required: + - provider + - required: + - provider + properties: + action: + description: Optional. + enum: + - ALLOW + - DENY + - AUDIT + - CUSTOM + type: string + provider: + description: Specifies detailed configuration of the CUSTOM action. + properties: + name: + description: Specifies the name of the extension provider. + type: string + type: object + rules: + description: Optional. + items: + properties: + from: + description: Optional. + items: + properties: + source: + description: Source specifies the source of a request. + properties: + ipBlocks: + description: Optional. + items: + type: string + type: array + namespaces: + description: Optional. + items: + type: string + type: array + notIpBlocks: + description: Optional. + items: + type: string + type: array + notNamespaces: + description: Optional. + items: + type: string + type: array + notPrincipals: + description: Optional. + items: + type: string + type: array + notRemoteIpBlocks: + description: Optional. + items: + type: string + type: array + notRequestPrincipals: + description: Optional. + items: + type: string + type: array + principals: + description: Optional. + items: + type: string + type: array + remoteIpBlocks: + description: Optional. + items: + type: string + type: array + requestPrincipals: + description: Optional. + items: + type: string + type: array + type: object + type: object + type: array + to: + description: Optional. + items: + properties: + operation: + description: Operation specifies the operation of a request. + properties: + hosts: + description: Optional. + items: + type: string + type: array + methods: + description: Optional. + items: + type: string + type: array + notHosts: + description: Optional. + items: + type: string + type: array + notMethods: + description: Optional. + items: + type: string + type: array + notPaths: + description: Optional. + items: + type: string + type: array + notPorts: + description: Optional. + items: + type: string + type: array + paths: + description: Optional. + items: + type: string + type: array + ports: + description: Optional. + items: + type: string + type: array + type: object + type: object + type: array + when: + description: Optional. + items: + properties: + key: + description: The name of an Istio attribute. + type: string + notValues: + description: Optional. + items: + type: string + type: array + values: + description: Optional. + items: + type: string + type: array + type: object + type: array + type: object + type: array + selector: + description: Optional. + properties: + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -3253,19 +5520,6 @@ metadata: release: istio name: peerauthentications.security.istio.io spec: - additionalPrinterColumns: - - JSONPath: .spec.mtls.mode - description: Defines the mTLS mode used for peer authentication. - name: Mode - type: string - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date group: security.istio.io names: categories: @@ -3277,31 +5531,31 @@ spec: shortNames: - pa singular: peerauthentication - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: PeerAuthentication defines how traffic will be tunneled (or - not) to the sidecar. - properties: - mtls: - description: Mutual TLS settings for workload. - properties: - mode: - description: Defines the mTLS mode used for peer authentication. - enum: - - UNSET - - DISABLE - - PERMISSIVE - - STRICT - type: string - type: object - portLevelMtls: - additionalProperties: + versions: + - additionalPrinterColumns: + - description: Defines the mTLS mode used for peer authentication. + jsonPath: .spec.mtls.mode + name: Mode + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: PeerAuthentication defines how traffic will be tunneled (or + not) to the sidecar. + properties: + mtls: + description: Mutual TLS settings for workload. properties: mode: description: Defines the mTLS mode used for peer authentication. @@ -3312,30 +5566,41 @@ spec: - STRICT type: string type: object - description: Port specific mutual TLS settings. - type: object - selector: - description: The selector determines the workloads to apply the ChannelAuthentication - on. - properties: - matchLabels: - additionalProperties: - format: string - type: string + portLevelMtls: + additionalProperties: + properties: + mode: + description: Defines the mTLS mode used for peer authentication. + enum: + - UNSET + - DISABLE + - PERMISSIVE + - STRICT + type: string type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1beta1 + description: Port specific mutual TLS settings. + type: object + selector: + description: The selector determines the workloads to apply the ChannelAuthentication + on. + properties: + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -3359,90 +5624,318 @@ spec: shortNames: - ra singular: requestauthentication - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: RequestAuthentication defines what request authentication methods - are supported by a workload. - properties: - jwtRules: - description: Define the list of JWTs that can be validated at the selected - workloads' proxy. - items: + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: RequestAuthentication defines what request authentication + methods are supported by a workload. + properties: + jwtRules: + description: Define the list of JWTs that can be validated at the + selected workloads' proxy. + items: + properties: + audiences: + items: + type: string + type: array + forwardOriginalToken: + description: If set to true, the original token will be kept + for the upstream request. + type: boolean + fromHeaders: + description: List of header locations from which JWT is expected. + items: + properties: + name: + description: The HTTP header name. + type: string + prefix: + description: The prefix that should be stripped before + decoding the token. + type: string + type: object + type: array + fromParams: + description: List of query parameters from which JWT is expected. + items: + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + type: string + jwks_uri: + type: string + jwksUri: + type: string + outputPayloadToHeader: + type: string + type: object + type: array + selector: + description: Optional. properties: - audiences: - items: - format: string + matchLabels: + additionalProperties: type: string - type: array - forwardOriginalToken: - description: If set to true, the orginal token will be kept for - the ustream request. - type: boolean - fromHeaders: - description: List of header locations from which JWT is expected. - items: - properties: - name: - description: The HTTP header name. - format: string - type: string - prefix: - description: The prefix that should be stripped before decoding - the token. - format: string - type: string - type: object - type: array - fromParams: - description: List of query parameters from which JWT is expected. - items: - format: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: telemetry + release: istio + name: telemetries.telemetry.istio.io +spec: + group: telemetry.istio.io + names: + categories: + - istio-io + - telemetry-istio-io + kind: Telemetry + listKind: TelemetryList + plural: telemetries + shortNames: + - telemetry + singular: telemetry + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Telemetry configuration for workloads. See more details + at: https://istio.io/docs/reference/config/telemetry.html' + properties: + accessLogging: + description: Optional. + items: + properties: + disabled: + description: Controls logging. + nullable: true + type: boolean + providers: + description: Optional. + items: + properties: + name: + description: Required. + type: string + type: object + type: array + type: object + type: array + metrics: + description: Optional. + items: + properties: + overrides: + description: Optional. + items: + properties: + disabled: + description: Optional. + nullable: true + type: boolean + match: + description: Match allows provides the scope of the override. + oneOf: + - not: + anyOf: + - required: + - metric + - required: + - customMetric + - required: + - metric + - required: + - customMetric + properties: + customMetric: + description: Allows free-form specification of a metric. + type: string + metric: + description: One of the well-known Istio Standard + Metrics. + enum: + - ALL_METRICS + - REQUEST_COUNT + - REQUEST_DURATION + - REQUEST_SIZE + - RESPONSE_SIZE + - TCP_OPENED_CONNECTIONS + - TCP_CLOSED_CONNECTIONS + - TCP_SENT_BYTES + - TCP_RECEIVED_BYTES + - GRPC_REQUEST_MESSAGES + - GRPC_RESPONSE_MESSAGES + type: string + mode: + description: 'Controls which mode of metrics generation + is selected: CLIENT and/or SERVER.' + enum: + - CLIENT_AND_SERVER + - CLIENT + - SERVER + type: string + type: object + tagOverrides: + additionalProperties: + properties: + operation: + description: Operation controls whether or not to + update/add a tag, or to remove it. + enum: + - UPSERT + - REMOVE + type: string + value: + description: Value is only considered if the operation + is `UPSERT`. + type: string + type: object + description: Optional. + type: object + type: object + type: array + providers: + description: Optional. + items: + properties: + name: + description: Required. + type: string + type: object + type: array + type: object + type: array + selector: + description: Optional. + properties: + matchLabels: + additionalProperties: type: string - type: array - issuer: - description: Identifies the issuer that issued the JWT. - format: string - type: string - jwks: - description: JSON Web Key Set of public keys to validate signature - of the JWT. - format: string - type: string - jwks_uri: - format: string - type: string - jwksUri: - format: string - type: string - outputPayloadToHeader: - format: string - type: string + type: object type: object - type: array - selector: - description: The selector determines the workloads to apply the RequestAuthentication - on. - properties: - matchLabels: - additionalProperties: - format: string - type: string + tracing: + description: Optional. + items: + properties: + customTags: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - literal + - required: + - environment + - required: + - header + - required: + - literal + - required: + - environment + - required: + - header + properties: + environment: + description: Environment adds the value of an environment + variable to each span. + properties: + defaultValue: + description: Optional. + type: string + name: + description: Name of the environment variable from + which to extract the tag value. + type: string + type: object + header: + description: RequestHeader adds the value of an header + from the request to each span. + properties: + defaultValue: + description: Optional. + type: string + name: + description: Name of the header from which to extract + the tag value. + type: string + type: object + literal: + description: Literal adds the same, hard-coded value to + each span. + properties: + value: + description: The tag value to use. + type: string + type: object + type: object + description: Optional. + type: object + disableSpanReporting: + description: Controls span reporting. + nullable: true + type: boolean + providers: + description: Optional. + items: + properties: + name: + description: Required. + type: string + type: object + type: array + randomSamplingPercentage: + nullable: true + type: number type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1beta1 + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true + subresources: + status: {} ---- \ No newline at end of file +--- diff --git a/test/e2e/crds/split.yaml b/test/e2e/crds/split.yaml index 04aa266b71..716b8552b9 100644 --- a/test/e2e/crds/split.yaml +++ b/test/e2e/crds/split.yaml @@ -1,25 +1,265 @@ --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: trafficsplits.split.smi-spec.io spec: group: split.smi-spec.io - version: v1alpha1 - scope: Namespaced names: kind: TrafficSplit listKind: TrafficSplitList + plural: trafficsplits shortNames: - ts - plural: trafficsplits singular: trafficsplit + scope: Namespaced versions: - name: v1alpha1 + schema: + openAPIV3Schema: + description: TrafficSplit is the Schema for the trafficsplits API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TrafficSplitSpec defines the desired state of TrafficSplit + properties: + backends: + items: + description: TrafficSplitBackend defines a backend + properties: + service: + type: string + weight: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: array + service: + type: string + type: object + status: + description: TrafficSplitStatus defines the observed state of TrafficSplit + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha2 + schema: + openAPIV3Schema: + description: TrafficSplit is the Schema for the trafficsplits API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TrafficSplitSpec defines the desired state of TrafficSplit + properties: + backends: + items: + description: TrafficSplitBackend defines a backend + properties: + service: + type: string + weight: + type: integer + required: + - service + - weight + type: object + type: array + service: + type: string + type: object + status: + description: TrafficSplitStatus defines the observed state of TrafficSplit + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha3 + schema: + openAPIV3Schema: + description: TrafficSplit is the Schema for the trafficsplits API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TrafficSplitSpec defines the desired state of TrafficSplit + properties: + backends: + description: Backends defines a list of Kubernetes services used as + the traffic split destination + items: + description: TrafficSplitBackend defines a backend + properties: + service: + description: Service is the name of a Kubernetes service + type: string + weight: + description: Weight defines the traffic split percentage + type: integer + required: + - service + - weight + type: object + type: array + matches: + description: Matches allows defining a list of HTTP route groups that + this traffic split object should match + items: + description: TypedLocalObjectReference contains enough information + to let you locate the typed referenced object inside the same + namespace. + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + type: array + service: + description: Service represents the apex service + type: string + required: + - backends + - service + type: object + status: + description: TrafficSplitStatus defines the observed state of TrafficSplit + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha4 + schema: + openAPIV3Schema: + description: TrafficSplit is the Schema for the trafficsplits API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TrafficSplitSpec defines the desired state of TrafficSplit + properties: + backends: + description: Backends defines a list of Kubernetes services used as + the traffic split destination + items: + description: TrafficSplitBackend defines a backend + properties: + service: + description: Service is the name of a Kubernetes service + type: string + weight: + description: Weight defines the traffic split percentage + type: integer + required: + - service + - weight + type: object + type: array + matches: + description: Matches allows defining a list of HTTP route groups that + this traffic split object should match + items: + description: TypedLocalObjectReference contains enough information + to let you locate the typed referenced object inside the same + namespace. + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + type: array + service: + description: Service represents the apex service + type: string + required: + - backends + - service + type: object + status: + description: TrafficSplitStatus defines the observed state of TrafficSplit + type: object + type: object served: true storage: true - additionalPrinterColumns: - - name: Service - type: string - description: The apex service of this split. - JSONPath: .spec.service + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/test/e2e/functional/alb-bluegreen-rollout.yaml b/test/e2e/functional/alb-bluegreen-rollout.yaml index e06c2b5bea..3eedb62a8d 100644 --- a/test/e2e/functional/alb-bluegreen-rollout.yaml +++ b/test/e2e/functional/alb-bluegreen-rollout.yaml @@ -26,7 +26,7 @@ spec: selector: app: alb-bluegreen --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: alb-bluegreen-ingress @@ -37,9 +37,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: alb-bluegreen-stable - servicePort: 80 + service: + name: alb-bluegreen-stable + port: + number: 80 --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/alb-canary-rollout.yaml b/test/e2e/functional/alb-canary-rollout.yaml index df90ecc3cd..e05f73d2c2 100644 --- a/test/e2e/functional/alb-canary-rollout.yaml +++ b/test/e2e/functional/alb-canary-rollout.yaml @@ -40,7 +40,7 @@ spec: selector: app: alb-canary --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: alb-canary-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: alb-canary-root - servicePort: use-annotation + service: + name: alb-canary-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/canary-dynamic-stable-scale.yaml b/test/e2e/functional/canary-dynamic-stable-scale.yaml index 612f684dea..aae5e8c324 100644 --- a/test/e2e/functional/canary-dynamic-stable-scale.yaml +++ b/test/e2e/functional/canary-dynamic-stable-scale.yaml @@ -38,7 +38,7 @@ spec: selector: app: dynamic-stable-scale --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: dynamic-stable-scale-ingress @@ -49,9 +49,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: dynamic-stable-scale-root - servicePort: use-annotation + service: + name: dynamic-stable-scale-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/canary-scaledowndelay.yaml b/test/e2e/functional/canary-scaledowndelay.yaml index 21fc6a4d42..7d469fe929 100644 --- a/test/e2e/functional/canary-scaledowndelay.yaml +++ b/test/e2e/functional/canary-scaledowndelay.yaml @@ -40,7 +40,7 @@ spec: selector: app: canary-scaledowndelay --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: canary-scaledowndelay-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: canary-scaledowndelay-root - servicePort: use-annotation + service: + name: canary-scaledowndelay-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/canary-scaledownonabort.yaml b/test/e2e/functional/canary-scaledownonabort.yaml index 8d5d05aff3..308becf609 100644 --- a/test/e2e/functional/canary-scaledownonabort.yaml +++ b/test/e2e/functional/canary-scaledownonabort.yaml @@ -40,7 +40,7 @@ spec: selector: app: canary-scaledowndelay --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: canary-scaledowndelay-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: canary-scaledowndelay-root - servicePort: use-annotation + service: + name: canary-scaledowndelay-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/canary-unscaledownonabort.yaml b/test/e2e/functional/canary-unscaledownonabort.yaml index cf9ce26438..a4b4955988 100644 --- a/test/e2e/functional/canary-unscaledownonabort.yaml +++ b/test/e2e/functional/canary-unscaledownonabort.yaml @@ -40,7 +40,7 @@ spec: selector: app: canary-scaledowndelay --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: canary-scaledowndelay-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: canary-scaledowndelay-root - servicePort: use-annotation + service: + name: canary-scaledowndelay-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/nginx-template.yaml b/test/e2e/functional/nginx-template.yaml index 85058636f7..9fa3335af1 100644 --- a/test/e2e/functional/nginx-template.yaml +++ b/test/e2e/functional/nginx-template.yaml @@ -26,7 +26,7 @@ spec: selector: app: REPLACEME --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: REPLACEME-ingress @@ -37,9 +37,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: REPLACEME-stable - servicePort: 80 + service: + name: REPLACEME-stable + port: + number: 80 --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/smi/rollout-smi-experiment.yaml b/test/e2e/smi/rollout-smi-experiment.yaml index 88e5a529e4..a71a759805 100644 --- a/test/e2e/smi/rollout-smi-experiment.yaml +++ b/test/e2e/smi/rollout-smi-experiment.yaml @@ -28,7 +28,7 @@ spec: # This selector will be updated with the pod-template-hash of the stable ReplicaSet. e.g.: # rollouts-pod-template-hash: 789746c88d --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: rollout-smi-experiment-stable @@ -40,10 +40,13 @@ spec: http: paths: - path: / + pathType: ImplementationSpecific backend: # Reference to a Service name, also specified in the Rollout spec.strategy.canary.stableService field - serviceName: rollout-smi-experiment-stable - servicePort: 80 + service: + name: rollout-smi-experiment-stable + port: + number: 80 --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/smi_ingress/rollout-smi-ingress-canary.yaml b/test/e2e/smi_ingress/rollout-smi-ingress-canary.yaml new file mode 100644 index 0000000000..c9b71c5fcc --- /dev/null +++ b/test/e2e/smi_ingress/rollout-smi-ingress-canary.yaml @@ -0,0 +1,92 @@ +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-ingress-canary-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-ingress-canary + # This selector will be updated with the pod-template-hash of the canary ReplicaSet. e.g.: + # rollouts-pod-template-hash: 7bf84f9696 +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-ingress-canary-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-ingress-canary + # This selector will be updated with the pod-template-hash of the stable ReplicaSet. e.g.: + # rollouts-pod-template-hash: 789746c88d +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: rollout-smi-ingress-canary-stable + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-ingress-canary.local + http: + paths: + - path: / + pathType: Prefix + backend: + # Reference to a Service name, also specified in the Rollout spec.strategy.canary.stableService field + service: + name: rollout-smi-ingress-canary-stable + port: + number: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-ingress-canary +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-ingress-canary-canary + stableService: rollout-smi-ingress-canary-stable + trafficRouting: + nginx: + stableIngress: rollout-smi-ingress-canary-stable + smi: + trafficSplitName: rollout-smi-ingress-canary-trafficsplit + steps: + - setWeight: 5 + - pause: + duration: 15 + - setWeight: 50 + - pause: + duration: 15 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-ingress-canary + template: + metadata: + labels: + app: rollout-smi-ingress-canary + spec: + containers: + - name: rollout-smi-ingress-canary + image: nginx:1.19-alpine + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m diff --git a/test/fixtures/common.go b/test/fixtures/common.go index 4a734c78ff..9d73f21447 100644 --- a/test/fixtures/common.go +++ b/test/fixtures/common.go @@ -21,7 +21,7 @@ import ( appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" - extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + networkingv1 "k8s.io/api/networking/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -527,10 +527,26 @@ func (c *Common) GetServices() (*corev1.Service, *corev1.Service) { return desiredSvc, stableSvc } -func (c *Common) GetALBIngress() *extensionsv1beta1.Ingress { +func (c *Common) GetALBIngress() *networkingv1.Ingress { ro := c.Rollout() name := ro.Spec.Strategy.Canary.TrafficRouting.ALB.Ingress - ingress, err := c.kubeClient.ExtensionsV1beta1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) + ingress, err := c.kubeClient.NetworkingV1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) + c.CheckError(err) + return ingress +} + +func (c *Common) GetNginxIngressStable() *networkingv1.Ingress { + ro := c.Rollout() + name := ro.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress + ingress, err := c.kubeClient.NetworkingV1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) + c.CheckError(err) + return ingress +} + +func (c *Common) GetNginxIngressCanary() *networkingv1.Ingress { + ro := c.Rollout() + name := ro.Name + "-" + ro.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress + "-canary" + ingress, err := c.kubeClient.NetworkingV1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) c.CheckError(err) return ingress } diff --git a/test/kustomize/rollout/expected.yaml b/test/kustomize/rollout/expected.yaml index eebed46dc9..e9dee28f1c 100644 --- a/test/kustomize/rollout/expected.yaml +++ b/test/kustomize/rollout/expected.yaml @@ -351,7 +351,7 @@ spec: host: guestbook-canary-svc weight: 0 --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -365,5 +365,7 @@ spec: http: paths: - backend: - serviceName: website - servicePort: 80 + service: + name: website + port: + number: 80 diff --git a/test/kustomize/rollout/rollout.yaml b/test/kustomize/rollout/rollout.yaml index 5a0db90149..03b78371a3 100644 --- a/test/kustomize/rollout/rollout.yaml +++ b/test/kustomize/rollout/rollout.yaml @@ -182,7 +182,7 @@ spec: targetPort: 8080 --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: networking-ingress @@ -192,8 +192,10 @@ spec: http: paths: - backend: - serviceName: website - servicePort: 80 + service: + name: website + port: + number: 80 --- apiVersion: extensions/v1beta1 From 197f9db2e4a15a57f934b1ac90cc1f719708d258 Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Thu, 11 Nov 2021 12:36:37 -0500 Subject: [PATCH 26/90] fix(e2e): DeFlake E2E Tests #1647 (#1648) Signed-off-by: Rohit Agrawal --- Makefile | 4 ++-- test/e2e/analysis_test.go | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2c2409ece6..ea5b1f9115 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ DEV_IMAGE=false # E2E variables E2E_INSTANCE_ID ?= argo-rollouts-e2e E2E_TEST_OPTIONS ?= -E2E_PARALLEL ?= 1 +E2E_PARALLEL ?= 4 override LDFLAGS += \ -X ${PACKAGE}/utils/version.version=${VERSION} \ @@ -244,7 +244,7 @@ start-e2e: .PHONY: test-e2e test-e2e: - go test -timeout 20m -v -count 1 --tags e2e -p ${E2E_PARALLEL} --short ./test/e2e ${E2E_TEST_OPTIONS} + go test -timeout 30m -v -count 1 --tags e2e -p ${E2E_PARALLEL} --short ./test/e2e ${E2E_TEST_OPTIONS} .PHONY: coverage coverage: test diff --git a/test/e2e/analysis_test.go b/test/e2e/analysis_test.go index 394f5dd064..dfe8f44f21 100644 --- a/test/e2e/analysis_test.go +++ b/test/e2e/analysis_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e @@ -450,6 +451,7 @@ spec: args: null `). WaitForRolloutStatus("Paused"). + Sleep(2*time.Second). // Give some time before validating the scaling down event Then(). ExpectRevisionPodCount("1", 1). ExpectRevisionScaleDown("2", true). @@ -459,6 +461,7 @@ spec: When(). PromoteRollout(). WaitForRolloutStatus("Healthy"). + Sleep(2*time.Second). // Give some time before validating the scaling down event Then(). ExpectRevisionPodCount("1", 1). ExpectRevisionScaleDown("1", true). @@ -714,6 +717,7 @@ func (s *AnalysisSuite) TestBackgroundAnalysisWithArgs() { When(). UpdateSpec(). WaitForRolloutStatus("Paused"). + Sleep(3 * time.Second). // Give some time before validating that AnalysisRun got kicked off Then(). ExpectAnalysisRunCount(1). ExpectBackgroundAnalysisRunPhase("Running"). From 06e2c303523c6e510e7d45b23c48232300a904c6 Mon Sep 17 00:00:00 2001 From: Leonardo Luz Almeida Date: Fri, 12 Nov 2021 17:51:38 -0500 Subject: [PATCH 27/90] fix: nginx traffic router patching wrong ingress resource (#1655) Signed-off-by: Leonardo Luz Almeida --- rollout/trafficrouting/nginx/nginx.go | 2 +- rollout/trafficrouting/nginx/nginx_test.go | 42 +++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/rollout/trafficrouting/nginx/nginx.go b/rollout/trafficrouting/nginx/nginx.go index cd55787fb2..2b6e6b9399 100644 --- a/rollout/trafficrouting/nginx/nginx.go +++ b/rollout/trafficrouting/nginx/nginx.go @@ -298,7 +298,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("desiredWeight", desiredWeight).Info("updating canary Ingress") r.cfg.Recorder.Eventf(r.cfg.Rollout, record.EventOptions{EventReason: "PatchingCanaryIngress"}, "Updating Ingress `%s` to desiredWeight '%d'", canaryIngressName, desiredWeight) - _, err = r.cfg.Client.ExtensionsV1beta1().Ingresses(r.cfg.Rollout.Namespace).Patch(ctx, canaryIngressName, types.MergePatchType, patch, metav1.PatchOptions{}) + _, err = r.cfg.IngressWrapper.Patch(ctx, r.cfg.Rollout.Namespace, canaryIngressName, types.MergePatchType, patch, metav1.PatchOptions{}) if err != nil { r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error patching canary ingress") return fmt.Errorf("error patching canary ingress `%s`: %v", canaryIngressName, err) diff --git a/rollout/trafficrouting/nginx/nginx_test.go b/rollout/trafficrouting/nginx/nginx_test.go index 6f72fe1a4b..2b3a7cf328 100644 --- a/rollout/trafficrouting/nginx/nginx_test.go +++ b/rollout/trafficrouting/nginx/nginx_test.go @@ -30,7 +30,7 @@ func networkingIngress(name string, port int, serviceName string) *networkingv1. return &networkingv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: "some-namespace", + Namespace: metav1.NamespaceDefault, Annotations: map[string]string{ "annotation-key1": "annotation-value1", }, @@ -511,6 +511,46 @@ func TestReconcileStableAndCanaryIngressFoundPatch(t *testing.T) { } } +func TestReconcileWillInvokeNetworkingIngress(t *testing.T) { + // given + rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") + stableIngress := networkingIngress("stable-ingress", 80, "stable-service") + canaryIngress := networkingIngress("rollout-stable-ingress-canary", 80, "canary-service") + canaryIngress.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "15", + }) + canaryIngress.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(rollout, schema.GroupVersionKind{Group: "argoproj.io", Version: "v1alpha1", Kind: "Rollout"})}) + client := fake.NewSimpleClientset(stableIngress, canaryIngress) + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Networking().V1().Ingresses().Informer().GetIndexer().Add(stableIngress) + k8sI.Networking().V1().Ingresses().Informer().GetIndexer().Add(canaryIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeNetworking, client, k8sI) + if err != nil { + t.Fatal(err) + } + r := NewReconciler(ReconcilerConfig{ + Rollout: rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + + // when + err = r.SetWeight(10) + + // then + assert.Nil(t, err, "Reconcile returns no error") + actions := client.Actions() + assert.Len(t, actions, 1) + if !t.Failed() { + // Avoid "index out of range" errors + assert.Equal(t, "patch", actions[0].GetVerb(), "action: patch canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1", Resource: "ingresses"}, actions[0].GetResource(), "action: patch canary ingress") + } +} + func TestReconcileStableAndCanaryIngressFoundNoChange(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") From 50bfe5ace8989057bb9fbff1447dff7eb791643b Mon Sep 17 00:00:00 2001 From: ilyagorban-codefresh <75360841+ilyagorban-codefresh@users.noreply.github.com> Date: Tue, 14 Sep 2021 13:01:39 +0300 Subject: [PATCH 28/90] replace argoproj for ghcr.io and quay.io (#4) Co-authored-by: Ilya Gorban From 2346db2a1730f27d5f8e5aafc82726d2fdba2dee Mon Sep 17 00:00:00 2001 From: danielm-codefresh Date: Tue, 8 Mar 2022 15:38:28 +0200 Subject: [PATCH 29/90] fix update-manifest script to point to codefresh quay registry --- hack/update-manifests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hack/update-manifests.sh b/hack/update-manifests.sh index 161b149bc5..ffc9c876e1 100755 --- a/hack/update-manifests.sh +++ b/hack/update-manifests.sh @@ -15,8 +15,8 @@ if [ ! -z "${IMAGE_TAG}" ]; then fi if [ ! -z "${SET_IMAGE_NAMESPACE}" ] || [ ! -z "${SET_IMAGE_TAG}" ]; then - (cd ${SRCROOT}/manifests/base && kustomize edit set image quay.io/argoproj/argo-rollouts${SET_IMAGE_NAMESPACE}${SET_IMAGE_TAG}) - (cd ${SRCROOT}/manifests/dashboard-install && kustomize edit set image quay.io/argoproj/kubectl-argo-rollouts${SET_IMAGE_NAMESPACE}${SET_IMAGE_TAG}) + (cd ${SRCROOT}/manifests/base && kustomize edit set image quay.io/codefresh/argo-rollouts${SET_IMAGE_NAMESPACE}${SET_IMAGE_TAG}) + (cd ${SRCROOT}/manifests/dashboard-install && kustomize edit set image quay.io/codefresh/kubectl-argo-rollouts${SET_IMAGE_NAMESPACE}${SET_IMAGE_TAG}) fi kust_cmd="kustomize build --load-restrictor LoadRestrictionsNone" From cc7a3c466b6beee0f4b0a3ff0a6e39cf51a4f841 Mon Sep 17 00:00:00 2001 From: Kiran Meduri Date: Thu, 28 Oct 2021 09:37:18 -0700 Subject: [PATCH 30/90] fix: Handle minor version with '+' when determining ingress mode (#1529) (#1612) Signed-off-by: Kiran Meduri --- utils/ingress/ingress.go | 7 +++++-- utils/ingress/ingress_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/utils/ingress/ingress.go b/utils/ingress/ingress.go index e2662e0ddb..ad9c9ee316 100644 --- a/utils/ingress/ingress.go +++ b/utils/ingress/ingress.go @@ -275,7 +275,11 @@ func DetermineIngressMode(apiVersion string, d discovery.ServerVersionInterface) if err != nil { return 0, err } - minor, err := strconv.Atoi(ver.Minor) + verMinor := ver.Minor + if strings.HasSuffix(ver.Minor, "+") { + verMinor = ver.Minor[0 : len(ver.Minor)-1] + } + minor, err := strconv.Atoi(verMinor) if err != nil { return 0, err } @@ -286,5 +290,4 @@ func DetermineIngressMode(apiVersion string, d discovery.ServerVersionInterface) return IngressModeNetworking, nil } return IngressModeExtensions, nil - } diff --git a/utils/ingress/ingress_test.go b/utils/ingress/ingress_test.go index 36a013ee4a..eaca7e6a86 100644 --- a/utils/ingress/ingress_test.go +++ b/utils/ingress/ingress_test.go @@ -329,6 +329,12 @@ func TestDetermineIngressMode(t *testing.T) { faKeDiscovery: newFakeDiscovery("1", "18", nil), expectedMode: IngressModeExtensions, }, + { + name: "will return networking mode if server minor version has '+' suffix, e.g. 1.19+", + apiVersion: "", + faKeDiscovery: newFakeDiscovery("1", "19+", nil), + expectedMode: IngressModeNetworking, + }, { name: "will return error if fails to retrieve server version", apiVersion: "", @@ -358,6 +364,28 @@ func TestDetermineIngressMode(t *testing.T) { Err: errors.New("invalid syntax"), }, }, + { + name: "will return error if fails to parse minor version with '+' suffix, e.g. 1.wrong+", + apiVersion: "", + faKeDiscovery: newFakeDiscovery("1", "wrong+", nil), + expectedMode: 0, + expectedError: &strconv.NumError{ + Func: "Atoi", + Num: "wrong", + Err: errors.New("invalid syntax"), + }, + }, + { + name: "will return error if fails to parse minor version with just '+'", + apiVersion: "", + faKeDiscovery: newFakeDiscovery("1", "+", nil), + expectedMode: 0, + expectedError: &strconv.NumError{ + Func: "Atoi", + Num: "", + Err: errors.New("invalid syntax"), + }, + }, } for _, c := range cases { c := c // necessary to ensure all test cases are executed when running in parallel mode From 51c0fe1f4b9535f2da1a585b60089fe40af0410b Mon Sep 17 00:00:00 2001 From: Daniel Maizel Date: Thu, 12 May 2022 10:35:20 +0300 Subject: [PATCH 31/90] Update go.yml Added actions/setup-go@v2 step --- .github/workflows/go.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 60b6b2bd11..e652de40f4 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -13,6 +13,10 @@ jobs: name: Lint Go code runs-on: ubuntu-latest steps: + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.17 - name: Checkout code uses: actions/checkout@v2 - name: Run golangci-lint From 6e2c11a9d8ad3a2038b5d1ae5f4893f7ee639201 Mon Sep 17 00:00:00 2001 From: Daniel Maizel Date: Thu, 12 May 2022 10:45:22 +0300 Subject: [PATCH 32/90] Update go.yml --- .github/workflows/go.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index e652de40f4..03b7ee60c2 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -14,13 +14,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - name: Checkout code uses: actions/checkout@v2 - name: Run golangci-lint - uses: golangci/golangci-lint-action@v2 + uses: golangci/golangci-lint-action@v3 with: version: v1.30 args: --timeout 5m From f1e9dd27701bde2fcb8e2fd8f0823526917616b2 Mon Sep 17 00:00:00 2001 From: elad-codefresh Date: Thu, 12 May 2022 10:50:07 +0300 Subject: [PATCH 33/90] lint --- rollout/controller_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollout/controller_test.go b/rollout/controller_test.go index a02d5e8267..61a2b351f1 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -519,7 +519,7 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share f.t.Fatal(err) } - ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, f.kubeclient, k8sI) + ingressWrapper, err = ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, f.kubeclient, k8sI) if err != nil { f.t.Fatal(err) } From 54192d04ff154322b06c18ce20c488de6dacbe1f Mon Sep 17 00:00:00 2001 From: elad-codefresh Date: Thu, 12 May 2022 10:51:45 +0300 Subject: [PATCH 34/90] removed redundant --- rollout/controller_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 61a2b351f1..7f324ea10b 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -519,11 +519,6 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share f.t.Fatal(err) } - ingressWrapper, err = ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, f.kubeclient, k8sI) - if err != nil { - f.t.Fatal(err) - } - c := NewController(ControllerConfig{ Namespace: metav1.NamespaceAll, KubeClientSet: f.kubeclient, From e1a202179b73850d15562d3a2f5105c90495205e Mon Sep 17 00:00:00 2001 From: Daniel Maizel Date: Thu, 19 May 2022 20:48:51 +0300 Subject: [PATCH 35/90] Update release.yaml --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a8471d22c7..b48aa2ed39 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -137,7 +137,7 @@ jobs: # managers (gomod, yarn, npm). PROJECT_FOLDERS: ".,./ui" # full qualified name of the docker image to be inspected - DOCKER_IMAGE: quay.io/argoproj/argo-rollouts:${{ github.event.inputs.tag }} + DOCKER_IMAGE: quay.io/codefresh/argo-rollouts:${{ github.event.inputs.tag }} run: | yarn install --cwd ./ui From e37fea158e445aae89794a104583c278ebbe5aad Mon Sep 17 00:00:00 2001 From: kezhenxu94 Date: Tue, 20 Dec 2022 04:07:56 +0000 Subject: [PATCH 36/90] Add SkyWalking metrics provider Signed-off-by: kezhenxu94 --- docs/analysis/skywalking.md | 35 + .../features/kustomize/rollout_cr_schema.json | 42 + go.mod | 3 + go.sum | 4 + manifests/crds/analysis-run-crd.yaml | 9 + manifests/crds/analysis-template-crd.yaml | 9 + .../crds/cluster-analysis-template-crd.yaml | 9 + manifests/install.yaml | 27 + manifests/namespace-install.yaml | 27 + metricproviders/metricproviders.go | 9 + metricproviders/skywalking/mock_test.go | 13 + metricproviders/skywalking/skywalking.go | 150 ++ metricproviders/skywalking/skywalking_test.go | 194 +++ mkdocs.yml | 1 + pkg/apis/api-rules/violation_exceptions.list | 1 + pkg/apis/rollouts/v1alpha1/analysis_types.go | 8 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 1296 ++++++++++------- pkg/apis/rollouts/v1alpha1/generated.proto | 11 + .../rollouts/v1alpha1/openapi_generated.go | 39 +- .../v1alpha1/zz_generated.deepcopy.go | 21 + utils/analysis/factory.go | 3 + utils/evaluate/evaluate_test.go | 14 +- 22 files changed, 1422 insertions(+), 503 deletions(-) create mode 100644 docs/analysis/skywalking.md create mode 100644 metricproviders/skywalking/mock_test.go create mode 100644 metricproviders/skywalking/skywalking.go create mode 100644 metricproviders/skywalking/skywalking_test.go diff --git a/docs/analysis/skywalking.md b/docs/analysis/skywalking.md new file mode 100644 index 0000000000..993c2c313a --- /dev/null +++ b/docs/analysis/skywalking.md @@ -0,0 +1,35 @@ +# Apache SkyWalking Metrics + +!!! important + Available since v1.5.0 + +A [SkyWalking](https://skywalking.apache.org/) query using GraphQL can be used to obtain measurements for analysis. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: AnalysisTemplate +metadata: + name: apdex +spec: + args: + - name: service-name + metrics: + - name: apdex + interval: 5m + successCondition: "all(result.service_apdex.values.values, {asFloat(.value) >= 9900})" + failureLimit: 3 + provider: + skywalking: + interval: 3m + address: http://skywalking-oap.istio-system:12800 + query: | + query queryData($duration: Duration!) { + service_apdex: readMetricsValues( + condition: { name: "service_apdex", entity: { scope: Service, serviceName: "{{ args.service-name }}", normal: true } }, + duration: $duration) { + label values { values { value } } + } + } +``` + +The `result` evaluated for the query depends on the specific GraphQL you give, you can try to run the GraphQL query first and inspect the output format, then compose the condition. diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index fbff809be6..e81cc03214 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -4176,6 +4176,20 @@ }, "type": "object" }, + "skywalking": { + "properties": { + "address": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, "wavefront": { "properties": { "address": { @@ -8444,6 +8458,20 @@ }, "type": "object" }, + "skywalking": { + "properties": { + "address": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, "wavefront": { "properties": { "address": { @@ -12712,6 +12740,20 @@ }, "type": "object" }, + "skywalking": { + "properties": { + "address": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, "wavefront": { "properties": { "address": { diff --git a/go.mod b/go.mod index ff8b55a221..304313f599 100644 --- a/go.mod +++ b/go.mod @@ -53,6 +53,8 @@ require ( ) +require github.com/matryer/is v1.4.0 // indirect + require ( cloud.google.com/go/compute v1.7.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect @@ -121,6 +123,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lunixbochs/vtclean v1.0.0 // indirect + github.com/machinebox/graphql v0.2.2 github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect diff --git a/go.sum b/go.sum index 2819dc9531..a9f201cd37 100644 --- a/go.sum +++ b/go.sum @@ -667,6 +667,8 @@ github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+L github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0= github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg= +github.com/machinebox/graphql v0.2.2 h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkBZfo= +github.com/machinebox/graphql v0.2.2/go.mod h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -678,6 +680,8 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index da21888bde..1f370972f7 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -2707,6 +2707,15 @@ spec: query: type: string type: object + skywalking: + properties: + address: + type: string + interval: + type: string + query: + type: string + type: object wavefront: properties: address: diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index 1e37db2dd0..4fec3af46c 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -2703,6 +2703,15 @@ spec: query: type: string type: object + skywalking: + properties: + address: + type: string + interval: + type: string + query: + type: string + type: object wavefront: properties: address: diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index fb149f2fa3..2873fcabe5 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -2703,6 +2703,15 @@ spec: query: type: string type: object + skywalking: + properties: + address: + type: string + interval: + type: string + query: + type: string + type: object wavefront: properties: address: diff --git a/manifests/install.yaml b/manifests/install.yaml index c90546d8b7..fe720daaa0 100755 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2708,6 +2708,15 @@ spec: query: type: string type: object + skywalking: + properties: + address: + type: string + interval: + type: string + query: + type: string + type: object wavefront: properties: address: @@ -5585,6 +5594,15 @@ spec: query: type: string type: object + skywalking: + properties: + address: + type: string + interval: + type: string + query: + type: string + type: object wavefront: properties: address: @@ -8348,6 +8366,15 @@ spec: query: type: string type: object + skywalking: + properties: + address: + type: string + interval: + type: string + query: + type: string + type: object wavefront: properties: address: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 827b3ca280..75b6a3878e 100755 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -2708,6 +2708,15 @@ spec: query: type: string type: object + skywalking: + properties: + address: + type: string + interval: + type: string + query: + type: string + type: object wavefront: properties: address: @@ -5585,6 +5594,15 @@ spec: query: type: string type: object + skywalking: + properties: + address: + type: string + interval: + type: string + query: + type: string + type: object wavefront: properties: address: @@ -8348,6 +8366,15 @@ spec: query: type: string type: object + skywalking: + properties: + address: + type: string + interval: + type: string + query: + type: string + type: object wavefront: properties: address: diff --git a/metricproviders/metricproviders.go b/metricproviders/metricproviders.go index d8a1637acf..5bf57b56fb 100644 --- a/metricproviders/metricproviders.go +++ b/metricproviders/metricproviders.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/argoproj/argo-rollouts/metricproviders/influxdb" + "github.com/argoproj/argo-rollouts/metricproviders/skywalking" "github.com/argoproj/argo-rollouts/metricproviders/cloudwatch" "github.com/argoproj/argo-rollouts/metricproviders/datadog" @@ -101,6 +102,12 @@ func (f *ProviderFactory) NewProvider(logCtx log.Entry, metric v1alpha1.Metric) return nil, err } return influxdb.NewInfluxdbProvider(client, logCtx), nil + case skywalking.ProviderType: + client, err := skywalking.NewSkyWalkingClient(metric, f.KubeClient) + if err != nil { + return nil, err + } + return skywalking.NewSkyWalkingProvider(client, logCtx), nil default: return nil, fmt.Errorf("no valid provider in metric '%s'", metric.Name) } @@ -127,6 +134,8 @@ func Type(metric v1alpha1.Metric) string { return graphite.ProviderType } else if metric.Provider.Influxdb != nil { return influxdb.ProviderType + } else if metric.Provider.SkyWalking != nil { + return skywalking.ProviderType } return "Unknown Provider" diff --git a/metricproviders/skywalking/mock_test.go b/metricproviders/skywalking/mock_test.go new file mode 100644 index 0000000000..70a5b67867 --- /dev/null +++ b/metricproviders/skywalking/mock_test.go @@ -0,0 +1,13 @@ +package skywalking + +type mockAPI struct { + err error + results interface{} +} + +func (m mockAPI) Query(query string) (interface{}, error) { + if m.err != nil { + return m.results, m.err + } + return m.results, nil +} diff --git a/metricproviders/skywalking/skywalking.go b/metricproviders/skywalking/skywalking.go new file mode 100644 index 0000000000..eb343b1bdd --- /dev/null +++ b/metricproviders/skywalking/skywalking.go @@ -0,0 +1,150 @@ +package skywalking + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/machinebox/graphql" + log "github.com/sirupsen/logrus" + "k8s.io/client-go/kubernetes" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/utils/evaluate" + metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" +) + +type duration struct { + Start string `json:"start"` + End string `json:"end"` + Step string `json:"step"` +} + +const ( + // ProviderType indicates the provider is skywalking + ProviderType = "skywalking" + defaultQueryTimeout = 30 * time.Second +) + +type SkyWalkingClientAPI interface { + Query(query string) (interface{}, error) +} + +type SkyWalkingClient struct { + *graphql.Client + Interval time.Duration +} + +// Query executes a GraphQL query against the given SkyWalking backend +func (n SkyWalkingClient) Query(query string) (interface{}, error) { + ctx, cancel := context.WithTimeout(context.Background(), defaultQueryTimeout) + defer cancel() + + req := graphql.NewRequest(query) + req.Var("duration", duration{ + Start: time.Now().Add(-n.Interval).Format("2006-01-02 1504"), + End: time.Now().Format("2006-01-02 1504"), + Step: "MINUTE", + }) + var results interface{} + err := n.Run(ctx, req, &results) + return results, err +} + +type Provider struct { + client SkyWalkingClientAPI + logCtx log.Entry +} + +// Run queries SkyWalking for the metric +func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { + startTime := timeutil.MetaNow() + newMeasurement := v1alpha1.Measurement{ + StartedAt: &startTime, + } + + results, err := p.client.Query(metric.Provider.SkyWalking.Query) + if err != nil { + return metricutil.MarkMeasurementError(newMeasurement, err) + } + + valueStr, newStatus, err := p.processResponse(metric, results) + if err != nil { + return metricutil.MarkMeasurementError(newMeasurement, err) + } + newMeasurement.Value = valueStr + newMeasurement.Phase = newStatus + + finishedTime := timeutil.MetaNow() + newMeasurement.FinishedAt = &finishedTime + return newMeasurement +} + +func toJSONString(v interface{}) (string, error) { + b, err := json.Marshal(v) + if err != nil { + return "", err + } + return string(b), nil +} + +func (p *Provider) processResponse(metric v1alpha1.Metric, result interface{}) (string, v1alpha1.AnalysisPhase, error) { + if result == nil { + return "", v1alpha1.AnalysisPhaseFailed, fmt.Errorf("no results returned from SkyWalking query") + } + valueStr, err := toJSONString(result) + if err != nil { + return "", v1alpha1.AnalysisPhaseError, fmt.Errorf("could not marshal results: %w", err) + } + newStatus, err := evaluate.EvaluateResult(result, metric, p.logCtx) + return valueStr, newStatus, err +} + +// Resume should not be used the SkyWalking provider since all the work should occur in the Run method +func (p *Provider) Resume(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric, measurement v1alpha1.Measurement) v1alpha1.Measurement { + p.logCtx.Warn("SkyWalking provider should not execute the Resume method") + return measurement +} + +// Terminate should not be used the SkyWalking provider since all the work should occur in the Run method +func (p *Provider) Terminate(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric, measurement v1alpha1.Measurement) v1alpha1.Measurement { + p.logCtx.Warn("SkyWalking provider should not execute the Terminate method") + return measurement +} + +// GarbageCollect should not be used the SkyWalking provider since all the work should occur in the Run method +func (p *Provider) GarbageCollect(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric, i int) error { + return nil +} + +func (p *Provider) Type() string { + return ProviderType +} + +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + +// NewSkyWalkingProvider creates a new SkyWalking provider +func NewSkyWalkingProvider(client SkyWalkingClientAPI, logCtx log.Entry) *Provider { + return &Provider{ + logCtx: logCtx, + client: client, + } +} + +// NewSkyWalkingClient creates a new GraphQL API client from metric configuration +func NewSkyWalkingClient(metric v1alpha1.Metric, kubeclientset kubernetes.Interface) (*SkyWalkingClient, error) { + c := graphql.NewClient(metric.Provider.SkyWalking.Address + "/graphql") + d, err := metric.Provider.SkyWalking.Interval.Duration() + if err != nil { + return nil, err + } + return &SkyWalkingClient{ + Client: c, + Interval: d, + }, nil +} diff --git a/metricproviders/skywalking/skywalking_test.go b/metricproviders/skywalking/skywalking_test.go new file mode 100644 index 0000000000..47c1a60dc9 --- /dev/null +++ b/metricproviders/skywalking/skywalking_test.go @@ -0,0 +1,194 @@ +package skywalking + +import ( + "fmt" + "testing" + + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" +) + +func newAnalysisRun() *v1alpha1.AnalysisRun { + return &v1alpha1.AnalysisRun{} +} + +func TestType(t *testing.T) { + e := log.Entry{} + mock := &mockAPI{} + p := NewSkyWalkingProvider(mock, e) + assert.Equal(t, ProviderType, p.Type()) +} + +func TestRunSuccessfully(t *testing.T) { + e := log.Entry{} + mock := &mockAPI{ + results: map[string]interface{}{"count": 10}, + } + p := NewSkyWalkingProvider(mock, e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.count == 10", + FailureCondition: "result.count != 10", + Provider: v1alpha1.MetricProvider{ + SkyWalking: &v1alpha1.SkyWalkingMetric{ + Query: "test", + }, + }, + } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + + measurement := p.Run(newAnalysisRun(), metric) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, `{"count":10}`, measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, measurement.Phase) +} + +func TestRunWithTimeseries(t *testing.T) { + e := log.NewEntry(log.New()) + mock := &mockAPI{ + results: []interface{}{ + map[string]interface{}{"count": 10}, + map[string]interface{}{"count": 20}, + map[string]interface{}{"count": 30}}, + } + p := NewSkyWalkingProvider(mock, *e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result[0].count == 10", + FailureCondition: "result[2].count < 20", + Provider: v1alpha1.MetricProvider{ + SkyWalking: &v1alpha1.SkyWalkingMetric{ + Query: "test", + }, + }, + } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + + measurement := p.Run(newAnalysisRun(), metric) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, `[{"count":10},{"count":20},{"count":30}]`, measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, measurement.Phase) +} + +func TestRunWithQueryError(t *testing.T) { + e := log.NewEntry(log.New()) + expectedErr := fmt.Errorf("no results returned from SkyWalking query") + mock := &mockAPI{ + err: expectedErr, + } + p := NewSkyWalkingProvider(mock, *e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result == 10", + FailureCondition: "result != 10", + Provider: v1alpha1.MetricProvider{ + SkyWalking: &v1alpha1.SkyWalkingMetric{ + Query: "test", + }, + }, + } + measurement := p.Run(newAnalysisRun(), metric) + assert.Equal(t, expectedErr.Error(), measurement.Message) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, "", measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseError, measurement.Phase) +} + +func TestRunWithResolveArgsError(t *testing.T) { + e := log.NewEntry(log.New()) + expectedErr := fmt.Errorf("failed to resolve {{args.var}}") + mock := &mockAPI{ + err: expectedErr, + results: map[string]interface{}{"A": "B"}, + } + p := NewSkyWalkingProvider(mock, *e) + metric := v1alpha1.Metric{ + Name: "foo", + Provider: v1alpha1.MetricProvider{ + SkyWalking: &v1alpha1.SkyWalkingMetric{ + Query: "test", + }, + }, + } + measurement := p.Run(newAnalysisRun(), metric) + assert.Equal(t, expectedErr.Error(), measurement.Message) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, "", measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseError, measurement.Phase) +} + +func TestRunWithEvaluationError(t *testing.T) { + e := log.WithField("", "") + mock := &mockAPI{} + p := NewSkyWalkingProvider(mock, *e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result == 10", + FailureCondition: "result != 10", + Provider: v1alpha1.MetricProvider{ + SkyWalking: &v1alpha1.SkyWalkingMetric{ + Query: "test", + }, + }, + } + measurement := p.Run(newAnalysisRun(), metric) + assert.Equal(t, "no results returned from SkyWalking query", measurement.Message) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, "", measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseError, measurement.Phase) +} + +func TestResume(t *testing.T) { + e := log.WithField("", "") + mock := &mockAPI{} + p := NewSkyWalkingProvider(mock, *e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result == 10", + FailureCondition: "result != 10", + Provider: v1alpha1.MetricProvider{ + SkyWalking: &v1alpha1.SkyWalkingMetric{ + Query: "test", + }, + }, + } + now := metav1.Now() + previousMeasurement := v1alpha1.Measurement{ + StartedAt: &now, + Phase: v1alpha1.AnalysisPhaseInconclusive, + } + measurement := p.Resume(newAnalysisRun(), metric, previousMeasurement) + assert.Equal(t, previousMeasurement, measurement) +} + +func TestTerminate(t *testing.T) { + e := log.NewEntry(log.New()) + mock := &mockAPI{} + p := NewSkyWalkingProvider(mock, *e) + metric := v1alpha1.Metric{} + now := metav1.Now() + previousMeasurement := v1alpha1.Measurement{ + StartedAt: &now, + Phase: v1alpha1.AnalysisPhaseRunning, + } + measurement := p.Terminate(newAnalysisRun(), metric, previousMeasurement) + assert.Equal(t, previousMeasurement, measurement) +} + +func TestGarbageCollect(t *testing.T) { + e := log.NewEntry(log.New()) + mock := &mockAPI{} + p := NewSkyWalkingProvider(mock, *e) + err := p.GarbageCollect(nil, v1alpha1.Metric{}, 0) + assert.NoError(t, err) +} diff --git a/mkdocs.yml b/mkdocs.yml index 3781e5d314..0e2a2e2a46 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -63,6 +63,7 @@ nav: - CloudWatch: analysis/cloudwatch.md - Graphite: analysis/graphite.md - InfluxDB: analysis/influxdb.md + - Apache SkyWalking: analysis/skywalking.md - Experiments: features/experiment.md - Notifications: - Overview: features/notifications.md diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index 224d72b2e8..a07dc69dce 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -42,4 +42,5 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,TLSRoute,SNIHosts API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,TrafficWeights,Additional API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,WebMetric,Headers +API rule violation: names_match,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,MetricProvider,SkyWalking API rule violation: names_match,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutStatus,HPAReplicas diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index f26fc91585..e4cdaa0265 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -173,6 +173,8 @@ type MetricProvider struct { Graphite *GraphiteMetric `json:"graphite,omitempty" protobuf:"bytes,9,opt,name=graphite"` // Influxdb specifies the influxdb metric to query Influxdb *InfluxdbMetric `json:"influxdb,omitempty" protobuf:"bytes,10,opt,name=influxdb"` + // SkyWalking specifies the skywalking metric to query + SkyWalking *SkyWalkingMetric `json:"skywalking,omitempty" protobuf:"bytes,11,opt,name=skywalking"` } // AnalysisPhase is the overall phase of an AnalysisRun, MetricResult, or Measurement @@ -298,6 +300,12 @@ type AnalysisRunList struct { Items []AnalysisRun `json:"items" protobuf:"bytes,2,rep,name=items"` } +type SkyWalkingMetric struct { + Address string `json:"address,omitempty" protobuf:"bytes,1,opt,name=address"` + Query string `json:"query,omitempty" protobuf:"bytes,2,opt,name=query"` + Interval DurationString `json:"interval,omitempty" protobuf:"bytes,3,opt,name=interval,casttype=DurationString"` +} + // AnalysisRunSpec is the spec for a AnalysisRun resource type AnalysisRunSpec struct { // Metrics contains the list of metrics to query as part of an analysis run diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 6cdc52bc37..510110d641 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -2658,10 +2658,38 @@ func (m *SetMirrorRoute) XXX_DiscardUnknown() { var xxx_messageInfo_SetMirrorRoute proto.InternalMessageInfo +func (m *SkyWalkingMetric) Reset() { *m = SkyWalkingMetric{} } +func (*SkyWalkingMetric) ProtoMessage() {} +func (*SkyWalkingMetric) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{93} +} +func (m *SkyWalkingMetric) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SkyWalkingMetric) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *SkyWalkingMetric) XXX_Merge(src proto.Message) { + xxx_messageInfo_SkyWalkingMetric.Merge(m, src) +} +func (m *SkyWalkingMetric) XXX_Size() int { + return m.Size() +} +func (m *SkyWalkingMetric) XXX_DiscardUnknown() { + xxx_messageInfo_SkyWalkingMetric.DiscardUnknown(m) +} + +var xxx_messageInfo_SkyWalkingMetric proto.InternalMessageInfo + func (m *StickinessConfig) Reset() { *m = StickinessConfig{} } func (*StickinessConfig) ProtoMessage() {} func (*StickinessConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{93} + return fileDescriptor_e0e705f843545fab, []int{94} } func (m *StickinessConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2689,7 +2717,7 @@ var xxx_messageInfo_StickinessConfig proto.InternalMessageInfo func (m *StringMatch) Reset() { *m = StringMatch{} } func (*StringMatch) ProtoMessage() {} func (*StringMatch) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{94} + return fileDescriptor_e0e705f843545fab, []int{95} } func (m *StringMatch) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2717,7 +2745,7 @@ var xxx_messageInfo_StringMatch proto.InternalMessageInfo func (m *TCPRoute) Reset() { *m = TCPRoute{} } func (*TCPRoute) ProtoMessage() {} func (*TCPRoute) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{95} + return fileDescriptor_e0e705f843545fab, []int{96} } func (m *TCPRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2745,7 +2773,7 @@ var xxx_messageInfo_TCPRoute proto.InternalMessageInfo func (m *TLSRoute) Reset() { *m = TLSRoute{} } func (*TLSRoute) ProtoMessage() {} func (*TLSRoute) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{96} + return fileDescriptor_e0e705f843545fab, []int{97} } func (m *TLSRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2773,7 +2801,7 @@ var xxx_messageInfo_TLSRoute proto.InternalMessageInfo func (m *TemplateService) Reset() { *m = TemplateService{} } func (*TemplateService) ProtoMessage() {} func (*TemplateService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{97} + return fileDescriptor_e0e705f843545fab, []int{98} } func (m *TemplateService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2801,7 +2829,7 @@ var xxx_messageInfo_TemplateService proto.InternalMessageInfo func (m *TemplateSpec) Reset() { *m = TemplateSpec{} } func (*TemplateSpec) ProtoMessage() {} func (*TemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{98} + return fileDescriptor_e0e705f843545fab, []int{99} } func (m *TemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2829,7 +2857,7 @@ var xxx_messageInfo_TemplateSpec proto.InternalMessageInfo func (m *TemplateStatus) Reset() { *m = TemplateStatus{} } func (*TemplateStatus) ProtoMessage() {} func (*TemplateStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{99} + return fileDescriptor_e0e705f843545fab, []int{100} } func (m *TemplateStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2857,7 +2885,7 @@ var xxx_messageInfo_TemplateStatus proto.InternalMessageInfo func (m *TraefikTrafficRouting) Reset() { *m = TraefikTrafficRouting{} } func (*TraefikTrafficRouting) ProtoMessage() {} func (*TraefikTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{100} + return fileDescriptor_e0e705f843545fab, []int{101} } func (m *TraefikTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2885,7 +2913,7 @@ var xxx_messageInfo_TraefikTrafficRouting proto.InternalMessageInfo func (m *TrafficWeights) Reset() { *m = TrafficWeights{} } func (*TrafficWeights) ProtoMessage() {} func (*TrafficWeights) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{101} + return fileDescriptor_e0e705f843545fab, []int{102} } func (m *TrafficWeights) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2913,7 +2941,7 @@ var xxx_messageInfo_TrafficWeights proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{102} + return fileDescriptor_e0e705f843545fab, []int{103} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2941,7 +2969,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *WavefrontMetric) Reset() { *m = WavefrontMetric{} } func (*WavefrontMetric) ProtoMessage() {} func (*WavefrontMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{103} + return fileDescriptor_e0e705f843545fab, []int{104} } func (m *WavefrontMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2969,7 +2997,7 @@ var xxx_messageInfo_WavefrontMetric proto.InternalMessageInfo func (m *WebMetric) Reset() { *m = WebMetric{} } func (*WebMetric) ProtoMessage() {} func (*WebMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{104} + return fileDescriptor_e0e705f843545fab, []int{105} } func (m *WebMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2997,7 +3025,7 @@ var xxx_messageInfo_WebMetric proto.InternalMessageInfo func (m *WebMetricHeader) Reset() { *m = WebMetricHeader{} } func (*WebMetricHeader) ProtoMessage() {} func (*WebMetricHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{105} + return fileDescriptor_e0e705f843545fab, []int{106} } func (m *WebMetricHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3025,7 +3053,7 @@ var xxx_messageInfo_WebMetricHeader proto.InternalMessageInfo func (m *WeightDestination) Reset() { *m = WeightDestination{} } func (*WeightDestination) ProtoMessage() {} func (*WeightDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{106} + return fileDescriptor_e0e705f843545fab, []int{107} } func (m *WeightDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3150,6 +3178,7 @@ func init() { proto.RegisterType((*SetCanaryScale)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetCanaryScale") proto.RegisterType((*SetHeaderRoute)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRoute") proto.RegisterType((*SetMirrorRoute)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetMirrorRoute") + proto.RegisterType((*SkyWalkingMetric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SkyWalkingMetric") proto.RegisterType((*StickinessConfig)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StickinessConfig") proto.RegisterType((*StringMatch)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StringMatch") proto.RegisterType((*TCPRoute)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TCPRoute") @@ -3171,493 +3200,496 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 7773 bytes of a gzipped FileDescriptorProto + // 7816 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x6c, 0x23, 0xd7, - 0x75, 0xb0, 0x87, 0x14, 0x25, 0xf2, 0xe8, 0xff, 0xae, 0x36, 0x2b, 0xcb, 0xde, 0xa5, 0x33, 0x0e, - 0xfc, 0x39, 0xdf, 0xe7, 0x48, 0x89, 0x7f, 0xbe, 0xcf, 0x89, 0x0d, 0x7f, 0x25, 0xa5, 0x5d, 0xaf, - 0xd6, 0xd2, 0x2e, 0xf7, 0x52, 0xbb, 0x9b, 0x38, 0x71, 0x92, 0x11, 0x79, 0x45, 0xcd, 0x8a, 0x9c, - 0x61, 0x66, 0x86, 0xd2, 0xca, 0x31, 0x12, 0x3b, 0x81, 0xdd, 0xb4, 0x48, 0x10, 0xb7, 0x49, 0x50, - 0x14, 0x05, 0x8a, 0xa0, 0x30, 0xd0, 0x9f, 0xe4, 0x29, 0x68, 0xd1, 0x97, 0x00, 0x2d, 0x9a, 0x9f, - 0xa6, 0x0f, 0x29, 0x92, 0x87, 0x36, 0x3f, 0x40, 0xd8, 0x5a, 0xe9, 0x4b, 0x8b, 0x16, 0x41, 0x81, - 0x14, 0x45, 0xf6, 0xa9, 0xb8, 0xbf, 0x73, 0x67, 0x38, 0xd4, 0x52, 0xe2, 0x68, 0x63, 0xb4, 0x79, - 0x23, 0xef, 0x39, 0xf7, 0x9c, 0x73, 0x7f, 0xcf, 0xbd, 0xe7, 0x9e, 0x73, 0x06, 0xd6, 0x1a, 0x76, - 0xb0, 0xdd, 0xd9, 0x5c, 0xac, 0xb9, 0xad, 0x25, 0xcb, 0x6b, 0xb8, 0x6d, 0xcf, 0xbd, 0xc9, 0x7e, - 0xbc, 0xcb, 0x73, 0x9b, 0x4d, 0xb7, 0x13, 0xf8, 0x4b, 0xed, 0x9d, 0xc6, 0x92, 0xd5, 0xb6, 0xfd, - 0x25, 0x55, 0xb2, 0xfb, 0x1e, 0xab, 0xd9, 0xde, 0xb6, 0xde, 0xb3, 0xd4, 0x20, 0x0e, 0xf1, 0xac, - 0x80, 0xd4, 0x17, 0xdb, 0x9e, 0x1b, 0xb8, 0xe8, 0xe9, 0x90, 0xda, 0xa2, 0xa4, 0xc6, 0x7e, 0x7c, - 0x44, 0xd6, 0x5d, 0x6c, 0xef, 0x34, 0x16, 0x29, 0xb5, 0x45, 0x55, 0x22, 0xa9, 0x2d, 0xbc, 0x4b, - 0x93, 0xa5, 0xe1, 0x36, 0xdc, 0x25, 0x46, 0x74, 0xb3, 0xb3, 0xc5, 0xfe, 0xb1, 0x3f, 0xec, 0x17, - 0x67, 0xb6, 0xf0, 0xe0, 0xce, 0x93, 0xfe, 0xa2, 0xed, 0x52, 0xd9, 0x96, 0x36, 0xad, 0xa0, 0xb6, - 0xbd, 0xb4, 0xdb, 0x23, 0xd1, 0x82, 0xa9, 0x21, 0xd5, 0x5c, 0x8f, 0x24, 0xe1, 0x3c, 0x1e, 0xe2, - 0xb4, 0xac, 0xda, 0xb6, 0xed, 0x10, 0x6f, 0x3f, 0x6c, 0x75, 0x8b, 0x04, 0x56, 0x52, 0xad, 0xa5, - 0x7e, 0xb5, 0xbc, 0x8e, 0x13, 0xd8, 0x2d, 0xd2, 0x53, 0xe1, 0xff, 0xde, 0xa9, 0x82, 0x5f, 0xdb, - 0x26, 0x2d, 0xab, 0xa7, 0xde, 0x63, 0xfd, 0xea, 0x75, 0x02, 0xbb, 0xb9, 0x64, 0x3b, 0x81, 0x1f, - 0x78, 0xf1, 0x4a, 0xe6, 0x37, 0xb3, 0x50, 0x28, 0xad, 0x95, 0xab, 0x81, 0x15, 0x74, 0x7c, 0xf4, - 0x9a, 0x01, 0x13, 0x4d, 0xd7, 0xaa, 0x97, 0xad, 0xa6, 0xe5, 0xd4, 0x88, 0x37, 0x6f, 0x3c, 0x60, - 0x3c, 0x3c, 0xfe, 0xe8, 0xda, 0xe2, 0x30, 0xe3, 0xb5, 0x58, 0xda, 0xf3, 0x31, 0xf1, 0xdd, 0x8e, - 0x57, 0x23, 0x98, 0x6c, 0x95, 0xe7, 0xbe, 0xd3, 0x2d, 0xde, 0x73, 0xd0, 0x2d, 0x4e, 0xac, 0x69, - 0x9c, 0x70, 0x84, 0x2f, 0xfa, 0x92, 0x01, 0xb3, 0x35, 0xcb, 0xb1, 0xbc, 0xfd, 0x0d, 0xcb, 0x6b, - 0x90, 0xe0, 0x59, 0xcf, 0xed, 0xb4, 0xe7, 0x33, 0x27, 0x20, 0xcd, 0xbd, 0x42, 0x9a, 0xd9, 0xe5, - 0x38, 0x3b, 0xdc, 0x2b, 0x01, 0x93, 0xcb, 0x0f, 0xac, 0xcd, 0x26, 0xd1, 0xe5, 0xca, 0x9e, 0xa4, - 0x5c, 0xd5, 0x38, 0x3b, 0xdc, 0x2b, 0x81, 0xf9, 0x6a, 0x16, 0x66, 0x4b, 0x6b, 0xe5, 0x0d, 0xcf, - 0xda, 0xda, 0xb2, 0x6b, 0xd8, 0xed, 0x04, 0xb6, 0xd3, 0x40, 0xef, 0x84, 0x31, 0xdb, 0x69, 0x78, - 0xc4, 0xf7, 0xd9, 0x40, 0x16, 0xca, 0xd3, 0x82, 0xe8, 0xd8, 0x2a, 0x2f, 0xc6, 0x12, 0x8e, 0x9e, - 0x80, 0x71, 0x9f, 0x78, 0xbb, 0x76, 0x8d, 0x54, 0x5c, 0x2f, 0x60, 0x3d, 0x9d, 0x2b, 0x9f, 0x12, - 0xe8, 0xe3, 0xd5, 0x10, 0x84, 0x75, 0x3c, 0x5a, 0xcd, 0x73, 0xdd, 0x40, 0xc0, 0x59, 0x47, 0x14, - 0xc2, 0x6a, 0x38, 0x04, 0x61, 0x1d, 0x0f, 0xbd, 0x6e, 0xc0, 0x8c, 0x1f, 0xd8, 0xb5, 0x1d, 0xdb, - 0x21, 0xbe, 0xbf, 0xec, 0x3a, 0x5b, 0x76, 0x63, 0x3e, 0xc7, 0x7a, 0xf1, 0xf2, 0x70, 0xbd, 0x58, - 0x8d, 0x51, 0x2d, 0xcf, 0x1d, 0x74, 0x8b, 0x33, 0xf1, 0x52, 0xdc, 0xc3, 0x1d, 0xad, 0xc0, 0x8c, - 0xe5, 0x38, 0x6e, 0x60, 0x05, 0xb6, 0xeb, 0x54, 0x3c, 0xb2, 0x65, 0xdf, 0x9a, 0x1f, 0x61, 0xcd, - 0x99, 0x17, 0xcd, 0x99, 0x29, 0xc5, 0xe0, 0xb8, 0xa7, 0x86, 0xb9, 0x02, 0xf3, 0xa5, 0xd6, 0xa6, - 0xe5, 0xfb, 0x56, 0xdd, 0xf5, 0x62, 0xa3, 0xf1, 0x30, 0xe4, 0x5b, 0x56, 0xbb, 0x6d, 0x3b, 0x0d, - 0x3a, 0x1c, 0xd9, 0x87, 0x0b, 0xe5, 0x89, 0x83, 0x6e, 0x31, 0xbf, 0x2e, 0xca, 0xb0, 0x82, 0x9a, - 0x3f, 0xca, 0xc0, 0x78, 0xc9, 0xb1, 0x9a, 0xfb, 0xbe, 0xed, 0xe3, 0x8e, 0x83, 0x3e, 0x0a, 0x79, - 0xba, 0xbb, 0xd4, 0xad, 0xc0, 0x12, 0x2b, 0xf2, 0xdd, 0x8b, 0x7c, 0xb1, 0x2f, 0xea, 0x8b, 0x3d, - 0xec, 0x17, 0x8a, 0xbd, 0xb8, 0xfb, 0x9e, 0xc5, 0x2b, 0x9b, 0x37, 0x49, 0x2d, 0x58, 0x27, 0x81, - 0x55, 0x46, 0xa2, 0x15, 0x10, 0x96, 0x61, 0x45, 0x15, 0xb9, 0x30, 0xe2, 0xb7, 0x49, 0x4d, 0xac, - 0xb0, 0xf5, 0x21, 0x67, 0x72, 0x28, 0x7a, 0xb5, 0x4d, 0x6a, 0xe5, 0x09, 0xc1, 0x7a, 0x84, 0xfe, - 0xc3, 0x8c, 0x11, 0xda, 0x83, 0x51, 0x9f, 0xed, 0x39, 0x62, 0xf1, 0x5c, 0x49, 0x8f, 0x25, 0x23, - 0x5b, 0x9e, 0x12, 0x4c, 0x47, 0xf9, 0x7f, 0x2c, 0xd8, 0x99, 0x3f, 0x36, 0xe0, 0x94, 0x86, 0x5d, - 0xf2, 0x1a, 0x9d, 0x16, 0x71, 0x02, 0xf4, 0x00, 0x8c, 0x38, 0x56, 0x8b, 0x88, 0x85, 0xa2, 0x44, - 0xbe, 0x6c, 0xb5, 0x08, 0x66, 0x10, 0xf4, 0x20, 0xe4, 0x76, 0xad, 0x66, 0x87, 0xb0, 0x4e, 0x2a, - 0x94, 0x27, 0x05, 0x4a, 0xee, 0x3a, 0x2d, 0xc4, 0x1c, 0x86, 0x5e, 0x82, 0x02, 0xfb, 0x71, 0xc1, - 0x73, 0x5b, 0x29, 0x35, 0x4d, 0x48, 0x78, 0x5d, 0x92, 0x2d, 0x4f, 0x1e, 0x74, 0x8b, 0x05, 0xf5, - 0x17, 0x87, 0x0c, 0xcd, 0x7f, 0x30, 0x60, 0x5a, 0x6b, 0xdc, 0x9a, 0xed, 0x07, 0xe8, 0x43, 0x3d, - 0x93, 0x67, 0x71, 0xb0, 0xc9, 0x43, 0x6b, 0xb3, 0xa9, 0x33, 0x23, 0x5a, 0x9a, 0x97, 0x25, 0xda, - 0xc4, 0x71, 0x20, 0x67, 0x07, 0xa4, 0xe5, 0xcf, 0x67, 0x1e, 0xc8, 0x3e, 0x3c, 0xfe, 0xe8, 0x6a, - 0x6a, 0xc3, 0x18, 0xf6, 0xef, 0x2a, 0xa5, 0x8f, 0x39, 0x1b, 0xf3, 0x6b, 0x23, 0x91, 0x16, 0xd2, - 0x19, 0x85, 0x5c, 0x18, 0x6b, 0x91, 0xc0, 0xb3, 0x6b, 0x7c, 0x5d, 0x8d, 0x3f, 0xba, 0x32, 0x9c, - 0x14, 0xeb, 0x8c, 0x58, 0xb8, 0x59, 0xf2, 0xff, 0x3e, 0x96, 0x5c, 0xd0, 0x36, 0x8c, 0x58, 0x5e, - 0x43, 0xb6, 0xf9, 0x42, 0x3a, 0xe3, 0x1b, 0xce, 0xb9, 0x92, 0xd7, 0xf0, 0x31, 0xe3, 0x80, 0x96, - 0xa0, 0x10, 0x10, 0xaf, 0x65, 0x3b, 0x56, 0xc0, 0x77, 0xd7, 0x7c, 0x79, 0x56, 0xa0, 0x15, 0x36, - 0x24, 0x00, 0x87, 0x38, 0xa8, 0x09, 0xa3, 0x75, 0x6f, 0x1f, 0x77, 0x9c, 0xf9, 0x91, 0x34, 0xba, - 0x62, 0x85, 0xd1, 0x0a, 0x17, 0x13, 0xff, 0x8f, 0x05, 0x0f, 0xf4, 0x86, 0x01, 0x73, 0x2d, 0x62, - 0xf9, 0x1d, 0x8f, 0xd0, 0x26, 0x60, 0x12, 0x10, 0x87, 0xee, 0x86, 0xf3, 0x39, 0xc6, 0x1c, 0x0f, - 0x3b, 0x0e, 0xbd, 0x94, 0xcb, 0xf7, 0x0b, 0x51, 0xe6, 0x92, 0xa0, 0x38, 0x51, 0x1a, 0xf3, 0x47, - 0x23, 0x30, 0xdb, 0xb3, 0x43, 0xa0, 0xc7, 0x21, 0xd7, 0xde, 0xb6, 0x7c, 0xb9, 0xe4, 0xcf, 0xc9, - 0xf9, 0x56, 0xa1, 0x85, 0xb7, 0xbb, 0xc5, 0x49, 0x59, 0x85, 0x15, 0x60, 0x8e, 0x4c, 0x75, 0x6a, - 0x8b, 0xf8, 0xbe, 0xd5, 0x90, 0xfb, 0x80, 0x36, 0x4d, 0x58, 0x31, 0x96, 0x70, 0xf4, 0xeb, 0x06, - 0x4c, 0xf2, 0x29, 0x83, 0x89, 0xdf, 0x69, 0x06, 0x74, 0xaf, 0xa3, 0xdd, 0x72, 0x29, 0x8d, 0xe9, - 0xc9, 0x49, 0x96, 0x4f, 0x0b, 0xee, 0x93, 0x7a, 0xa9, 0x8f, 0xa3, 0x7c, 0xd1, 0x0d, 0x28, 0xf8, - 0x81, 0xe5, 0x05, 0xa4, 0x5e, 0x0a, 0x98, 0x56, 0x1b, 0x7f, 0xf4, 0x7f, 0x0f, 0xb6, 0x09, 0x6c, - 0xd8, 0x2d, 0xc2, 0x37, 0x9c, 0xaa, 0x24, 0x80, 0x43, 0x5a, 0xe8, 0x25, 0x00, 0xaf, 0xe3, 0x54, - 0x3b, 0xad, 0x96, 0xe5, 0xed, 0x0b, 0x0d, 0x7e, 0x71, 0xb8, 0xe6, 0x61, 0x45, 0x2f, 0xd4, 0x59, - 0x61, 0x19, 0xd6, 0xf8, 0xa1, 0x57, 0x0c, 0x98, 0xe4, 0x33, 0x51, 0x4a, 0x30, 0x9a, 0xb2, 0x04, - 0xb3, 0xb4, 0x6b, 0x57, 0x74, 0x16, 0x38, 0xca, 0xd1, 0xfc, 0xbb, 0xa8, 0x3e, 0xa9, 0x06, 0xf4, - 0x74, 0xdd, 0xd8, 0x47, 0x1f, 0x84, 0x7b, 0xfd, 0x4e, 0xad, 0x46, 0x7c, 0x7f, 0xab, 0xd3, 0xc4, - 0x1d, 0xe7, 0xa2, 0xed, 0x07, 0xae, 0xb7, 0xbf, 0x66, 0xb7, 0xec, 0x80, 0xcd, 0xb8, 0x5c, 0xf9, - 0xec, 0x41, 0xb7, 0x78, 0x6f, 0xb5, 0x1f, 0x12, 0xee, 0x5f, 0x1f, 0x59, 0x70, 0x5f, 0xc7, 0xe9, - 0x4f, 0x9e, 0x9f, 0xde, 0x8a, 0x07, 0xdd, 0xe2, 0x7d, 0xd7, 0xfa, 0xa3, 0xe1, 0xc3, 0x68, 0x98, - 0xff, 0x62, 0xc0, 0x8c, 0x6c, 0xd7, 0x06, 0x69, 0xb5, 0x9b, 0x74, 0x77, 0x39, 0xf9, 0x83, 0x48, - 0x10, 0x39, 0x88, 0xe0, 0x74, 0xd4, 0x89, 0x94, 0xbf, 0xdf, 0x69, 0xc4, 0xfc, 0x67, 0x03, 0xe6, - 0xe2, 0xc8, 0x77, 0x41, 0x79, 0xfa, 0x51, 0xe5, 0x79, 0x39, 0xdd, 0xd6, 0xf6, 0xd1, 0xa0, 0xaf, - 0x8d, 0xf4, 0xb6, 0xf5, 0xbf, 0xbb, 0x1a, 0x0d, 0xb5, 0x62, 0xf6, 0x97, 0xa9, 0x15, 0x47, 0xde, - 0x52, 0x5a, 0xf1, 0x8f, 0x46, 0x60, 0xa2, 0xe4, 0x04, 0x76, 0x69, 0x6b, 0xcb, 0x76, 0xec, 0x60, - 0x1f, 0x7d, 0x36, 0x03, 0x4b, 0x6d, 0x8f, 0x6c, 0x11, 0xcf, 0x23, 0xf5, 0x95, 0x8e, 0x67, 0x3b, - 0x8d, 0x6a, 0x6d, 0x9b, 0xd4, 0x3b, 0x4d, 0xdb, 0x69, 0xac, 0x36, 0x1c, 0x57, 0x15, 0x9f, 0xbf, - 0x45, 0x6a, 0x1d, 0xd6, 0x24, 0xbe, 0x28, 0x5a, 0xc3, 0x35, 0xa9, 0x72, 0x34, 0xa6, 0xe5, 0xc7, - 0x0e, 0xba, 0xc5, 0xa5, 0x23, 0x56, 0xc2, 0x47, 0x6d, 0x1a, 0xfa, 0x4c, 0x06, 0x16, 0x3d, 0xf2, - 0xb1, 0x8e, 0x3d, 0x78, 0x6f, 0xf0, 0x5d, 0xab, 0x39, 0xa4, 0xfa, 0x39, 0x12, 0xcf, 0xf2, 0xa3, - 0x07, 0xdd, 0xe2, 0x11, 0xeb, 0xe0, 0x23, 0xb6, 0xcb, 0xac, 0xc0, 0x78, 0xa9, 0x6d, 0xfb, 0xf6, - 0x2d, 0x7a, 0x97, 0x25, 0x03, 0xdc, 0x95, 0x8a, 0x90, 0xf3, 0x3a, 0x4d, 0xc2, 0xd7, 0x76, 0xa1, - 0x5c, 0xa0, 0xbb, 0x10, 0xa6, 0x05, 0x98, 0x97, 0x9b, 0x9f, 0xa2, 0x3b, 0x2e, 0x23, 0x19, 0xbb, - 0x25, 0xdf, 0x84, 0x9c, 0x47, 0x99, 0x88, 0x99, 0x35, 0xec, 0x85, 0x22, 0x94, 0x5a, 0x08, 0x41, - 0x7f, 0x62, 0xce, 0xc2, 0xfc, 0x46, 0x06, 0x4e, 0x97, 0xda, 0xed, 0x75, 0xe2, 0x6f, 0xc7, 0xa4, - 0xf8, 0xbc, 0x01, 0x53, 0xbb, 0xb6, 0x17, 0x74, 0xac, 0xa6, 0xb4, 0x6d, 0x70, 0x79, 0xaa, 0xc3, - 0xca, 0xc3, 0xb8, 0x5d, 0x8f, 0x90, 0x2e, 0xa3, 0x83, 0x6e, 0x71, 0x2a, 0x5a, 0x86, 0x63, 0xec, - 0xd1, 0xef, 0x18, 0x30, 0x23, 0x8a, 0x2e, 0xbb, 0x75, 0xa2, 0x1b, 0xc4, 0xae, 0xa5, 0x29, 0x93, - 0x22, 0xce, 0x2d, 0x27, 0xf1, 0x52, 0xdc, 0x23, 0x84, 0xf9, 0x6f, 0x19, 0x38, 0xd3, 0x87, 0x06, - 0xfa, 0x43, 0x03, 0xe6, 0xb8, 0x15, 0x4d, 0x03, 0x61, 0xb2, 0x25, 0x7a, 0xf3, 0x03, 0x69, 0x4b, - 0x8e, 0xe9, 0x12, 0x27, 0x4e, 0x8d, 0x94, 0xe7, 0xe9, 0x6e, 0xb8, 0x9c, 0xc0, 0x1a, 0x27, 0x0a, - 0xc4, 0x24, 0xe5, 0x76, 0xb5, 0x98, 0xa4, 0x99, 0xbb, 0x22, 0x69, 0x35, 0x81, 0x35, 0x4e, 0x14, - 0xc8, 0xfc, 0xff, 0x70, 0xdf, 0x21, 0xe4, 0xee, 0xbc, 0x38, 0xcd, 0x17, 0xd4, 0xac, 0x8f, 0xce, - 0xb9, 0x01, 0xd6, 0xb5, 0x09, 0xa3, 0x6c, 0xe9, 0xc8, 0x85, 0x0d, 0x54, 0xfd, 0xb1, 0x35, 0xe5, - 0x63, 0x01, 0x31, 0xbf, 0x61, 0x40, 0xfe, 0x08, 0x66, 0x95, 0x62, 0xd4, 0xac, 0x52, 0xe8, 0x31, - 0xa9, 0x04, 0xbd, 0x26, 0x95, 0x67, 0x87, 0x1b, 0x8d, 0x41, 0x4c, 0x29, 0x3f, 0x33, 0x60, 0xb6, - 0xc7, 0xf4, 0x82, 0xb6, 0x61, 0xae, 0xed, 0xd6, 0xe5, 0xb1, 0xe9, 0xa2, 0xe5, 0x6f, 0x33, 0x98, - 0x68, 0xde, 0xe3, 0x74, 0x24, 0x2b, 0x09, 0xf0, 0xdb, 0xdd, 0xe2, 0xbc, 0x22, 0x12, 0x43, 0xc0, - 0x89, 0x14, 0x51, 0x1b, 0xf2, 0x5b, 0x36, 0x69, 0xd6, 0xc3, 0x29, 0x38, 0xe4, 0x01, 0xe9, 0x82, - 0xa0, 0xc6, 0xad, 0x8e, 0xf2, 0x1f, 0x56, 0x5c, 0xcc, 0xab, 0x30, 0x15, 0xb5, 0x41, 0x0f, 0x30, - 0x78, 0x67, 0x21, 0x6b, 0x79, 0x8e, 0x18, 0xba, 0x71, 0x81, 0x90, 0x2d, 0xe1, 0xcb, 0x98, 0x96, - 0x9b, 0xbf, 0x18, 0x81, 0xe9, 0x72, 0xb3, 0x43, 0x9e, 0xf5, 0x08, 0x91, 0xd7, 0xee, 0x12, 0x4c, - 0xb7, 0x3d, 0xb2, 0x6b, 0x93, 0xbd, 0x2a, 0x69, 0x92, 0x5a, 0xe0, 0x7a, 0x82, 0xfe, 0x19, 0x51, - 0x7d, 0xba, 0x12, 0x05, 0xe3, 0x38, 0x3e, 0x7a, 0x06, 0xa6, 0xac, 0x5a, 0x60, 0xef, 0x12, 0x45, - 0x81, 0x0b, 0xf0, 0x36, 0x41, 0x61, 0xaa, 0x14, 0x81, 0xe2, 0x18, 0x36, 0xfa, 0x10, 0xcc, 0xfb, - 0x35, 0xab, 0x49, 0xae, 0xb5, 0x05, 0xab, 0xe5, 0x6d, 0x52, 0xdb, 0xa9, 0xb8, 0xb6, 0x13, 0x08, - 0x23, 0xcb, 0x03, 0x82, 0xd2, 0x7c, 0xb5, 0x0f, 0x1e, 0xee, 0x4b, 0x01, 0xfd, 0x85, 0x01, 0x67, - 0xdb, 0x1e, 0xa9, 0x78, 0x6e, 0xcb, 0xa5, 0xda, 0xb3, 0xc7, 0xf2, 0x20, 0x6e, 0xe0, 0xd7, 0x87, - 0x3c, 0x26, 0xf0, 0x92, 0x5e, 0xcb, 0xe7, 0xdb, 0x0f, 0xba, 0xc5, 0xb3, 0x95, 0xc3, 0x04, 0xc0, - 0x87, 0xcb, 0x87, 0xfe, 0xca, 0x80, 0x73, 0x6d, 0xd7, 0x0f, 0x0e, 0x69, 0x42, 0xee, 0x44, 0x9b, - 0x60, 0x1e, 0x74, 0x8b, 0xe7, 0x2a, 0x87, 0x4a, 0x80, 0xef, 0x20, 0xa1, 0x79, 0x30, 0x0e, 0xb3, - 0xda, 0xdc, 0x13, 0xd7, 0xf2, 0xa7, 0x60, 0x52, 0x4e, 0x86, 0x50, 0xad, 0x17, 0x42, 0x33, 0x4a, - 0x49, 0x07, 0xe2, 0x28, 0x2e, 0x9d, 0x77, 0x6a, 0x2a, 0xf2, 0xda, 0xb1, 0x79, 0x57, 0x89, 0x40, - 0x71, 0x0c, 0x1b, 0xad, 0xc2, 0x29, 0x51, 0x82, 0x49, 0xbb, 0x69, 0xd7, 0xac, 0x65, 0xb7, 0x23, - 0xa6, 0x5c, 0xae, 0x7c, 0xe6, 0xa0, 0x5b, 0x3c, 0x55, 0xe9, 0x05, 0xe3, 0xa4, 0x3a, 0x68, 0x0d, - 0xe6, 0xac, 0x4e, 0xe0, 0xaa, 0xf6, 0x9f, 0x77, 0xa8, 0xa6, 0xa8, 0xb3, 0xa9, 0x95, 0xe7, 0x2a, - 0xa5, 0x94, 0x00, 0xc7, 0x89, 0xb5, 0x50, 0x25, 0x46, 0xad, 0x4a, 0x6a, 0xae, 0x53, 0xe7, 0xa3, - 0x9c, 0x0b, 0x2f, 0x17, 0xa5, 0x04, 0x1c, 0x9c, 0x58, 0x13, 0x35, 0x61, 0xaa, 0x65, 0xdd, 0xba, - 0xe6, 0x58, 0xbb, 0x96, 0xdd, 0xa4, 0x4c, 0x84, 0x69, 0xa6, 0xbf, 0xbd, 0xa0, 0x13, 0xd8, 0xcd, - 0x45, 0xfe, 0x4a, 0xb9, 0xb8, 0xea, 0x04, 0x57, 0xbc, 0x6a, 0x40, 0x0f, 0xa1, 0xfc, 0x70, 0xb4, - 0x1e, 0xa1, 0x85, 0x63, 0xb4, 0xd1, 0x15, 0x38, 0xcd, 0x96, 0xe3, 0x8a, 0xbb, 0xe7, 0xac, 0x90, - 0xa6, 0xb5, 0x2f, 0x1b, 0x30, 0xc6, 0x1a, 0x70, 0xef, 0x41, 0xb7, 0x78, 0xba, 0x9a, 0x84, 0x80, - 0x93, 0xeb, 0x21, 0x0b, 0xee, 0x8b, 0x02, 0x30, 0xd9, 0xb5, 0x7d, 0xdb, 0x75, 0xb8, 0x81, 0x25, - 0x1f, 0x1a, 0x58, 0xaa, 0xfd, 0xd1, 0xf0, 0x61, 0x34, 0xd0, 0xef, 0x19, 0x30, 0x97, 0xb4, 0x0c, - 0xe7, 0x0b, 0x69, 0xbc, 0xc1, 0xc4, 0x96, 0x16, 0x9f, 0x11, 0x89, 0x9b, 0x42, 0xa2, 0x10, 0xe8, - 0x65, 0x03, 0x26, 0x2c, 0xed, 0x72, 0x38, 0x0f, 0x4c, 0xaa, 0x4b, 0xc3, 0x9a, 0x28, 0x42, 0x8a, - 0xe5, 0x99, 0x83, 0x6e, 0x31, 0x72, 0x01, 0xc5, 0x11, 0x8e, 0xe8, 0xf7, 0x0d, 0x38, 0x9d, 0xb8, - 0xc6, 0xe7, 0xc7, 0x4f, 0xa2, 0x87, 0xd8, 0x24, 0x49, 0xde, 0x73, 0x92, 0xc5, 0x40, 0xaf, 0x1b, - 0x4a, 0x95, 0xad, 0x4b, 0x23, 0xd1, 0x04, 0x13, 0xed, 0xea, 0x90, 0xf7, 0xe1, 0xf0, 0x40, 0x20, - 0x09, 0x97, 0x4f, 0x69, 0x9a, 0x51, 0x16, 0xe2, 0x38, 0x7b, 0xf4, 0x39, 0x43, 0xaa, 0x46, 0x25, - 0xd1, 0xe4, 0x49, 0x49, 0x84, 0x42, 0x4d, 0xab, 0x04, 0x8a, 0x31, 0x47, 0x1f, 0x86, 0x05, 0x6b, - 0xd3, 0xf5, 0x82, 0xc4, 0xc5, 0x37, 0x3f, 0xc5, 0x96, 0xd1, 0xb9, 0x83, 0x6e, 0x71, 0xa1, 0xd4, - 0x17, 0x0b, 0x1f, 0x42, 0xc1, 0xfc, 0x6a, 0x0e, 0x26, 0xf8, 0x21, 0x5f, 0xa8, 0xae, 0xaf, 0x1b, - 0x70, 0x7f, 0xad, 0xe3, 0x79, 0xc4, 0x09, 0xaa, 0x01, 0x69, 0xf7, 0x2a, 0x2e, 0xe3, 0x44, 0x15, - 0xd7, 0x03, 0x07, 0xdd, 0xe2, 0xfd, 0xcb, 0x87, 0xf0, 0xc7, 0x87, 0x4a, 0x87, 0xfe, 0xd6, 0x00, - 0x53, 0x20, 0x94, 0xad, 0xda, 0x4e, 0xc3, 0x73, 0x3b, 0x4e, 0xbd, 0xb7, 0x11, 0x99, 0x13, 0x6d, - 0xc4, 0x43, 0x07, 0xdd, 0xa2, 0xb9, 0x7c, 0x47, 0x29, 0xf0, 0x00, 0x92, 0xa2, 0x67, 0x61, 0x56, - 0x60, 0x9d, 0xbf, 0xd5, 0x26, 0x9e, 0x4d, 0x8f, 0xd3, 0xc2, 0x4d, 0x20, 0xf4, 0xbc, 0x88, 0x23, - 0xe0, 0xde, 0x3a, 0xc8, 0x87, 0xb1, 0x3d, 0x62, 0x37, 0xb6, 0x03, 0x79, 0x7c, 0x1a, 0xd2, 0xdd, - 0x42, 0x5c, 0xf8, 0x6f, 0x70, 0x9a, 0xe5, 0xf1, 0x83, 0x6e, 0x71, 0x4c, 0xfc, 0xc1, 0x92, 0x13, - 0xba, 0x0c, 0x53, 0xfc, 0x0a, 0x56, 0xb1, 0x9d, 0x46, 0xc5, 0x75, 0xb8, 0x93, 0x42, 0xa1, 0xfc, - 0x90, 0x54, 0xf8, 0xd5, 0x08, 0xf4, 0x76, 0xb7, 0x38, 0x21, 0x7f, 0x6f, 0xec, 0xb7, 0x09, 0x8e, - 0xd5, 0x36, 0xbf, 0x3d, 0x0a, 0x20, 0xa7, 0x2b, 0x69, 0xa3, 0xff, 0x03, 0x05, 0x9f, 0x04, 0x9c, - 0xab, 0x78, 0x13, 0xe0, 0x4f, 0x2d, 0xb2, 0x10, 0x87, 0x70, 0xb4, 0x03, 0xb9, 0xb6, 0xd5, 0xf1, - 0x89, 0x18, 0xfc, 0x4b, 0xa9, 0x0c, 0x7e, 0x85, 0x52, 0xe4, 0x77, 0x2e, 0xf6, 0x13, 0x73, 0x1e, - 0xe8, 0xd3, 0x06, 0x00, 0x89, 0x0e, 0xd8, 0xd0, 0xb6, 0x0f, 0xc1, 0x32, 0x1c, 0x53, 0xda, 0x07, - 0xe5, 0xa9, 0x83, 0x6e, 0x11, 0xb4, 0xa1, 0xd7, 0xd8, 0xa2, 0x3d, 0xc8, 0x5b, 0x72, 0xcf, 0x1f, - 0x39, 0x89, 0x3d, 0x9f, 0x5d, 0x85, 0xd4, 0xa4, 0x55, 0xcc, 0xd0, 0x67, 0x0c, 0x98, 0xf2, 0x49, - 0x20, 0x86, 0x8a, 0xee, 0x3c, 0xe2, 0xc0, 0x3b, 0xe4, 0xa4, 0xab, 0x46, 0x68, 0xf2, 0x1d, 0x34, - 0x5a, 0x86, 0x63, 0x7c, 0xa5, 0x28, 0x17, 0x89, 0x55, 0x27, 0x1e, 0xbb, 0x69, 0x8b, 0x93, 0xd4, - 0xf0, 0xa2, 0x68, 0x34, 0x95, 0x28, 0x5a, 0x19, 0x8e, 0xf1, 0x95, 0xa2, 0xac, 0xdb, 0x9e, 0xe7, - 0x0a, 0x51, 0xf2, 0x29, 0x89, 0xa2, 0xd1, 0x54, 0xa2, 0x68, 0x65, 0x38, 0xc6, 0xd7, 0xfc, 0xf2, - 0x24, 0x4c, 0xc9, 0x85, 0x14, 0x9e, 0xec, 0xb9, 0x61, 0xa7, 0xcf, 0xc9, 0x7e, 0x59, 0x07, 0xe2, - 0x28, 0x2e, 0xad, 0xcc, 0x97, 0x6a, 0xf4, 0x60, 0xaf, 0x2a, 0x57, 0x75, 0x20, 0x8e, 0xe2, 0xa2, - 0x16, 0xe4, 0xfc, 0x80, 0xb4, 0xe5, 0xf3, 0xee, 0x90, 0xaf, 0x8f, 0xe1, 0xfe, 0x10, 0x3e, 0xe0, - 0xd0, 0x7f, 0x3e, 0xe6, 0x5c, 0x98, 0x6d, 0x32, 0x88, 0x98, 0x2b, 0xc5, 0xe2, 0x48, 0x67, 0x7d, - 0x46, 0x2d, 0xa1, 0x7c, 0x34, 0xa2, 0x65, 0x38, 0xc6, 0x3e, 0xe1, 0xb0, 0x9f, 0x3b, 0xc1, 0xc3, - 0xfe, 0xf3, 0x90, 0x6f, 0x59, 0xb7, 0xaa, 0x1d, 0xaf, 0x71, 0xfc, 0x4b, 0x85, 0xf0, 0xbc, 0xe2, - 0x54, 0xb0, 0xa2, 0x87, 0x5e, 0x31, 0xb4, 0x2d, 0x67, 0x8c, 0x11, 0xbf, 0x91, 0xee, 0x96, 0xa3, - 0x74, 0x65, 0xdf, 0xcd, 0xa7, 0xe7, 0xe8, 0x9d, 0xbf, 0xeb, 0x47, 0x6f, 0x7a, 0x8c, 0xe4, 0x0b, - 0x44, 0x1d, 0x23, 0x0b, 0x27, 0x7a, 0x8c, 0x5c, 0x8e, 0x30, 0xc3, 0x31, 0xe6, 0x4c, 0x1e, 0xbe, - 0xe6, 0x94, 0x3c, 0x70, 0xa2, 0xf2, 0x54, 0x23, 0xcc, 0x70, 0x8c, 0x79, 0xff, 0xfb, 0xe6, 0xf8, - 0xc9, 0xdc, 0x37, 0x27, 0x52, 0xb8, 0x6f, 0x1e, 0x7e, 0x14, 0x9f, 0x1c, 0xf6, 0x28, 0x8e, 0x2e, - 0x01, 0xaa, 0xef, 0x3b, 0x56, 0xcb, 0xae, 0x89, 0xcd, 0x92, 0xa9, 0xcd, 0x29, 0x66, 0x8f, 0x58, - 0x10, 0x1b, 0x19, 0x5a, 0xe9, 0xc1, 0xc0, 0x09, 0xb5, 0x50, 0x00, 0xf9, 0xb6, 0x3c, 0x71, 0x4d, - 0xa7, 0x31, 0xfb, 0xe5, 0x09, 0x8c, 0x7b, 0x00, 0xd0, 0x85, 0x27, 0x4b, 0xb0, 0xe2, 0x84, 0xd6, - 0x60, 0xae, 0x65, 0x3b, 0x15, 0xb7, 0xee, 0x57, 0x88, 0x27, 0xac, 0x2d, 0x55, 0x12, 0xcc, 0xcf, - 0xb0, 0xbe, 0x61, 0x37, 0xe8, 0xf5, 0x04, 0x38, 0x4e, 0xac, 0x65, 0xfe, 0x87, 0x01, 0x33, 0xcb, - 0x4d, 0xb7, 0x53, 0xbf, 0x61, 0x05, 0xb5, 0x6d, 0xfe, 0xf8, 0x8d, 0x9e, 0x81, 0xbc, 0xed, 0x04, - 0xc4, 0xdb, 0xb5, 0x9a, 0x42, 0x3f, 0x99, 0xd2, 0x3f, 0x60, 0x55, 0x94, 0xdf, 0xee, 0x16, 0xa7, - 0x56, 0x3a, 0x1e, 0xf3, 0x2a, 0xe5, 0xbb, 0x15, 0x56, 0x75, 0xd0, 0x97, 0x0d, 0x98, 0xe5, 0xcf, - 0xe7, 0x2b, 0x56, 0x60, 0x5d, 0xed, 0x10, 0xcf, 0x26, 0xf2, 0x01, 0x7d, 0xc8, 0x8d, 0x2a, 0x2e, - 0xab, 0x64, 0xb0, 0x1f, 0x1e, 0xd4, 0xd7, 0xe3, 0x9c, 0x71, 0xaf, 0x30, 0xe6, 0x17, 0xb2, 0x70, - 0x6f, 0x5f, 0x5a, 0x68, 0x01, 0x32, 0x76, 0x5d, 0x34, 0x1d, 0x04, 0xdd, 0xcc, 0x6a, 0x1d, 0x67, - 0xec, 0x3a, 0x5a, 0x64, 0x67, 0x4e, 0x8f, 0xf8, 0xbe, 0x7c, 0x4b, 0x2d, 0xa8, 0xe3, 0xa1, 0x28, - 0xc5, 0x1a, 0x06, 0x2a, 0x42, 0xae, 0x69, 0x6d, 0x92, 0xa6, 0xb8, 0x4f, 0xb0, 0x53, 0xec, 0x1a, - 0x2d, 0xc0, 0xbc, 0x1c, 0x7d, 0xca, 0x00, 0xe0, 0x02, 0xd2, 0xdb, 0x88, 0xd0, 0x92, 0x38, 0xdd, - 0x6e, 0xa2, 0x94, 0xb9, 0x94, 0xe1, 0x7f, 0xac, 0x71, 0x45, 0x1b, 0x30, 0x4a, 0x0f, 0xb4, 0x6e, - 0xfd, 0xd8, 0x4a, 0x91, 0x3d, 0xb2, 0x54, 0x18, 0x0d, 0x2c, 0x68, 0xd1, 0xbe, 0xf2, 0x48, 0xd0, - 0xf1, 0x1c, 0xda, 0xb5, 0x4c, 0x0d, 0xe6, 0xb9, 0x14, 0x58, 0x95, 0x62, 0x0d, 0xc3, 0xfc, 0xf3, - 0x0c, 0xcc, 0x25, 0x89, 0x4e, 0xb5, 0xcd, 0x28, 0x97, 0x56, 0x5c, 0x8d, 0xdf, 0x9f, 0x7e, 0xff, - 0x08, 0x4f, 0x10, 0xe5, 0x2f, 0x21, 0x7c, 0xd5, 0x04, 0x5f, 0xf4, 0x7e, 0xd5, 0x43, 0x99, 0x63, - 0xf6, 0x90, 0xa2, 0x1c, 0xeb, 0xa5, 0x07, 0x60, 0xc4, 0xa7, 0x23, 0x9f, 0x8d, 0x3e, 0x60, 0xb0, - 0x31, 0x62, 0x10, 0x8a, 0xd1, 0x71, 0xec, 0x40, 0xb8, 0x7a, 0x2b, 0x8c, 0x6b, 0x8e, 0x1d, 0x60, - 0x06, 0x31, 0xbf, 0x94, 0x81, 0x85, 0xfe, 0x8d, 0x42, 0x5f, 0x32, 0x00, 0xea, 0xf4, 0xba, 0x42, - 0xa7, 0xa4, 0xf4, 0x9c, 0xb1, 0x4e, 0xaa, 0x0f, 0x57, 0x24, 0xa7, 0xd0, 0x8d, 0x4a, 0x15, 0xf9, - 0x58, 0x13, 0x04, 0x3d, 0x2a, 0xa7, 0xfe, 0x65, 0xab, 0x25, 0x8f, 0xb3, 0xaa, 0xce, 0xba, 0x82, - 0x60, 0x0d, 0x8b, 0xde, 0x47, 0x1d, 0xab, 0x45, 0xfc, 0xb6, 0xa5, 0x7c, 0xf9, 0xd9, 0x7d, 0xf4, - 0xb2, 0x2c, 0xc4, 0x21, 0xdc, 0x6c, 0xc2, 0x83, 0x03, 0xc8, 0x99, 0x92, 0x5f, 0xb5, 0xf9, 0xef, - 0x06, 0x9c, 0x59, 0x6e, 0x76, 0xfc, 0x80, 0x78, 0xff, 0x63, 0xbc, 0xd2, 0xfe, 0xd3, 0x80, 0xfb, - 0xfa, 0xb4, 0xf9, 0x2e, 0x38, 0xa7, 0xbd, 0x18, 0x75, 0x4e, 0xbb, 0x36, 0xec, 0x94, 0x4e, 0x6c, - 0x47, 0x1f, 0x1f, 0xb5, 0x00, 0x26, 0xe9, 0xae, 0x55, 0x77, 0x1b, 0x29, 0xe9, 0xcd, 0x07, 0x21, - 0xf7, 0x31, 0xaa, 0x7f, 0xe2, 0x73, 0x8c, 0x29, 0x25, 0xcc, 0x61, 0xe6, 0xd3, 0x20, 0x3c, 0xb9, - 0x62, 0x8b, 0xc7, 0x18, 0x64, 0xf1, 0x98, 0x7f, 0x9f, 0x01, 0xcd, 0x8e, 0x71, 0x17, 0x26, 0xa5, - 0x13, 0x99, 0x94, 0x43, 0xde, 0xc1, 0x35, 0xab, 0x4c, 0xbf, 0x90, 0x8d, 0xdd, 0x58, 0xc8, 0xc6, - 0xe5, 0xd4, 0x38, 0x1e, 0x1e, 0xb1, 0xf1, 0x03, 0x03, 0xee, 0x0b, 0x91, 0x7b, 0x4d, 0x8c, 0x77, - 0xde, 0x61, 0x9e, 0x80, 0x71, 0x2b, 0xac, 0x26, 0xe6, 0x80, 0x8a, 0x52, 0xd2, 0x28, 0x62, 0x1d, - 0x2f, 0x74, 0x10, 0xcf, 0x1e, 0xd3, 0x41, 0x7c, 0xe4, 0x70, 0x07, 0x71, 0xf3, 0xe7, 0x19, 0x38, - 0xdb, 0xdb, 0x32, 0xb9, 0x36, 0x06, 0x7b, 0x81, 0x7f, 0x12, 0x26, 0x02, 0x51, 0x41, 0xdb, 0xe9, - 0x55, 0x8c, 0xdd, 0x86, 0x06, 0xc3, 0x11, 0x4c, 0x5a, 0xb3, 0xc6, 0x57, 0x65, 0xb5, 0xe6, 0xb6, - 0x65, 0x78, 0x81, 0xaa, 0xb9, 0xac, 0xc1, 0x70, 0x04, 0x53, 0x39, 0x6e, 0x8e, 0x9c, 0xb8, 0xe3, - 0x66, 0x15, 0x4e, 0x4b, 0x57, 0xb5, 0x0b, 0xae, 0xb7, 0xec, 0xb6, 0xda, 0x4d, 0x22, 0x02, 0x0c, - 0xa8, 0xb0, 0x67, 0x45, 0x95, 0xd3, 0x38, 0x09, 0x09, 0x27, 0xd7, 0x35, 0x7f, 0x90, 0x85, 0x53, - 0x61, 0xb7, 0x2f, 0xbb, 0x4e, 0xdd, 0x66, 0x0e, 0x7f, 0x4f, 0xc1, 0x48, 0xb0, 0xdf, 0x96, 0x9d, - 0xfd, 0xbf, 0xa4, 0x38, 0x1b, 0xfb, 0x6d, 0x3a, 0xda, 0x67, 0x12, 0xaa, 0x30, 0x23, 0x2f, 0xab, - 0x84, 0xd6, 0xd4, 0xea, 0xe0, 0x23, 0xf0, 0x78, 0x74, 0x36, 0xdf, 0xee, 0x16, 0x13, 0x42, 0x4c, - 0x17, 0x15, 0xa5, 0xe8, 0x9c, 0x47, 0x37, 0x61, 0xaa, 0x69, 0xf9, 0xc1, 0xb5, 0x76, 0xdd, 0x0a, - 0xc8, 0x86, 0xdd, 0x22, 0x62, 0xcd, 0x1d, 0xc5, 0x6b, 0x5f, 0xbd, 0x4a, 0xaf, 0x45, 0x28, 0xe1, - 0x18, 0x65, 0xb4, 0x0b, 0x88, 0x96, 0x6c, 0x78, 0x96, 0xe3, 0xf3, 0x56, 0x51, 0x7e, 0x47, 0x8f, - 0x12, 0x50, 0x97, 0xbc, 0xb5, 0x1e, 0x6a, 0x38, 0x81, 0x03, 0x7a, 0x08, 0x46, 0x3d, 0x62, 0xf9, - 0x62, 0x30, 0x0b, 0xe1, 0xfa, 0xc7, 0xac, 0x14, 0x0b, 0xa8, 0xbe, 0xa0, 0x46, 0xef, 0xb0, 0xa0, - 0x7e, 0x62, 0xc0, 0x54, 0x38, 0x4c, 0x77, 0x41, 0x49, 0xb6, 0xa2, 0x4a, 0xf2, 0x62, 0x5a, 0x5b, - 0x62, 0x1f, 0xbd, 0xf8, 0xd7, 0xa3, 0x7a, 0xfb, 0x98, 0xd7, 0xf6, 0xc7, 0xa1, 0x20, 0x57, 0xb5, - 0x3c, 0x7d, 0x0e, 0x79, 0x57, 0x8e, 0x9c, 0x4b, 0xb4, 0x68, 0x23, 0xc1, 0x04, 0x87, 0xfc, 0xa8, - 0x5a, 0xae, 0x0b, 0x95, 0x2b, 0xa6, 0xbd, 0x52, 0xcb, 0x52, 0x15, 0x27, 0xa9, 0x65, 0x59, 0x07, - 0x5d, 0x83, 0x33, 0x6d, 0xcf, 0x65, 0x11, 0xa8, 0x2b, 0xc4, 0xaa, 0x37, 0x6d, 0x87, 0x48, 0x83, - 0x04, 0x77, 0x8a, 0xb8, 0xef, 0xa0, 0x5b, 0x3c, 0x53, 0x49, 0x46, 0xc1, 0xfd, 0xea, 0x46, 0xa3, - 0xa6, 0x46, 0x06, 0x88, 0x9a, 0xfa, 0x0d, 0x65, 0xf6, 0x23, 0xbe, 0x88, 0x5d, 0xfa, 0x60, 0x5a, - 0x43, 0x99, 0xb0, 0xad, 0x87, 0x53, 0xaa, 0x24, 0x98, 0x62, 0xc5, 0xbe, 0xbf, 0x6d, 0x69, 0xf4, - 0x98, 0xb6, 0xa5, 0xd0, 0xf9, 0x7d, 0xec, 0x97, 0xe9, 0xfc, 0x9e, 0x7f, 0x4b, 0x39, 0xbf, 0xbf, - 0x9a, 0x83, 0x99, 0xf8, 0x09, 0xe4, 0xe4, 0x23, 0xc2, 0x7e, 0xdb, 0x80, 0x19, 0xb9, 0x7a, 0x38, - 0x4f, 0x22, 0x5f, 0x0d, 0xd6, 0x52, 0x5a, 0xb4, 0xfc, 0x2c, 0xa5, 0x62, 0x96, 0x37, 0x62, 0xdc, - 0x70, 0x0f, 0x7f, 0xf4, 0x02, 0x8c, 0x2b, 0xe3, 0xfa, 0xb1, 0xc2, 0xc3, 0xa6, 0xd9, 0x29, 0x2a, - 0x24, 0x81, 0x75, 0x7a, 0xe8, 0x55, 0x03, 0xa0, 0x26, 0xd5, 0x9c, 0x5c, 0x5d, 0x57, 0xd3, 0x5a, - 0x5d, 0x4a, 0x81, 0x86, 0x87, 0x65, 0x55, 0xe4, 0x63, 0x8d, 0x31, 0xfa, 0x02, 0x33, 0xab, 0xab, - 0xd3, 0x1d, 0x5d, 0x4f, 0xd9, 0xe1, 0x1d, 0x7b, 0x0f, 0x39, 0x98, 0x86, 0x47, 0x29, 0x0d, 0xe4, - 0xe3, 0x88, 0x10, 0xe6, 0x53, 0xa0, 0x5c, 0x31, 0xe9, 0xb6, 0xc5, 0x9c, 0x31, 0x2b, 0x56, 0xb0, - 0x2d, 0xa6, 0xa0, 0xda, 0xb6, 0x2e, 0x48, 0x00, 0x0e, 0x71, 0xcc, 0x8f, 0xc2, 0xd4, 0xb3, 0x9e, - 0xd5, 0xde, 0xb6, 0x99, 0xf9, 0x9a, 0xde, 0x93, 0xde, 0x09, 0x63, 0x56, 0xbd, 0x9e, 0x14, 0xf1, - 0x5f, 0xe2, 0xc5, 0x58, 0xc2, 0x07, 0xbb, 0x12, 0x7d, 0xdb, 0x00, 0x14, 0x3e, 0x01, 0xda, 0x4e, - 0x63, 0x9d, 0xde, 0xf6, 0xe9, 0xfd, 0x68, 0x9b, 0x95, 0x26, 0xdd, 0x8f, 0x2e, 0x2a, 0x08, 0xd6, - 0xb0, 0xd0, 0x4b, 0x30, 0xce, 0xff, 0x5d, 0x57, 0x97, 0xfd, 0xa1, 0xdd, 0xfb, 0xb9, 0x42, 0x61, - 0x32, 0xf1, 0x59, 0x78, 0x31, 0xe4, 0x80, 0x75, 0x76, 0xb4, 0xab, 0x56, 0x9d, 0xad, 0x66, 0xe7, - 0x56, 0x7d, 0x33, 0xec, 0xaa, 0xb6, 0xe7, 0x6e, 0xd9, 0x4d, 0x12, 0xef, 0xaa, 0x0a, 0x2f, 0xc6, - 0x12, 0x3e, 0x58, 0x57, 0x7d, 0xd3, 0x80, 0xb9, 0x55, 0x3f, 0xb0, 0xdd, 0x15, 0xe2, 0x07, 0x54, - 0xad, 0xd0, 0xcd, 0xa7, 0xd3, 0x1c, 0xc4, 0xab, 0x7a, 0x05, 0x66, 0xc4, 0x73, 0x64, 0x67, 0xd3, - 0x27, 0x81, 0x76, 0x8e, 0x57, 0xeb, 0x78, 0x39, 0x06, 0xc7, 0x3d, 0x35, 0x28, 0x15, 0xf1, 0x2e, - 0x19, 0x52, 0xc9, 0x46, 0xa9, 0x54, 0x63, 0x70, 0xdc, 0x53, 0xc3, 0xfc, 0x5e, 0x16, 0x4e, 0xb1, - 0x66, 0xc4, 0x22, 0x22, 0x3e, 0xd7, 0x2f, 0x22, 0x62, 0xc8, 0xa5, 0xcc, 0x78, 0x1d, 0x23, 0x1e, - 0xe2, 0xb7, 0x0c, 0x98, 0xae, 0x47, 0x7b, 0x3a, 0x1d, 0xf3, 0x4c, 0xd2, 0x18, 0x72, 0xef, 0xab, - 0x58, 0x21, 0x8e, 0xf3, 0x47, 0x5f, 0x34, 0x60, 0x3a, 0x2a, 0xa6, 0xdc, 0xdd, 0x4f, 0xa0, 0x93, - 0x94, 0xbb, 0x74, 0xb4, 0xdc, 0xc7, 0x71, 0x11, 0xcc, 0xef, 0x66, 0xc4, 0x90, 0x9e, 0x84, 0xbb, - 0x3f, 0xda, 0x83, 0x42, 0xd0, 0xf4, 0x79, 0xa1, 0x68, 0xed, 0x90, 0x37, 0xc2, 0x8d, 0xb5, 0x2a, - 0xf7, 0x04, 0x08, 0x0f, 0x6d, 0xa2, 0x84, 0x1e, 0x3e, 0x25, 0x2f, 0xc6, 0xb8, 0xd6, 0x16, 0x8c, - 0x53, 0xb9, 0x8a, 0x6e, 0x2c, 0x57, 0xe2, 0x8c, 0x45, 0x09, 0x65, 0x2c, 0x79, 0x99, 0x5f, 0x31, - 0xa0, 0x70, 0xc9, 0x95, 0xfb, 0xc8, 0x87, 0x53, 0x30, 0xf4, 0xa8, 0xf3, 0xa0, 0x7a, 0x71, 0x0c, - 0xaf, 0x18, 0xcf, 0x44, 0xcc, 0x3c, 0xf7, 0x6b, 0xb4, 0x17, 0x59, 0x36, 0x23, 0x4a, 0xea, 0x92, - 0xbb, 0xd9, 0xd7, 0x8a, 0xf8, 0x07, 0x39, 0x98, 0x7c, 0xce, 0xda, 0x27, 0x4e, 0x60, 0x1d, 0x5d, - 0x49, 0x3c, 0x01, 0xe3, 0x56, 0x9b, 0x3d, 0x69, 0x69, 0x67, 0xfc, 0xd0, 0x72, 0x12, 0x82, 0xb0, - 0x8e, 0x17, 0x6e, 0x68, 0x3c, 0xb9, 0x4a, 0xd2, 0x56, 0xb4, 0x1c, 0x83, 0xe3, 0x9e, 0x1a, 0xe8, - 0x12, 0x20, 0x11, 0x2a, 0x5a, 0xaa, 0xd5, 0xdc, 0x8e, 0xc3, 0xb7, 0x34, 0x6e, 0x54, 0x51, 0x97, - 0xcd, 0xf5, 0x1e, 0x0c, 0x9c, 0x50, 0x0b, 0x7d, 0x08, 0xe6, 0x6b, 0x8c, 0xb2, 0xb8, 0x7a, 0xe8, - 0x14, 0xf9, 0xf5, 0x53, 0xb9, 0xfc, 0x2f, 0xf7, 0xc1, 0xc3, 0x7d, 0x29, 0x50, 0x49, 0xfd, 0xc0, - 0xf5, 0xac, 0x06, 0xd1, 0xe9, 0x8e, 0x46, 0x25, 0xad, 0xf6, 0x60, 0xe0, 0x84, 0x5a, 0xe8, 0x93, - 0x50, 0x08, 0xb6, 0x3d, 0xe2, 0x6f, 0xbb, 0xcd, 0xba, 0x70, 0x41, 0x18, 0xd2, 0xd2, 0x26, 0x46, - 0x7f, 0x43, 0x52, 0xd5, 0xa6, 0xb7, 0x2c, 0xc2, 0x21, 0x4f, 0xe4, 0xc1, 0xa8, 0x5f, 0x73, 0xdb, - 0xc4, 0x17, 0x47, 0xf6, 0x4b, 0xa9, 0x70, 0x67, 0x96, 0x23, 0xcd, 0xc6, 0xc7, 0x38, 0x60, 0xc1, - 0xc9, 0xfc, 0x56, 0x06, 0x26, 0x74, 0xc4, 0x01, 0xf6, 0xa6, 0x4f, 0x1b, 0x30, 0x51, 0x73, 0x9d, - 0xc0, 0x73, 0x9b, 0xdc, 0x7e, 0x95, 0xce, 0x89, 0x82, 0x92, 0x5a, 0x21, 0x81, 0x65, 0x37, 0x35, - 0x53, 0x98, 0xc6, 0x06, 0x47, 0x98, 0xa2, 0xcf, 0x1a, 0x30, 0x1d, 0x7a, 0xac, 0x85, 0x86, 0xb4, - 0x54, 0x05, 0x51, 0x5b, 0xfd, 0xf9, 0x28, 0x27, 0x1c, 0x67, 0x6d, 0x6e, 0xc2, 0x4c, 0x7c, 0xb4, - 0x69, 0x57, 0xb6, 0x2d, 0xb1, 0xd6, 0xb3, 0x61, 0x57, 0x56, 0x2c, 0xdf, 0xc7, 0x0c, 0x82, 0x1e, - 0x81, 0x7c, 0xcb, 0xf2, 0x1a, 0xb6, 0x63, 0x35, 0x59, 0x2f, 0x66, 0xb5, 0x0d, 0x49, 0x94, 0x63, - 0x85, 0x61, 0xbe, 0x1b, 0x26, 0xd6, 0x2d, 0xa7, 0x41, 0xea, 0x62, 0x1f, 0xbe, 0x73, 0xc0, 0xd9, - 0x4f, 0x47, 0x60, 0x5c, 0xbb, 0x9b, 0x9d, 0xfc, 0x3d, 0x2b, 0x92, 0xef, 0x22, 0x9b, 0x62, 0xbe, - 0x8b, 0xe7, 0x01, 0xb6, 0x6c, 0xc7, 0xf6, 0xb7, 0x8f, 0x99, 0x49, 0x83, 0x3d, 0xd1, 0x5e, 0x50, - 0x14, 0xb0, 0x46, 0x2d, 0x7c, 0x07, 0xcb, 0x1d, 0x92, 0x5f, 0xe8, 0x55, 0x43, 0x53, 0x37, 0xa3, - 0x69, 0xbc, 0xfb, 0x6b, 0x03, 0xb3, 0x28, 0xd5, 0xcf, 0x79, 0x27, 0xf0, 0xf6, 0x0f, 0xd5, 0x4a, - 0x1b, 0x90, 0xf7, 0x88, 0xdf, 0x69, 0xd1, 0x1b, 0xe3, 0xd8, 0x91, 0xbb, 0x81, 0x79, 0x60, 0x60, - 0x51, 0x1f, 0x2b, 0x4a, 0x0b, 0x4f, 0xc1, 0x64, 0x44, 0x04, 0x34, 0x03, 0xd9, 0x1d, 0xb2, 0xcf, - 0xe7, 0x09, 0xa6, 0x3f, 0xd1, 0x5c, 0xe4, 0xb5, 0x50, 0x74, 0xcb, 0xfb, 0x32, 0x4f, 0x1a, 0xa6, - 0x0b, 0x89, 0x06, 0x80, 0xe3, 0x3c, 0xe6, 0xd0, 0xb1, 0x68, 0x6a, 0xa9, 0x34, 0xd4, 0x58, 0x70, - 0x3f, 0x1b, 0x0e, 0x33, 0x7f, 0x3e, 0x0a, 0xe2, 0x29, 0x7b, 0x80, 0xed, 0x4a, 0x7f, 0xc1, 0xca, - 0x1c, 0xe3, 0x05, 0xeb, 0x12, 0x4c, 0xd8, 0x8e, 0x1d, 0xd8, 0x56, 0x93, 0x19, 0x77, 0x84, 0x3a, - 0x95, 0x8e, 0xc8, 0x13, 0xab, 0x1a, 0x2c, 0x81, 0x4e, 0xa4, 0x2e, 0xba, 0x0a, 0x39, 0xa6, 0x6f, - 0xc4, 0x04, 0x3e, 0xfa, 0x7b, 0x3b, 0x73, 0xb5, 0xe0, 0xd1, 0x49, 0x9c, 0x12, 0xbb, 0x7c, 0xf0, - 0x5c, 0x22, 0xea, 0xfa, 0x2d, 0xe6, 0x71, 0x78, 0xf9, 0x88, 0xc1, 0x71, 0x4f, 0x0d, 0x4a, 0x65, - 0xcb, 0xb2, 0x9b, 0x1d, 0x8f, 0x84, 0x54, 0x46, 0xa3, 0x54, 0x2e, 0xc4, 0xe0, 0xb8, 0xa7, 0x06, - 0xda, 0x82, 0x09, 0x51, 0xc6, 0xbd, 0xa7, 0xc6, 0x8e, 0xd9, 0x4a, 0xe6, 0x25, 0x77, 0x41, 0xa3, - 0x84, 0x23, 0x74, 0x51, 0x07, 0x66, 0x6d, 0xa7, 0xe6, 0x3a, 0xb5, 0x66, 0xc7, 0xb7, 0x77, 0x49, - 0x18, 0x1a, 0x74, 0x1c, 0x66, 0xa7, 0x0f, 0xba, 0xc5, 0xd9, 0xd5, 0x38, 0x39, 0xdc, 0xcb, 0x01, - 0xbd, 0x62, 0xc0, 0xe9, 0x9a, 0xeb, 0xf8, 0x2c, 0x38, 0x7f, 0x97, 0x9c, 0xf7, 0x3c, 0xd7, 0xe3, - 0xbc, 0x0b, 0xc7, 0xe4, 0xcd, 0x6c, 0x8a, 0xcb, 0x49, 0x24, 0x71, 0x32, 0x27, 0xf4, 0x22, 0xe4, - 0xdb, 0x9e, 0xbb, 0x6b, 0xd7, 0x89, 0x27, 0x3c, 0xf1, 0xd6, 0xd2, 0x48, 0x16, 0x52, 0x11, 0x34, - 0xc3, 0xad, 0x47, 0x96, 0x60, 0xc5, 0xcf, 0x7c, 0xa3, 0x00, 0x53, 0x51, 0x74, 0xf4, 0x09, 0x80, - 0xb6, 0xe7, 0xb6, 0x48, 0xb0, 0x4d, 0x54, 0x88, 0xc7, 0xe5, 0x61, 0x73, 0x52, 0x48, 0x7a, 0xd2, - 0x7b, 0x85, 0x6e, 0x17, 0x61, 0x29, 0xd6, 0x38, 0x22, 0x0f, 0xc6, 0x76, 0xb8, 0xda, 0x15, 0xa7, - 0x90, 0xe7, 0x52, 0x39, 0x33, 0x09, 0xce, 0x2c, 0x36, 0x41, 0x14, 0x61, 0xc9, 0x08, 0x6d, 0x42, - 0x76, 0x8f, 0x6c, 0xa6, 0x13, 0x10, 0x7d, 0x83, 0x88, 0xdb, 0x4c, 0x79, 0xec, 0xa0, 0x5b, 0xcc, - 0xde, 0x20, 0x9b, 0x98, 0x12, 0xa7, 0xed, 0xaa, 0xf3, 0x77, 0x78, 0xb1, 0x55, 0x0c, 0xd9, 0xae, - 0xc8, 0xa3, 0x3e, 0x6f, 0x97, 0x28, 0xc2, 0x92, 0x11, 0x7a, 0x11, 0x0a, 0x7b, 0xd6, 0x2e, 0xd9, - 0xf2, 0x5c, 0x27, 0x10, 0x2e, 0x53, 0x43, 0x7a, 0xfd, 0xdf, 0x90, 0xe4, 0x04, 0x5f, 0xa6, 0xde, - 0x55, 0x21, 0x0e, 0xd9, 0xa1, 0x5d, 0xc8, 0x3b, 0x64, 0x0f, 0x93, 0xa6, 0x5d, 0x4b, 0xc7, 0xcb, - 0xfe, 0xb2, 0xa0, 0x26, 0x38, 0x33, 0xbd, 0x27, 0xcb, 0xb0, 0xe2, 0x45, 0xc7, 0xf2, 0xa6, 0xbb, - 0x29, 0x36, 0xaa, 0x21, 0xc7, 0x52, 0xdd, 0x4c, 0xf9, 0x58, 0x5e, 0x72, 0x37, 0x31, 0x25, 0x4e, - 0xd7, 0x48, 0x4d, 0xf9, 0xeb, 0x88, 0x6d, 0xea, 0x72, 0xba, 0x7e, 0x4a, 0x7c, 0x8d, 0x84, 0xa5, - 0x58, 0xe3, 0x48, 0xfb, 0xb6, 0x21, 0x8c, 0x95, 0x62, 0xa3, 0x1a, 0xb2, 0x6f, 0xa3, 0xa6, 0x4f, - 0xde, 0xb7, 0xb2, 0x0c, 0x2b, 0x5e, 0x94, 0xaf, 0x2d, 0x2c, 0x7f, 0xe9, 0x6c, 0x55, 0x51, 0x3b, - 0x22, 0xe7, 0x2b, 0xcb, 0xb0, 0xe2, 0x65, 0x7e, 0x65, 0x14, 0x26, 0xf4, 0xa4, 0x6c, 0x03, 0x9c, - 0x11, 0xd4, 0xb9, 0x38, 0x73, 0x94, 0x73, 0x31, 0xbd, 0x08, 0x69, 0x6f, 0x1c, 0xd2, 0x08, 0xb3, - 0x9a, 0xda, 0xb1, 0x30, 0xbc, 0x08, 0x69, 0x85, 0x3e, 0x8e, 0x30, 0x3d, 0x82, 0xdb, 0x03, 0x3d, - 0x5c, 0xf1, 0xe3, 0x47, 0x2e, 0x7a, 0xb8, 0x8a, 0x1c, 0x28, 0x1e, 0x05, 0x08, 0x93, 0x93, 0x89, - 0xb7, 0x2f, 0x75, 0x6a, 0xd3, 0x92, 0xa6, 0x69, 0x58, 0xe8, 0x21, 0x18, 0xa5, 0x0a, 0x9a, 0xd4, - 0x45, 0xdc, 0xaf, 0xba, 0x6d, 0x5e, 0x60, 0xa5, 0x58, 0x40, 0xd1, 0x93, 0xf4, 0x2c, 0x15, 0xaa, - 0x55, 0x11, 0xce, 0x3b, 0x17, 0x9e, 0xa5, 0x42, 0x18, 0x8e, 0x60, 0x52, 0xd1, 0x09, 0xd5, 0x82, - 0x6c, 0x06, 0x6b, 0xa2, 0x33, 0xd5, 0x88, 0x39, 0x8c, 0x59, 0x3f, 0x62, 0x5a, 0x93, 0xcd, 0xbc, - 0x9c, 0x66, 0xfd, 0x88, 0xc1, 0x71, 0x4f, 0x0d, 0xda, 0x18, 0xf1, 0x6c, 0x37, 0xce, 0xbd, 0x3b, - 0xfb, 0x3c, 0xb8, 0xbd, 0xa6, 0xdf, 0x08, 0x26, 0xd8, 0xd0, 0xbf, 0x3f, 0xbd, 0x04, 0x83, 0x83, - 0x5f, 0x09, 0x86, 0x3b, 0xbc, 0x7f, 0x14, 0xa6, 0xa2, 0x7b, 0x65, 0xea, 0xf6, 0xf9, 0xbf, 0xc9, - 0xc2, 0xa9, 0xcb, 0x0d, 0xdb, 0x89, 0x27, 0x1c, 0x4a, 0x4a, 0xfc, 0x6b, 0x1c, 0x35, 0xf1, 0x6f, - 0x18, 0x40, 0x24, 0x32, 0x2b, 0x27, 0x07, 0x10, 0xc9, 0xb4, 0xcb, 0x51, 0x5c, 0xf4, 0x13, 0x03, - 0xee, 0xb7, 0xea, 0xfc, 0xf4, 0x6a, 0x35, 0x45, 0x69, 0xc8, 0x54, 0xae, 0x68, 0x7f, 0x48, 0x5d, - 0xd4, 0xdb, 0xf8, 0xc5, 0xd2, 0x21, 0x5c, 0xf9, 0x88, 0xbf, 0x43, 0xb4, 0xe0, 0xfe, 0xc3, 0x50, - 0xf1, 0xa1, 0xe2, 0x2f, 0x5c, 0x81, 0xb7, 0xdf, 0x91, 0xd1, 0x91, 0x66, 0xcb, 0xa7, 0x0d, 0x28, - 0x70, 0xf3, 0x29, 0x26, 0x5b, 0x74, 0xab, 0xb0, 0xda, 0xf6, 0x75, 0xe2, 0xf9, 0x32, 0x23, 0x99, - 0x76, 0xc1, 0x2b, 0x55, 0x56, 0x05, 0x04, 0x6b, 0x58, 0x74, 0x33, 0xde, 0xb1, 0x9d, 0xba, 0x18, - 0x26, 0xb5, 0x19, 0x3f, 0x67, 0x3b, 0x75, 0xcc, 0x20, 0x6a, 0xbb, 0xce, 0xf6, 0x35, 0x6b, 0xbc, - 0x61, 0xc0, 0x14, 0x8b, 0x9a, 0x0c, 0xaf, 0x1e, 0x4f, 0x28, 0x9f, 0x16, 0x2e, 0xc6, 0xd9, 0xa8, - 0x4f, 0xcb, 0xed, 0x6e, 0x71, 0x9c, 0xc7, 0x59, 0x46, 0x5d, 0x5c, 0x3e, 0x28, 0xec, 0x15, 0xcc, - 0xf3, 0x26, 0x73, 0xe4, 0xeb, 0xb4, 0xb2, 0xe7, 0x55, 0x25, 0x11, 0x1c, 0xd2, 0x33, 0x5f, 0x82, - 0x09, 0x3d, 0xfc, 0x01, 0x3d, 0x01, 0xe3, 0x6d, 0xdb, 0x69, 0x44, 0xc3, 0xe4, 0x94, 0x4d, 0xb7, - 0x12, 0x82, 0xb0, 0x8e, 0xc7, 0xaa, 0xb9, 0x61, 0xb5, 0x98, 0x29, 0xb8, 0xe2, 0xea, 0xd5, 0xc2, - 0x3f, 0xe6, 0x9f, 0x66, 0xe1, 0x54, 0x42, 0x98, 0x0d, 0x7a, 0xd5, 0x80, 0x51, 0xe6, 0xa5, 0x2f, - 0xbd, 0x56, 0x5e, 0x48, 0x3d, 0x94, 0x67, 0x91, 0x05, 0x03, 0x88, 0x79, 0xac, 0xb6, 0x4f, 0x5e, - 0x88, 0x05, 0x73, 0xf4, 0xbb, 0x06, 0x8c, 0x5b, 0xda, 0x52, 0xe3, 0x8e, 0x3c, 0x9b, 0xe9, 0x0b, - 0xd3, 0xb3, 0xb2, 0x34, 0x07, 0xc4, 0x70, 0x21, 0xe9, 0xb2, 0x2c, 0xbc, 0x17, 0xc6, 0xb5, 0x26, - 0x1c, 0x65, 0x85, 0x2c, 0x3c, 0x03, 0x33, 0x43, 0xad, 0xb0, 0x0f, 0xc0, 0x51, 0x13, 0xec, 0x51, - 0x85, 0xb5, 0xa7, 0x87, 0x32, 0xab, 0x1e, 0x17, 0xb1, 0xcc, 0x02, 0x6a, 0x6e, 0xc2, 0x4c, 0xfc, - 0x72, 0x95, 0xfa, 0xbb, 0xf5, 0xbb, 0xe1, 0x88, 0x29, 0xf1, 0xcc, 0xf3, 0x80, 0xb0, 0xdb, 0x6c, - 0x6e, 0x5a, 0xb5, 0x9d, 0x1b, 0xb6, 0x53, 0x77, 0xf7, 0xd8, 0x5a, 0x59, 0x82, 0x82, 0x27, 0xa2, - 0xa8, 0x7c, 0xd1, 0x2c, 0xb5, 0xd8, 0x64, 0x78, 0x95, 0x8f, 0x43, 0x1c, 0xf3, 0xbb, 0x19, 0x18, - 0x13, 0x21, 0x7f, 0x77, 0xc1, 0x05, 0x78, 0x27, 0xf2, 0x36, 0xb4, 0x9a, 0x4a, 0xa4, 0x62, 0x5f, - 0xff, 0x5f, 0x3f, 0xe6, 0xff, 0xfb, 0x5c, 0x3a, 0xec, 0x0e, 0x77, 0xfe, 0x7d, 0x63, 0x04, 0xa6, - 0x63, 0x21, 0x94, 0xf4, 0xc4, 0xd3, 0xe3, 0xf3, 0x76, 0x2d, 0xd5, 0x28, 0x4d, 0xe5, 0x9e, 0x7e, - 0xb8, 0xfb, 0x9b, 0x1f, 0x49, 0x60, 0x7a, 0x35, 0xb5, 0xdc, 0xe7, 0xbf, 0xca, 0x65, 0x7a, 0x54, - 0x77, 0xae, 0x7f, 0x32, 0xe0, 0xde, 0xbe, 0x91, 0xb6, 0x2c, 0x51, 0x8b, 0x17, 0x85, 0x8a, 0x05, - 0x99, 0x72, 0x3e, 0x01, 0xf5, 0x50, 0x13, 0xcf, 0xad, 0x11, 0x67, 0x8f, 0x1e, 0x87, 0x09, 0xa6, - 0xa1, 0xe9, 0xd6, 0x14, 0x90, 0xb6, 0xb0, 0x33, 0x33, 0x8b, 0x63, 0x55, 0x2b, 0xc7, 0x11, 0x2c, - 0xf3, 0xcb, 0x06, 0xcc, 0xf7, 0x4b, 0xdb, 0x31, 0xc0, 0xfd, 0xf2, 0xff, 0xc5, 0x7c, 0x94, 0x8b, - 0x3d, 0x3e, 0xca, 0xb1, 0x1b, 0xa6, 0x74, 0x47, 0xd6, 0x2e, 0x77, 0xd9, 0x3b, 0xb8, 0xe0, 0x7e, - 0xce, 0x80, 0x33, 0x7d, 0x56, 0x53, 0x8f, 0xaf, 0xba, 0x71, 0x6c, 0x5f, 0xf5, 0xcc, 0xa0, 0xbe, - 0xea, 0xe6, 0xf7, 0xb3, 0x30, 0x23, 0xe4, 0x09, 0x8f, 0x69, 0x4f, 0x46, 0x3c, 0xbd, 0xdf, 0x11, - 0xf3, 0xf4, 0x9e, 0x8b, 0xe3, 0xff, 0xca, 0xcd, 0xfb, 0xad, 0xe5, 0xe6, 0xfd, 0x8b, 0x0c, 0x9c, - 0x4e, 0xcc, 0x26, 0x82, 0x3e, 0x93, 0xa0, 0x1a, 0x6e, 0xa4, 0x9c, 0xb6, 0x64, 0x40, 0xe5, 0x30, - 0xac, 0x6f, 0xf4, 0x17, 0x75, 0x9f, 0x64, 0xbe, 0xd5, 0x6f, 0x9d, 0x40, 0x02, 0x96, 0x23, 0xba, - 0x27, 0x9b, 0xbf, 0x99, 0x85, 0x87, 0x07, 0x25, 0xf4, 0x16, 0x0d, 0x5f, 0xf1, 0x23, 0xe1, 0x2b, - 0x77, 0x49, 0x6d, 0x9f, 0x48, 0x24, 0xcb, 0x57, 0xb2, 0x4a, 0xed, 0xf5, 0xce, 0xcf, 0x81, 0x1e, - 0x25, 0xc7, 0xe8, 0xd1, 0x4e, 0xe6, 0x18, 0x0d, 0xb7, 0xc2, 0xb1, 0x2a, 0x2f, 0xbe, 0xdd, 0x2d, - 0xce, 0x86, 0x31, 0xed, 0xa2, 0x10, 0xcb, 0x4a, 0xe8, 0x61, 0xc8, 0x7b, 0x1c, 0x2a, 0x1d, 0xf6, - 0xc5, 0xcb, 0x2e, 0x2f, 0xc3, 0x0a, 0x8a, 0x3e, 0xa9, 0x9d, 0x85, 0x47, 0x4e, 0x2a, 0x75, 0xc3, - 0x61, 0x0f, 0xd6, 0x2f, 0x40, 0xde, 0x97, 0xd9, 0x42, 0xf9, 0xab, 0xc2, 0x63, 0x03, 0xc6, 0x81, - 0xd0, 0x1b, 0x98, 0x4c, 0x1d, 0xca, 0xdb, 0xa7, 0x12, 0x8b, 0x2a, 0x92, 0xc8, 0x54, 0x97, 0x1f, - 0x6e, 0xaa, 0x84, 0x84, 0x8b, 0xcf, 0x0f, 0x0c, 0x18, 0x17, 0xa3, 0x75, 0x17, 0x42, 0x53, 0x6e, - 0x46, 0x43, 0x53, 0xce, 0xa7, 0xb2, 0x77, 0xf4, 0x89, 0x4b, 0xb9, 0x09, 0x13, 0x7a, 0x42, 0x29, - 0xf4, 0xbc, 0xb6, 0xf7, 0x19, 0xc3, 0xa4, 0x68, 0x91, 0xbb, 0x63, 0xb8, 0x2f, 0x9a, 0x5f, 0x2d, - 0xa8, 0x5e, 0x64, 0x57, 0x34, 0x7d, 0x0e, 0x1a, 0x87, 0xce, 0x41, 0x7d, 0x0a, 0x64, 0xd2, 0x9f, - 0x02, 0x57, 0x21, 0x2f, 0x37, 0x28, 0xa1, 0xc6, 0x1f, 0xd4, 0x9d, 0xf5, 0xe8, 0x59, 0x80, 0x12, - 0xd3, 0x26, 0x2e, 0xbb, 0x6a, 0xa9, 0x31, 0x54, 0x1b, 0xa7, 0x22, 0x83, 0x5e, 0x84, 0xf1, 0x3d, - 0xd7, 0xdb, 0x69, 0xba, 0x16, 0xcb, 0x03, 0x0c, 0x69, 0xbc, 0x0f, 0x29, 0xbb, 0x19, 0xf7, 0x98, - 0xbe, 0x11, 0xd2, 0xc7, 0x3a, 0x33, 0x54, 0x82, 0xe9, 0x96, 0xed, 0x60, 0x62, 0xd5, 0x55, 0x04, - 0xca, 0x08, 0x4f, 0x54, 0x2a, 0x0f, 0xb9, 0xeb, 0x51, 0x30, 0x8e, 0xe3, 0xa3, 0xcf, 0x1a, 0x30, - 0xe5, 0x45, 0x2e, 0xd5, 0x22, 0x1b, 0x61, 0x65, 0xf8, 0xc9, 0x18, 0xbd, 0xa8, 0x73, 0x97, 0xe1, - 0x68, 0x39, 0x8e, 0xf1, 0x46, 0x1f, 0x87, 0xbc, 0x2f, 0xb2, 0x45, 0xa5, 0xf3, 0xb0, 0xa8, 0xae, - 0xb0, 0x9c, 0x68, 0x38, 0x94, 0xb2, 0x04, 0x2b, 0x86, 0x68, 0x0d, 0xe6, 0xa4, 0x95, 0x20, 0xf2, - 0xad, 0x96, 0xd1, 0x30, 0xb9, 0x08, 0x4e, 0x80, 0xe3, 0xc4, 0x5a, 0xf4, 0x50, 0xc5, 0x12, 0xb5, - 0xf1, 0x97, 0x0e, 0xed, 0x71, 0x80, 0xad, 0xbf, 0x3a, 0x16, 0xd0, 0xc3, 0x02, 0xac, 0xf2, 0x43, - 0x04, 0x58, 0x55, 0xe1, 0x74, 0x1c, 0xc4, 0xb2, 0xc6, 0xb0, 0x44, 0x35, 0x9a, 0x32, 0xab, 0x24, - 0x21, 0xe1, 0xe4, 0xba, 0xe8, 0x06, 0x14, 0x3c, 0xc2, 0xae, 0x3b, 0x25, 0xe9, 0xca, 0x70, 0x64, - 0xa7, 0x2d, 0x2c, 0x09, 0xe0, 0x90, 0x16, 0x1d, 0x77, 0x2b, 0x9a, 0x3a, 0xf4, 0x6a, 0x8a, 0x5f, - 0x9b, 0x13, 0x63, 0xdf, 0x27, 0x9b, 0x93, 0xf9, 0xe6, 0x14, 0x4c, 0x46, 0x4c, 0x1d, 0xe8, 0x41, - 0xc8, 0xb1, 0x34, 0x3a, 0x6c, 0xb7, 0xca, 0x87, 0x3b, 0x2a, 0xef, 0x1c, 0x0e, 0x43, 0x9f, 0x37, - 0x60, 0xba, 0x1d, 0xb1, 0x2d, 0xcb, 0x8d, 0x7c, 0xc8, 0xd7, 0xcb, 0xa8, 0xc1, 0x5a, 0x4b, 0xba, - 0x1d, 0x65, 0x86, 0xe3, 0xdc, 0xe9, 0x7e, 0x20, 0x3c, 0x1f, 0x9b, 0xc4, 0x63, 0xd8, 0xe2, 0xc8, - 0xa5, 0x48, 0x2c, 0x47, 0xc1, 0x38, 0x8e, 0x4f, 0x47, 0x98, 0xb5, 0x6e, 0x98, 0xcf, 0x50, 0x95, - 0x24, 0x01, 0x1c, 0xd2, 0x42, 0xcf, 0xc0, 0x94, 0xc8, 0x18, 0x59, 0x71, 0xeb, 0x17, 0x2d, 0x7f, - 0x5b, 0xdc, 0x35, 0xd4, 0xdd, 0x68, 0x39, 0x02, 0xc5, 0x31, 0x6c, 0xd6, 0xb6, 0x30, 0x2d, 0x27, - 0x23, 0x30, 0x1a, 0xcd, 0x49, 0xbe, 0x1c, 0x05, 0xe3, 0x38, 0x3e, 0x7a, 0x44, 0x53, 0x43, 0xfc, - 0xf5, 0x51, 0xed, 0x06, 0x09, 0xaa, 0xa8, 0x04, 0xd3, 0x1d, 0x76, 0x35, 0xab, 0x4b, 0xa0, 0x58, - 0x8f, 0x8a, 0xe1, 0xb5, 0x28, 0x18, 0xc7, 0xf1, 0xd1, 0x53, 0x30, 0xe9, 0xd1, 0xcd, 0x56, 0x11, - 0xe0, 0x4f, 0x92, 0xea, 0xc5, 0x09, 0xeb, 0x40, 0x1c, 0xc5, 0x45, 0xcf, 0xc2, 0x6c, 0x98, 0x60, - 0x4d, 0x12, 0xe0, 0x6f, 0x94, 0x2a, 0xdb, 0x4f, 0x29, 0x8e, 0x80, 0x7b, 0xeb, 0xa0, 0x5f, 0x83, - 0x19, 0xad, 0x27, 0x56, 0x9d, 0x3a, 0xb9, 0x25, 0x92, 0x60, 0xb1, 0xcf, 0x47, 0x2c, 0xc7, 0x60, - 0xb8, 0x07, 0x1b, 0xbd, 0x0f, 0xa6, 0x6a, 0x6e, 0xb3, 0xc9, 0xf6, 0x38, 0x9e, 0x0f, 0x9b, 0x67, - 0xbb, 0xe2, 0x79, 0xc1, 0x22, 0x10, 0x1c, 0xc3, 0x44, 0x97, 0x00, 0xb9, 0x9b, 0x3e, 0xf1, 0x76, - 0x49, 0xfd, 0x59, 0xfe, 0x61, 0x5b, 0x7a, 0xe2, 0x98, 0x8c, 0xfa, 0x5d, 0x5f, 0xe9, 0xc1, 0xc0, - 0x09, 0xb5, 0x58, 0xb2, 0x20, 0x2d, 0x4e, 0x6d, 0x2a, 0x8d, 0x4f, 0x32, 0xc5, 0x0d, 0x09, 0x77, - 0x0c, 0x52, 0xf3, 0x60, 0x94, 0xbb, 0xc1, 0xa7, 0x93, 0xf6, 0x4a, 0x4f, 0x8d, 0x1b, 0xea, 0x08, - 0x5e, 0x8a, 0x05, 0x27, 0xf4, 0x09, 0x28, 0x6c, 0xca, 0x3c, 0xe9, 0x2c, 0xd7, 0xd5, 0xd0, 0x7a, - 0x31, 0x96, 0xf2, 0x3f, 0xbc, 0x28, 0x2b, 0x00, 0x0e, 0x59, 0xa2, 0x87, 0x60, 0xfc, 0x62, 0xa5, - 0xa4, 0x66, 0xe1, 0x2c, 0x1b, 0xfd, 0x11, 0x5a, 0x05, 0xeb, 0x00, 0xba, 0xc2, 0xd4, 0xf1, 0x0d, - 0xb1, 0x21, 0x0e, 0xf5, 0x6d, 0xef, 0x69, 0x8c, 0x62, 0xb3, 0x47, 0x56, 0x5c, 0x9d, 0x3f, 0x15, - 0xc3, 0x16, 0xe5, 0x58, 0x61, 0xa0, 0x17, 0x60, 0x5c, 0xe8, 0x0b, 0xb6, 0x37, 0xcd, 0x1d, 0x2f, - 0x06, 0x12, 0x87, 0x24, 0xb0, 0x4e, 0x8f, 0xbd, 0x9d, 0xb1, 0xf4, 0xd1, 0xe4, 0x42, 0xa7, 0xd9, - 0x9c, 0x3f, 0xcd, 0xf6, 0xcd, 0xf0, 0xed, 0x2c, 0x04, 0x61, 0x1d, 0x0f, 0x3d, 0x26, 0xfd, 0x41, - 0xde, 0x16, 0x79, 0x4c, 0x54, 0xfe, 0x20, 0xea, 0xd0, 0xdd, 0xc7, 0x4d, 0xfa, 0xcc, 0x1d, 0x1c, - 0x31, 0x36, 0x61, 0x41, 0x9e, 0xf8, 0x7a, 0x17, 0xc9, 0xfc, 0x7c, 0xc4, 0x68, 0xb1, 0x70, 0xa3, - 0x2f, 0x26, 0x3e, 0x84, 0x0a, 0xda, 0x84, 0xac, 0xd5, 0xdc, 0x9c, 0xbf, 0x37, 0x8d, 0xa3, 0xab, - 0xfa, 0x50, 0x35, 0x77, 0x6d, 0x2a, 0xad, 0x95, 0x31, 0x25, 0x6e, 0xbe, 0x92, 0x51, 0x8f, 0x04, - 0x2a, 0x1d, 0xe8, 0x4b, 0xfa, 0xac, 0x36, 0xd2, 0xf8, 0x10, 0x6b, 0xcf, 0xc7, 0x04, 0xb8, 0x42, - 0x4a, 0x9c, 0xd3, 0x6d, 0xb5, 0x8e, 0x53, 0xc9, 0xce, 0x12, 0x4d, 0x75, 0xca, 0x2f, 0x97, 0xd1, - 0x55, 0x6c, 0xfe, 0x38, 0xaf, 0x6c, 0x62, 0x31, 0x07, 0x07, 0x0f, 0x72, 0xb6, 0x1f, 0xd8, 0x6e, - 0x8a, 0xf1, 0x7a, 0xb1, 0x1c, 0xa1, 0xcc, 0x1d, 0x98, 0x01, 0x30, 0x67, 0x45, 0x79, 0x3a, 0x0d, - 0xdb, 0xb9, 0x25, 0x9a, 0x7f, 0x35, 0x75, 0xcf, 0x05, 0xce, 0x93, 0x01, 0x30, 0x67, 0x85, 0x6e, - 0xf2, 0x99, 0x96, 0xce, 0x47, 0x77, 0xe3, 0xdf, 0xd2, 0x8e, 0xce, 0x38, 0xca, 0xcb, 0x6f, 0xd9, - 0xe2, 0x0c, 0x33, 0x24, 0xaf, 0xea, 0xfa, 0x6a, 0x12, 0xaf, 0xea, 0xfa, 0x2a, 0xa6, 0x4c, 0xd0, - 0x6b, 0x06, 0x80, 0xa5, 0x3e, 0x2a, 0x9d, 0xce, 0x97, 0x37, 0xfa, 0x7d, 0xa4, 0x9a, 0x7b, 0xf0, - 0x85, 0x50, 0xac, 0x71, 0x46, 0x2f, 0xc2, 0x98, 0xc5, 0xbf, 0x1b, 0x24, 0x9c, 0x23, 0xd3, 0xf9, - 0x18, 0x56, 0x4c, 0x02, 0xe6, 0x15, 0x2a, 0x40, 0x58, 0x32, 0xa4, 0xbc, 0x03, 0xcf, 0x22, 0x5b, - 0xf6, 0x8e, 0xf0, 0x92, 0xac, 0x0e, 0x9d, 0xfe, 0x9b, 0x12, 0x4b, 0xe2, 0x2d, 0x40, 0x58, 0x32, - 0xe4, 0xdf, 0x71, 0xb5, 0x1c, 0x4b, 0x85, 0xbc, 0xa4, 0x13, 0x18, 0xa5, 0x07, 0xd1, 0x68, 0xdf, - 0x71, 0xd5, 0x19, 0xe1, 0x28, 0x5f, 0xb4, 0x0b, 0xa3, 0x16, 0xfb, 0xa2, 0x99, 0xb8, 0x1f, 0xe1, - 0x34, 0xbe, 0x8e, 0x16, 0xeb, 0x03, 0xb6, 0xb9, 0x88, 0xef, 0xa6, 0x09, 0x6e, 0xe6, 0xcf, 0xb2, - 0x00, 0x4c, 0x04, 0x1e, 0xfe, 0xdd, 0x62, 0x29, 0x03, 0xb7, 0xdd, 0x7a, 0x3a, 0x1f, 0x69, 0xd3, - 0xa3, 0xb8, 0x41, 0xe4, 0x07, 0xdc, 0x76, 0xeb, 0x58, 0x30, 0x41, 0x0d, 0x18, 0x69, 0x5b, 0xc1, - 0x76, 0xfa, 0x21, 0xe3, 0x79, 0x1e, 0x07, 0x15, 0x6c, 0x63, 0xc6, 0x00, 0xbd, 0x6c, 0xc0, 0x18, - 0x0f, 0x1a, 0x97, 0x16, 0xf7, 0xa1, 0x9f, 0x95, 0x65, 0x9f, 0x2d, 0xf2, 0xc8, 0x74, 0xe1, 0xfa, - 0xa1, 0x54, 0xb2, 0x28, 0xc5, 0x92, 0xed, 0xc2, 0xab, 0x06, 0x4c, 0xe8, 0xa8, 0x09, 0x4e, 0x1b, - 0x1f, 0xd1, 0x9d, 0x36, 0xd2, 0xec, 0x0f, 0xdd, 0xff, 0xe3, 0x5f, 0x0d, 0xd0, 0xbe, 0xba, 0x1b, - 0xba, 0x6c, 0x1a, 0x03, 0xbb, 0x6c, 0x66, 0x8e, 0xe8, 0xb2, 0x99, 0x3d, 0x92, 0xcb, 0xe6, 0xc8, - 0xd1, 0x5d, 0x36, 0x73, 0xfd, 0x5d, 0x36, 0xcd, 0xd7, 0x0d, 0x98, 0xed, 0xd9, 0x87, 0xe9, 0xb1, - 0xcd, 0x73, 0xdd, 0xa0, 0x8f, 0xa7, 0x14, 0x0e, 0x41, 0x58, 0xc7, 0x43, 0x2b, 0x30, 0x23, 0x12, - 0x64, 0x57, 0xdb, 0x4d, 0x3b, 0x31, 0x9c, 0x7f, 0x23, 0x06, 0xc7, 0x3d, 0x35, 0xcc, 0xbf, 0x34, - 0x60, 0x5c, 0x0b, 0x02, 0xa4, 0xed, 0x60, 0xc1, 0x92, 0x42, 0x8c, 0x30, 0x37, 0x38, 0x7b, 0xe1, - 0xe0, 0x30, 0xfe, 0xd8, 0xd6, 0xd0, 0xd2, 0xa7, 0x86, 0x8f, 0x6d, 0xb4, 0x14, 0x0b, 0x28, 0x4f, - 0x8c, 0x49, 0xda, 0xac, 0xd3, 0xb3, 0x7a, 0x62, 0x4c, 0xd2, 0xc6, 0x0c, 0xc2, 0xd8, 0xd1, 0xf3, - 0xab, 0xf0, 0xe6, 0xd5, 0x52, 0x91, 0x5b, 0x5e, 0x80, 0x39, 0x0c, 0x9d, 0x85, 0x2c, 0x71, 0xea, - 0xe2, 0xb2, 0xad, 0x3e, 0xff, 0x75, 0xde, 0xa9, 0x63, 0x5a, 0x6e, 0x5e, 0x81, 0x89, 0x2a, 0xa9, - 0x79, 0x24, 0x78, 0x8e, 0xec, 0x0f, 0xfc, 0x3d, 0x31, 0x3a, 0xdb, 0x63, 0xdf, 0x13, 0xa3, 0xd5, - 0x69, 0xb9, 0xf9, 0x27, 0x06, 0xc4, 0xf2, 0xe5, 0x6b, 0x86, 0x77, 0xa3, 0x9f, 0xe1, 0x3d, 0x62, - 0x22, 0xce, 0x1c, 0x6a, 0x22, 0xbe, 0x04, 0xa8, 0x45, 0x97, 0x42, 0xe4, 0xeb, 0x10, 0xc2, 0xce, - 0x11, 0x86, 0x1c, 0xf7, 0x60, 0xe0, 0x84, 0x5a, 0xe6, 0x1f, 0x73, 0x61, 0xf5, 0x0c, 0xfa, 0x77, - 0xee, 0x80, 0x0e, 0xe4, 0x18, 0x29, 0x61, 0xec, 0x19, 0xd2, 0x50, 0xda, 0x9b, 0xba, 0x23, 0x1c, - 0x48, 0xb1, 0xe4, 0x19, 0x37, 0xf3, 0xfb, 0x5c, 0x56, 0x2d, 0xc5, 0xfe, 0x00, 0xb2, 0xb6, 0xa2, - 0xb2, 0x5e, 0x4c, 0x6b, 0xaf, 0x4c, 0x96, 0x11, 0x2d, 0x02, 0xb4, 0x89, 0x57, 0x23, 0x4e, 0x20, - 0x9d, 0xcc, 0x73, 0x22, 0x28, 0x47, 0x95, 0x62, 0x0d, 0xc3, 0x7c, 0xd9, 0x80, 0x99, 0x6a, 0x60, - 0xd7, 0x76, 0x6c, 0x87, 0x07, 0x99, 0x6d, 0xd9, 0x0d, 0x7a, 0x3b, 0x22, 0xe2, 0x53, 0x59, 0xdc, - 0xfc, 0xa6, 0xb6, 0x62, 0xf9, 0x85, 0x2c, 0x09, 0x47, 0x25, 0x98, 0x96, 0x8f, 0x0e, 0xd2, 0x66, - 0xca, 0x83, 0x63, 0x95, 0x8d, 0x66, 0x25, 0x0a, 0xc6, 0x71, 0x7c, 0xf3, 0x93, 0x30, 0xae, 0xed, - 0xaf, 0x6c, 0x2b, 0xba, 0x65, 0xd5, 0x82, 0xf8, 0x12, 0x3e, 0x4f, 0x0b, 0x31, 0x87, 0x31, 0xd3, - 0x2e, 0xf7, 0x42, 0x8e, 0x2d, 0x61, 0xe1, 0x7b, 0x2c, 0xa0, 0x94, 0x98, 0x47, 0x1a, 0xe4, 0x96, - 0x4c, 0xd4, 0x2a, 0x89, 0x61, 0x5a, 0x88, 0x39, 0xcc, 0x7c, 0x04, 0xf2, 0x32, 0x85, 0x01, 0x8b, - 0x03, 0x96, 0x66, 0x47, 0x3d, 0x0e, 0xd8, 0xf5, 0x02, 0xcc, 0x20, 0xe6, 0x75, 0xc8, 0xcb, 0x4c, - 0x0b, 0x77, 0xc6, 0xa6, 0xab, 0xca, 0x77, 0xec, 0x8b, 0xae, 0x1f, 0xc8, 0xf4, 0x10, 0xfc, 0x65, - 0xe4, 0xf2, 0x2a, 0x2b, 0xc3, 0x0a, 0x6a, 0xce, 0xc2, 0xb4, 0x7a, 0xf2, 0x10, 0x6e, 0xa1, 0xdf, - 0xca, 0xc2, 0x44, 0xe4, 0xeb, 0xd3, 0x77, 0x9e, 0x6e, 0x83, 0xaf, 0xe2, 0x84, 0xa7, 0x8b, 0xec, - 0x11, 0x9f, 0x2e, 0xf4, 0xb7, 0xa2, 0x91, 0x93, 0x7d, 0x2b, 0xca, 0xa5, 0xf3, 0x56, 0x14, 0xc0, - 0x98, 0x2f, 0x14, 0xd5, 0x68, 0x1a, 0x46, 0x9c, 0xd8, 0x88, 0xf1, 0xb3, 0xb1, 0xd4, 0x77, 0x92, - 0x95, 0xf9, 0xf5, 0x1c, 0x4c, 0x45, 0x73, 0x4c, 0x0d, 0x30, 0x92, 0x8f, 0xf4, 0x8c, 0xe4, 0x11, - 0x6d, 0xa5, 0xd9, 0x61, 0x6d, 0xa5, 0x23, 0xc3, 0xda, 0x4a, 0x73, 0xc7, 0xb0, 0x95, 0xf6, 0x5a, - 0x3a, 0x47, 0x07, 0xb6, 0x74, 0x3e, 0xad, 0xfc, 0x8e, 0xc6, 0x22, 0x0f, 0xf5, 0xa1, 0xdf, 0x11, - 0x8a, 0x0e, 0xc3, 0xb2, 0x5b, 0x4f, 0xf4, 0xdf, 0xca, 0xdf, 0xc1, 0x26, 0xe4, 0x25, 0xba, 0x09, - 0x1d, 0xfd, 0x39, 0xe6, 0x6d, 0x47, 0x70, 0x11, 0x7a, 0x02, 0xc6, 0xc5, 0x7c, 0x62, 0x67, 0x25, - 0x88, 0x9e, 0xb3, 0xaa, 0x21, 0x08, 0xeb, 0x78, 0xec, 0x4b, 0xa2, 0xd1, 0x4f, 0xa7, 0x32, 0xd3, - 0xb3, 0xfe, 0x25, 0xd1, 0xd8, 0xa7, 0x56, 0xe3, 0xf8, 0xe6, 0xc7, 0xe1, 0x74, 0xe2, 0x4d, 0x90, - 0x99, 0xc6, 0x98, 0x1a, 0x27, 0x75, 0x81, 0xa0, 0x89, 0x11, 0x4b, 0x41, 0xbc, 0x70, 0xa3, 0x2f, - 0x26, 0x3e, 0x84, 0x8a, 0xf9, 0xb5, 0x2c, 0x4c, 0x45, 0x3f, 0x43, 0x85, 0xf6, 0x94, 0xdd, 0x28, - 0x15, 0x93, 0x15, 0x27, 0xab, 0xe5, 0x2d, 0xea, 0x6b, 0x04, 0xde, 0x63, 0xf3, 0x6b, 0x53, 0x25, - 0x51, 0x3a, 0x39, 0xc6, 0xc2, 0xfa, 0x2a, 0xd8, 0xb1, 0x2f, 0x4d, 0x85, 0xc1, 0x23, 0xe2, 0xda, - 0x95, 0x3a, 0xf7, 0x30, 0x1c, 0x44, 0xb1, 0xc2, 0x1a, 0x5b, 0xaa, 0x5b, 0x76, 0x89, 0x67, 0x6f, - 0xd9, 0xea, 0x13, 0x9a, 0x6c, 0xe7, 0xbe, 0x2e, 0xca, 0xb0, 0x82, 0x9a, 0x2f, 0x67, 0x20, 0xfc, - 0x60, 0x30, 0xfb, 0x56, 0x8b, 0xaf, 0x1d, 0x71, 0xc5, 0xb0, 0x5d, 0x1a, 0xf6, 0x83, 0x48, 0x21, - 0x45, 0xe1, 0x13, 0xaa, 0x95, 0xe0, 0x08, 0xc7, 0x5f, 0xc2, 0x87, 0x82, 0x2d, 0x98, 0x8e, 0x85, - 0xd4, 0xa6, 0xee, 0xbf, 0xff, 0xd3, 0x2c, 0x14, 0x54, 0x50, 0x32, 0x7a, 0x6f, 0xc4, 0xde, 0x50, - 0x28, 0xbf, 0x5d, 0xfb, 0x90, 0xc0, 0xb6, 0x5b, 0xbf, 0xdd, 0x2d, 0x4e, 0x2b, 0xe4, 0x98, 0xed, - 0xe0, 0x2c, 0x64, 0x3b, 0x5e, 0x33, 0x7e, 0xa1, 0xb8, 0x86, 0xd7, 0x30, 0x2d, 0x47, 0xb7, 0xe2, - 0x17, 0xfe, 0xf5, 0x94, 0x02, 0xa9, 0xf9, 0xc9, 0xbb, 0xff, 0x45, 0x9f, 0x6a, 0xc9, 0x4d, 0xb7, - 0xbe, 0x1f, 0xff, 0xf0, 0x40, 0xd9, 0xad, 0xef, 0x63, 0x06, 0x41, 0xcf, 0xc0, 0x54, 0x60, 0xb7, - 0x88, 0xdb, 0x09, 0xf4, 0xcf, 0xb1, 0x66, 0xc3, 0x47, 0xcd, 0x8d, 0x08, 0x14, 0xc7, 0xb0, 0xa9, - 0x96, 0xbd, 0xe9, 0xbb, 0x0e, 0xcb, 0x26, 0x38, 0x1a, 0x7d, 0x01, 0xb9, 0x54, 0xbd, 0x72, 0x99, - 0xd9, 0x3d, 0x14, 0x06, 0xc5, 0xb6, 0x59, 0x04, 0xa2, 0x47, 0x84, 0x4f, 0xc1, 0x4c, 0x98, 0x9f, - 0x82, 0x97, 0x63, 0x85, 0x81, 0x56, 0x38, 0x6d, 0x2a, 0x2d, 0xd3, 0x28, 0x13, 0xe5, 0x87, 0x25, - 0x5d, 0x5a, 0x76, 0xbb, 0x5b, 0x9c, 0x27, 0x4e, 0xcd, 0xad, 0xdb, 0x4e, 0x63, 0x89, 0x22, 0x2e, - 0x62, 0x6b, 0x4f, 0xaa, 0x1a, 0x55, 0xd3, 0xbc, 0x06, 0xd3, 0xb1, 0x0e, 0x93, 0x17, 0x40, 0x23, - 0xf9, 0x02, 0x38, 0xd8, 0xb7, 0x02, 0xfe, 0xcc, 0x80, 0xd9, 0x9e, 0x2d, 0x60, 0xd0, 0xf0, 0x94, - 0xb8, 0x32, 0xca, 0x1c, 0x5f, 0x19, 0x65, 0x8f, 0xa6, 0x8c, 0xca, 0x9b, 0xdf, 0x79, 0xf3, 0xdc, - 0x3d, 0xdf, 0x7b, 0xf3, 0xdc, 0x3d, 0x3f, 0x7c, 0xf3, 0xdc, 0x3d, 0x2f, 0x1f, 0x9c, 0x33, 0xbe, - 0x73, 0x70, 0xce, 0xf8, 0xde, 0xc1, 0x39, 0xe3, 0x87, 0x07, 0xe7, 0x8c, 0x7f, 0x3c, 0x38, 0x67, - 0xbc, 0xfe, 0xd3, 0x73, 0xf7, 0x3c, 0xff, 0x74, 0x38, 0x41, 0x97, 0xe4, 0x04, 0x65, 0x3f, 0xde, - 0x25, 0xa7, 0xe3, 0x52, 0x7b, 0xa7, 0xb1, 0x44, 0x27, 0xe8, 0x92, 0x2a, 0x91, 0x13, 0xf4, 0xbf, - 0x02, 0x00, 0x00, 0xff, 0xff, 0x3e, 0xb7, 0xa2, 0x97, 0xc8, 0x95, 0x00, 0x00, + 0xd5, 0x98, 0x87, 0x14, 0x25, 0xf2, 0xe8, 0xff, 0xae, 0x36, 0x2b, 0xcb, 0xde, 0xa5, 0x33, 0x0e, + 0x5c, 0xa7, 0x75, 0xa4, 0xc4, 0x3f, 0xad, 0x13, 0x1b, 0x6e, 0x49, 0x69, 0xd7, 0xab, 0xb5, 0xb4, + 0xcb, 0xbd, 0xd4, 0xee, 0x26, 0x4e, 0x9c, 0x64, 0x44, 0x5e, 0x51, 0xb3, 0x22, 0x67, 0x98, 0x99, + 0xa1, 0xb4, 0x72, 0x8c, 0xc4, 0x4e, 0x60, 0x37, 0x2d, 0x12, 0xc4, 0x6d, 0x12, 0x14, 0x45, 0x81, + 0x22, 0x08, 0x0c, 0xf4, 0x27, 0x79, 0x0a, 0x5a, 0xf4, 0x25, 0x40, 0x8b, 0xe6, 0xa7, 0xe9, 0x43, + 0x8a, 0xe4, 0xa1, 0xcd, 0x0f, 0x10, 0xb6, 0x56, 0xfa, 0xd2, 0xa2, 0x45, 0x50, 0x20, 0xc5, 0x87, + 0xec, 0xd3, 0x87, 0xfb, 0x3b, 0x77, 0x86, 0x43, 0x2d, 0x29, 0x8e, 0x36, 0xc6, 0xf7, 0xe5, 0x8d, + 0xbc, 0xe7, 0xdc, 0x73, 0xce, 0xfd, 0x3f, 0xf7, 0xdc, 0x73, 0xce, 0xc0, 0x46, 0xc3, 0x0e, 0x76, + 0x3b, 0xdb, 0xcb, 0x35, 0xb7, 0xb5, 0x62, 0x79, 0x0d, 0xb7, 0xed, 0xb9, 0xb7, 0xd9, 0x8f, 0x0f, + 0x79, 0x6e, 0xb3, 0xe9, 0x76, 0x02, 0x7f, 0xa5, 0xbd, 0xd7, 0x58, 0xb1, 0xda, 0xb6, 0xbf, 0xa2, + 0x4a, 0xf6, 0x3f, 0x62, 0x35, 0xdb, 0xbb, 0xd6, 0x47, 0x56, 0x1a, 0xc4, 0x21, 0x9e, 0x15, 0x90, + 0xfa, 0x72, 0xdb, 0x73, 0x03, 0x17, 0x3d, 0x1f, 0x52, 0x5b, 0x96, 0xd4, 0xd8, 0x8f, 0xcf, 0xc8, + 0xba, 0xcb, 0xed, 0xbd, 0xc6, 0x32, 0xa5, 0xb6, 0xac, 0x4a, 0x24, 0xb5, 0xa5, 0x0f, 0x69, 0xb2, + 0x34, 0xdc, 0x86, 0xbb, 0xc2, 0x88, 0x6e, 0x77, 0x76, 0xd8, 0x3f, 0xf6, 0x87, 0xfd, 0xe2, 0xcc, + 0x96, 0x1e, 0xdd, 0x7b, 0xd6, 0x5f, 0xb6, 0x5d, 0x2a, 0xdb, 0xca, 0xb6, 0x15, 0xd4, 0x76, 0x57, + 0xf6, 0x7b, 0x24, 0x5a, 0x32, 0x35, 0xa4, 0x9a, 0xeb, 0x91, 0x24, 0x9c, 0xa7, 0x43, 0x9c, 0x96, + 0x55, 0xdb, 0xb5, 0x1d, 0xe2, 0x1d, 0x86, 0xad, 0x6e, 0x91, 0xc0, 0x4a, 0xaa, 0xb5, 0xd2, 0xaf, + 0x96, 0xd7, 0x71, 0x02, 0xbb, 0x45, 0x7a, 0x2a, 0xfc, 0xed, 0x7b, 0x55, 0xf0, 0x6b, 0xbb, 0xa4, + 0x65, 0xf5, 0xd4, 0x7b, 0xaa, 0x5f, 0xbd, 0x4e, 0x60, 0x37, 0x57, 0x6c, 0x27, 0xf0, 0x03, 0x2f, + 0x5e, 0xc9, 0xfc, 0x51, 0x16, 0x0a, 0xa5, 0x8d, 0x72, 0x35, 0xb0, 0x82, 0x8e, 0x8f, 0xde, 0x32, + 0x60, 0xaa, 0xe9, 0x5a, 0xf5, 0xb2, 0xd5, 0xb4, 0x9c, 0x1a, 0xf1, 0x16, 0x8d, 0x47, 0x8c, 0xc7, + 0x27, 0x9f, 0xdc, 0x58, 0x1e, 0x65, 0xbc, 0x96, 0x4b, 0x07, 0x3e, 0x26, 0xbe, 0xdb, 0xf1, 0x6a, + 0x04, 0x93, 0x9d, 0xf2, 0xc2, 0x4f, 0xbb, 0xc5, 0x07, 0x8e, 0xba, 0xc5, 0xa9, 0x0d, 0x8d, 0x13, + 0x8e, 0xf0, 0x45, 0xdf, 0x32, 0x60, 0xbe, 0x66, 0x39, 0x96, 0x77, 0xb8, 0x65, 0x79, 0x0d, 0x12, + 0xbc, 0xe8, 0xb9, 0x9d, 0xf6, 0x62, 0xe6, 0x14, 0xa4, 0x79, 0x50, 0x48, 0x33, 0xbf, 0x1a, 0x67, + 0x87, 0x7b, 0x25, 0x60, 0x72, 0xf9, 0x81, 0xb5, 0xdd, 0x24, 0xba, 0x5c, 0xd9, 0xd3, 0x94, 0xab, + 0x1a, 0x67, 0x87, 0x7b, 0x25, 0x30, 0xdf, 0xcc, 0xc2, 0x7c, 0x69, 0xa3, 0xbc, 0xe5, 0x59, 0x3b, + 0x3b, 0x76, 0x0d, 0xbb, 0x9d, 0xc0, 0x76, 0x1a, 0xe8, 0x83, 0x30, 0x61, 0x3b, 0x0d, 0x8f, 0xf8, + 0x3e, 0x1b, 0xc8, 0x42, 0x79, 0x56, 0x10, 0x9d, 0x58, 0xe7, 0xc5, 0x58, 0xc2, 0xd1, 0x33, 0x30, + 0xe9, 0x13, 0x6f, 0xdf, 0xae, 0x91, 0x8a, 0xeb, 0x05, 0xac, 0xa7, 0x73, 0xe5, 0x33, 0x02, 0x7d, + 0xb2, 0x1a, 0x82, 0xb0, 0x8e, 0x47, 0xab, 0x79, 0xae, 0x1b, 0x08, 0x38, 0xeb, 0x88, 0x42, 0x58, + 0x0d, 0x87, 0x20, 0xac, 0xe3, 0xa1, 0xb7, 0x0d, 0x98, 0xf3, 0x03, 0xbb, 0xb6, 0x67, 0x3b, 0xc4, + 0xf7, 0x57, 0x5d, 0x67, 0xc7, 0x6e, 0x2c, 0xe6, 0x58, 0x2f, 0x5e, 0x1d, 0xad, 0x17, 0xab, 0x31, + 0xaa, 0xe5, 0x85, 0xa3, 0x6e, 0x71, 0x2e, 0x5e, 0x8a, 0x7b, 0xb8, 0xa3, 0x35, 0x98, 0xb3, 0x1c, + 0xc7, 0x0d, 0xac, 0xc0, 0x76, 0x9d, 0x8a, 0x47, 0x76, 0xec, 0x3b, 0x8b, 0x63, 0xac, 0x39, 0x8b, + 0xa2, 0x39, 0x73, 0xa5, 0x18, 0x1c, 0xf7, 0xd4, 0x30, 0xd7, 0x60, 0xb1, 0xd4, 0xda, 0xb6, 0x7c, + 0xdf, 0xaa, 0xbb, 0x5e, 0x6c, 0x34, 0x1e, 0x87, 0x7c, 0xcb, 0x6a, 0xb7, 0x6d, 0xa7, 0x41, 0x87, + 0x23, 0xfb, 0x78, 0xa1, 0x3c, 0x75, 0xd4, 0x2d, 0xe6, 0x37, 0x45, 0x19, 0x56, 0x50, 0xf3, 0xd7, + 0x19, 0x98, 0x2c, 0x39, 0x56, 0xf3, 0xd0, 0xb7, 0x7d, 0xdc, 0x71, 0xd0, 0x67, 0x21, 0x4f, 0x77, + 0x97, 0xba, 0x15, 0x58, 0x62, 0x45, 0x7e, 0x78, 0x99, 0x2f, 0xf6, 0x65, 0x7d, 0xb1, 0x87, 0xfd, + 0x42, 0xb1, 0x97, 0xf7, 0x3f, 0xb2, 0x7c, 0x6d, 0xfb, 0x36, 0xa9, 0x05, 0x9b, 0x24, 0xb0, 0xca, + 0x48, 0xb4, 0x02, 0xc2, 0x32, 0xac, 0xa8, 0x22, 0x17, 0xc6, 0xfc, 0x36, 0xa9, 0x89, 0x15, 0xb6, + 0x39, 0xe2, 0x4c, 0x0e, 0x45, 0xaf, 0xb6, 0x49, 0xad, 0x3c, 0x25, 0x58, 0x8f, 0xd1, 0x7f, 0x98, + 0x31, 0x42, 0x07, 0x30, 0xee, 0xb3, 0x3d, 0x47, 0x2c, 0x9e, 0x6b, 0xe9, 0xb1, 0x64, 0x64, 0xcb, + 0x33, 0x82, 0xe9, 0x38, 0xff, 0x8f, 0x05, 0x3b, 0xf3, 0x37, 0x06, 0x9c, 0xd1, 0xb0, 0x4b, 0x5e, + 0xa3, 0xd3, 0x22, 0x4e, 0x80, 0x1e, 0x81, 0x31, 0xc7, 0x6a, 0x11, 0xb1, 0x50, 0x94, 0xc8, 0x57, + 0xad, 0x16, 0xc1, 0x0c, 0x82, 0x1e, 0x85, 0xdc, 0xbe, 0xd5, 0xec, 0x10, 0xd6, 0x49, 0x85, 0xf2, + 0xb4, 0x40, 0xc9, 0xdd, 0xa4, 0x85, 0x98, 0xc3, 0xd0, 0x6b, 0x50, 0x60, 0x3f, 0x2e, 0x79, 0x6e, + 0x2b, 0xa5, 0xa6, 0x09, 0x09, 0x6f, 0x4a, 0xb2, 0xe5, 0xe9, 0xa3, 0x6e, 0xb1, 0xa0, 0xfe, 0xe2, + 0x90, 0xa1, 0xf9, 0xdf, 0x0d, 0x98, 0xd5, 0x1a, 0xb7, 0x61, 0xfb, 0x01, 0xfa, 0x54, 0xcf, 0xe4, + 0x59, 0x1e, 0x6c, 0xf2, 0xd0, 0xda, 0x6c, 0xea, 0xcc, 0x89, 0x96, 0xe6, 0x65, 0x89, 0x36, 0x71, + 0x1c, 0xc8, 0xd9, 0x01, 0x69, 0xf9, 0x8b, 0x99, 0x47, 0xb2, 0x8f, 0x4f, 0x3e, 0xb9, 0x9e, 0xda, + 0x30, 0x86, 0xfd, 0xbb, 0x4e, 0xe9, 0x63, 0xce, 0xc6, 0xfc, 0xfe, 0x58, 0xa4, 0x85, 0x74, 0x46, + 0x21, 0x17, 0x26, 0x5a, 0x24, 0xf0, 0xec, 0x1a, 0x5f, 0x57, 0x93, 0x4f, 0xae, 0x8d, 0x26, 0xc5, + 0x26, 0x23, 0x16, 0x6e, 0x96, 0xfc, 0xbf, 0x8f, 0x25, 0x17, 0xb4, 0x0b, 0x63, 0x96, 0xd7, 0x90, + 0x6d, 0xbe, 0x94, 0xce, 0xf8, 0x86, 0x73, 0xae, 0xe4, 0x35, 0x7c, 0xcc, 0x38, 0xa0, 0x15, 0x28, + 0x04, 0xc4, 0x6b, 0xd9, 0x8e, 0x15, 0xf0, 0xdd, 0x35, 0x5f, 0x9e, 0x17, 0x68, 0x85, 0x2d, 0x09, + 0xc0, 0x21, 0x0e, 0x6a, 0xc2, 0x78, 0xdd, 0x3b, 0xc4, 0x1d, 0x67, 0x71, 0x2c, 0x8d, 0xae, 0x58, + 0x63, 0xb4, 0xc2, 0xc5, 0xc4, 0xff, 0x63, 0xc1, 0x03, 0xbd, 0x63, 0xc0, 0x42, 0x8b, 0x58, 0x7e, + 0xc7, 0x23, 0xb4, 0x09, 0x98, 0x04, 0xc4, 0xa1, 0xbb, 0xe1, 0x62, 0x8e, 0x31, 0xc7, 0xa3, 0x8e, + 0x43, 0x2f, 0xe5, 0xf2, 0xc3, 0x42, 0x94, 0x85, 0x24, 0x28, 0x4e, 0x94, 0xc6, 0xfc, 0xf5, 0x18, + 0xcc, 0xf7, 0xec, 0x10, 0xe8, 0x69, 0xc8, 0xb5, 0x77, 0x2d, 0x5f, 0x2e, 0xf9, 0x0b, 0x72, 0xbe, + 0x55, 0x68, 0xe1, 0xdd, 0x6e, 0x71, 0x5a, 0x56, 0x61, 0x05, 0x98, 0x23, 0xd3, 0x33, 0xb5, 0x45, + 0x7c, 0xdf, 0x6a, 0xc8, 0x7d, 0x40, 0x9b, 0x26, 0xac, 0x18, 0x4b, 0x38, 0xfa, 0xfb, 0x06, 0x4c, + 0xf3, 0x29, 0x83, 0x89, 0xdf, 0x69, 0x06, 0x74, 0xaf, 0xa3, 0xdd, 0x72, 0x25, 0x8d, 0xe9, 0xc9, + 0x49, 0x96, 0xcf, 0x0a, 0xee, 0xd3, 0x7a, 0xa9, 0x8f, 0xa3, 0x7c, 0xd1, 0x2d, 0x28, 0xf8, 0x81, + 0xe5, 0x05, 0xa4, 0x5e, 0x0a, 0xd8, 0xa9, 0x36, 0xf9, 0xe4, 0xdf, 0x1c, 0x6c, 0x13, 0xd8, 0xb2, + 0x5b, 0x84, 0x6f, 0x38, 0x55, 0x49, 0x00, 0x87, 0xb4, 0xd0, 0x6b, 0x00, 0x5e, 0xc7, 0xa9, 0x76, + 0x5a, 0x2d, 0xcb, 0x3b, 0x14, 0x27, 0xf8, 0xe5, 0xd1, 0x9a, 0x87, 0x15, 0xbd, 0xf0, 0xcc, 0x0a, + 0xcb, 0xb0, 0xc6, 0x0f, 0xbd, 0x61, 0xc0, 0x34, 0x9f, 0x89, 0x52, 0x82, 0xf1, 0x94, 0x25, 0x98, + 0xa7, 0x5d, 0xbb, 0xa6, 0xb3, 0xc0, 0x51, 0x8e, 0xe6, 0x7f, 0x8d, 0x9e, 0x27, 0xd5, 0x80, 0x6a, + 0xd7, 0x8d, 0x43, 0xf4, 0x49, 0x78, 0xd0, 0xef, 0xd4, 0x6a, 0xc4, 0xf7, 0x77, 0x3a, 0x4d, 0xdc, + 0x71, 0x2e, 0xdb, 0x7e, 0xe0, 0x7a, 0x87, 0x1b, 0x76, 0xcb, 0x0e, 0xd8, 0x8c, 0xcb, 0x95, 0xcf, + 0x1f, 0x75, 0x8b, 0x0f, 0x56, 0xfb, 0x21, 0xe1, 0xfe, 0xf5, 0x91, 0x05, 0x0f, 0x75, 0x9c, 0xfe, + 0xe4, 0xb9, 0xf6, 0x56, 0x3c, 0xea, 0x16, 0x1f, 0xba, 0xd1, 0x1f, 0x0d, 0x1f, 0x47, 0xc3, 0xfc, + 0xdf, 0x06, 0xcc, 0xc9, 0x76, 0x6d, 0x91, 0x56, 0xbb, 0x49, 0x77, 0x97, 0xd3, 0x57, 0x44, 0x82, + 0x88, 0x22, 0x82, 0xd3, 0x39, 0x4e, 0xa4, 0xfc, 0xfd, 0xb4, 0x11, 0xf3, 0x7f, 0x19, 0xb0, 0x10, + 0x47, 0xbe, 0x0f, 0x87, 0xa7, 0x1f, 0x3d, 0x3c, 0xaf, 0xa6, 0xdb, 0xda, 0x3e, 0x27, 0xe8, 0x5b, + 0x63, 0xbd, 0x6d, 0xfd, 0xab, 0x7e, 0x8c, 0x86, 0xa7, 0x62, 0xf6, 0x4f, 0x79, 0x2a, 0x8e, 0xbd, + 0xa7, 0x4e, 0xc5, 0x7f, 0x39, 0x06, 0x53, 0x25, 0x27, 0xb0, 0x4b, 0x3b, 0x3b, 0xb6, 0x63, 0x07, + 0x87, 0xe8, 0xab, 0x19, 0x58, 0x69, 0x7b, 0x64, 0x87, 0x78, 0x1e, 0xa9, 0xaf, 0x75, 0x3c, 0xdb, + 0x69, 0x54, 0x6b, 0xbb, 0xa4, 0xde, 0x69, 0xda, 0x4e, 0x63, 0xbd, 0xe1, 0xb8, 0xaa, 0xf8, 0xe2, + 0x1d, 0x52, 0xeb, 0xb0, 0x26, 0xf1, 0x45, 0xd1, 0x1a, 0xad, 0x49, 0x95, 0xe1, 0x98, 0x96, 0x9f, + 0x3a, 0xea, 0x16, 0x57, 0x86, 0xac, 0x84, 0x87, 0x6d, 0x1a, 0xfa, 0x4a, 0x06, 0x96, 0x3d, 0xf2, + 0xb9, 0x8e, 0x3d, 0x78, 0x6f, 0xf0, 0x5d, 0xab, 0x39, 0xe2, 0xf1, 0x33, 0x14, 0xcf, 0xf2, 0x93, + 0x47, 0xdd, 0xe2, 0x90, 0x75, 0xf0, 0x90, 0xed, 0x32, 0x2b, 0x30, 0x59, 0x6a, 0xdb, 0xbe, 0x7d, + 0x87, 0xde, 0x65, 0xc9, 0x00, 0x77, 0xa5, 0x22, 0xe4, 0xbc, 0x4e, 0x93, 0xf0, 0xb5, 0x5d, 0x28, + 0x17, 0xe8, 0x2e, 0x84, 0x69, 0x01, 0xe6, 0xe5, 0xe6, 0x97, 0xe8, 0x8e, 0xcb, 0x48, 0xc6, 0x6e, + 0xc9, 0xb7, 0x21, 0xe7, 0x51, 0x26, 0x62, 0x66, 0x8d, 0x7a, 0xa1, 0x08, 0xa5, 0x16, 0x42, 0xd0, + 0x9f, 0x98, 0xb3, 0x30, 0x7f, 0x98, 0x81, 0xb3, 0xa5, 0x76, 0x7b, 0x93, 0xf8, 0xbb, 0x31, 0x29, + 0xbe, 0x6e, 0xc0, 0xcc, 0xbe, 0xed, 0x05, 0x1d, 0xab, 0x29, 0x6d, 0x1b, 0x5c, 0x9e, 0xea, 0xa8, + 0xf2, 0x30, 0x6e, 0x37, 0x23, 0xa4, 0xcb, 0xe8, 0xa8, 0x5b, 0x9c, 0x89, 0x96, 0xe1, 0x18, 0x7b, + 0xf4, 0x4f, 0x0c, 0x98, 0x13, 0x45, 0x57, 0xdd, 0x3a, 0xd1, 0x0d, 0x62, 0x37, 0xd2, 0x94, 0x49, + 0x11, 0xe7, 0x96, 0x93, 0x78, 0x29, 0xee, 0x11, 0xc2, 0xfc, 0xbf, 0x19, 0x38, 0xd7, 0x87, 0x06, + 0xfa, 0x17, 0x06, 0x2c, 0x70, 0x2b, 0x9a, 0x06, 0xc2, 0x64, 0x47, 0xf4, 0xe6, 0x27, 0xd2, 0x96, + 0x1c, 0xd3, 0x25, 0x4e, 0x9c, 0x1a, 0x29, 0x2f, 0xd2, 0xdd, 0x70, 0x35, 0x81, 0x35, 0x4e, 0x14, + 0x88, 0x49, 0xca, 0xed, 0x6a, 0x31, 0x49, 0x33, 0xf7, 0x45, 0xd2, 0x6a, 0x02, 0x6b, 0x9c, 0x28, + 0x90, 0xf9, 0x77, 0xe1, 0xa1, 0x63, 0xc8, 0xdd, 0x7b, 0x71, 0x9a, 0xaf, 0xa8, 0x59, 0x1f, 0x9d, + 0x73, 0x03, 0xac, 0x6b, 0x13, 0xc6, 0xd9, 0xd2, 0x91, 0x0b, 0x1b, 0xe8, 0xf1, 0xc7, 0xd6, 0x94, + 0x8f, 0x05, 0xc4, 0xfc, 0xa1, 0x01, 0xf9, 0x21, 0xcc, 0x2a, 0xc5, 0xa8, 0x59, 0xa5, 0xd0, 0x63, + 0x52, 0x09, 0x7a, 0x4d, 0x2a, 0x2f, 0x8e, 0x36, 0x1a, 0x83, 0x98, 0x52, 0x7e, 0x6f, 0xc0, 0x7c, + 0x8f, 0xe9, 0x05, 0xed, 0xc2, 0x42, 0xdb, 0xad, 0x4b, 0xb5, 0xe9, 0xb2, 0xe5, 0xef, 0x32, 0x98, + 0x68, 0xde, 0xd3, 0x74, 0x24, 0x2b, 0x09, 0xf0, 0xbb, 0xdd, 0xe2, 0xa2, 0x22, 0x12, 0x43, 0xc0, + 0x89, 0x14, 0x51, 0x1b, 0xf2, 0x3b, 0x36, 0x69, 0xd6, 0xc3, 0x29, 0x38, 0xa2, 0x82, 0x74, 0x49, + 0x50, 0xe3, 0x56, 0x47, 0xf9, 0x0f, 0x2b, 0x2e, 0xe6, 0x75, 0x98, 0x89, 0xda, 0xa0, 0x07, 0x18, + 0xbc, 0xf3, 0x90, 0xb5, 0x3c, 0x47, 0x0c, 0xdd, 0xa4, 0x40, 0xc8, 0x96, 0xf0, 0x55, 0x4c, 0xcb, + 0xcd, 0x3f, 0x8e, 0xc1, 0x6c, 0xb9, 0xd9, 0x21, 0x2f, 0x7a, 0x84, 0xc8, 0x6b, 0x77, 0x09, 0x66, + 0xdb, 0x1e, 0xd9, 0xb7, 0xc9, 0x41, 0x95, 0x34, 0x49, 0x2d, 0x70, 0x3d, 0x41, 0xff, 0x9c, 0xa8, + 0x3e, 0x5b, 0x89, 0x82, 0x71, 0x1c, 0x1f, 0xbd, 0x00, 0x33, 0x56, 0x2d, 0xb0, 0xf7, 0x89, 0xa2, + 0xc0, 0x05, 0x78, 0x9f, 0xa0, 0x30, 0x53, 0x8a, 0x40, 0x71, 0x0c, 0x1b, 0x7d, 0x0a, 0x16, 0xfd, + 0x9a, 0xd5, 0x24, 0x37, 0xda, 0x82, 0xd5, 0xea, 0x2e, 0xa9, 0xed, 0x55, 0x5c, 0xdb, 0x09, 0x84, + 0x91, 0xe5, 0x11, 0x41, 0x69, 0xb1, 0xda, 0x07, 0x0f, 0xf7, 0xa5, 0x80, 0xfe, 0xbd, 0x01, 0xe7, + 0xdb, 0x1e, 0xa9, 0x78, 0x6e, 0xcb, 0xa5, 0xa7, 0x67, 0x8f, 0xe5, 0x41, 0xdc, 0xc0, 0x6f, 0x8e, + 0xa8, 0x26, 0xf0, 0x92, 0x5e, 0xcb, 0xe7, 0xfb, 0x8f, 0xba, 0xc5, 0xf3, 0x95, 0xe3, 0x04, 0xc0, + 0xc7, 0xcb, 0x87, 0xfe, 0xa3, 0x01, 0x17, 0xda, 0xae, 0x1f, 0x1c, 0xd3, 0x84, 0xdc, 0xa9, 0x36, + 0xc1, 0x3c, 0xea, 0x16, 0x2f, 0x54, 0x8e, 0x95, 0x00, 0xdf, 0x43, 0x42, 0xf3, 0x68, 0x12, 0xe6, + 0xb5, 0xb9, 0x27, 0xae, 0xe5, 0xcf, 0xc1, 0xb4, 0x9c, 0x0c, 0xe1, 0xb1, 0x5e, 0x08, 0xcd, 0x28, + 0x25, 0x1d, 0x88, 0xa3, 0xb8, 0x74, 0xde, 0xa9, 0xa9, 0xc8, 0x6b, 0xc7, 0xe6, 0x5d, 0x25, 0x02, + 0xc5, 0x31, 0x6c, 0xb4, 0x0e, 0x67, 0x44, 0x09, 0x26, 0xed, 0xa6, 0x5d, 0xb3, 0x56, 0xdd, 0x8e, + 0x98, 0x72, 0xb9, 0xf2, 0xb9, 0xa3, 0x6e, 0xf1, 0x4c, 0xa5, 0x17, 0x8c, 0x93, 0xea, 0xa0, 0x0d, + 0x58, 0xb0, 0x3a, 0x81, 0xab, 0xda, 0x7f, 0xd1, 0xa1, 0x27, 0x45, 0x9d, 0x4d, 0xad, 0x3c, 0x3f, + 0x52, 0x4a, 0x09, 0x70, 0x9c, 0x58, 0x0b, 0x55, 0x62, 0xd4, 0xaa, 0xa4, 0xe6, 0x3a, 0x75, 0x3e, + 0xca, 0xb9, 0xf0, 0x72, 0x51, 0x4a, 0xc0, 0xc1, 0x89, 0x35, 0x51, 0x13, 0x66, 0x5a, 0xd6, 0x9d, + 0x1b, 0x8e, 0xb5, 0x6f, 0xd9, 0x4d, 0xca, 0x44, 0x98, 0x66, 0xfa, 0xdb, 0x0b, 0x3a, 0x81, 0xdd, + 0x5c, 0xe6, 0xaf, 0x94, 0xcb, 0xeb, 0x4e, 0x70, 0xcd, 0xab, 0x06, 0x54, 0x09, 0xe5, 0xca, 0xd1, + 0x66, 0x84, 0x16, 0x8e, 0xd1, 0x46, 0xd7, 0xe0, 0x2c, 0x5b, 0x8e, 0x6b, 0xee, 0x81, 0xb3, 0x46, + 0x9a, 0xd6, 0xa1, 0x6c, 0xc0, 0x04, 0x6b, 0xc0, 0x83, 0x47, 0xdd, 0xe2, 0xd9, 0x6a, 0x12, 0x02, + 0x4e, 0xae, 0x87, 0x2c, 0x78, 0x28, 0x0a, 0xc0, 0x64, 0xdf, 0xf6, 0x6d, 0xd7, 0xe1, 0x06, 0x96, + 0x7c, 0x68, 0x60, 0xa9, 0xf6, 0x47, 0xc3, 0xc7, 0xd1, 0x40, 0xff, 0xcc, 0x80, 0x85, 0xa4, 0x65, + 0xb8, 0x58, 0x48, 0xe3, 0x0d, 0x26, 0xb6, 0xb4, 0xf8, 0x8c, 0x48, 0xdc, 0x14, 0x12, 0x85, 0x40, + 0xaf, 0x1b, 0x30, 0x65, 0x69, 0x97, 0xc3, 0x45, 0x60, 0x52, 0x5d, 0x19, 0xd5, 0x44, 0x11, 0x52, + 0x2c, 0xcf, 0x1d, 0x75, 0x8b, 0x91, 0x0b, 0x28, 0x8e, 0x70, 0x44, 0xff, 0xdc, 0x80, 0xb3, 0x89, + 0x6b, 0x7c, 0x71, 0xf2, 0x34, 0x7a, 0x88, 0x4d, 0x92, 0xe4, 0x3d, 0x27, 0x59, 0x0c, 0xf4, 0xb6, + 0xa1, 0x8e, 0xb2, 0x4d, 0x69, 0x24, 0x9a, 0x62, 0xa2, 0x5d, 0x1f, 0xf1, 0x3e, 0x1c, 0x2a, 0x04, + 0x92, 0x70, 0xf9, 0x8c, 0x76, 0x32, 0xca, 0x42, 0x1c, 0x67, 0x8f, 0xbe, 0x66, 0xc8, 0xa3, 0x51, + 0x49, 0x34, 0x7d, 0x5a, 0x12, 0xa1, 0xf0, 0xa4, 0x55, 0x02, 0xc5, 0x98, 0xa3, 0x4f, 0xc3, 0x92, + 0xb5, 0xed, 0x7a, 0x41, 0xe2, 0xe2, 0x5b, 0x9c, 0x61, 0xcb, 0xe8, 0xc2, 0x51, 0xb7, 0xb8, 0x54, + 0xea, 0x8b, 0x85, 0x8f, 0xa1, 0x60, 0x7e, 0x2f, 0x07, 0x53, 0x5c, 0xc9, 0x17, 0x47, 0xd7, 0x0f, + 0x0c, 0x78, 0xb8, 0xd6, 0xf1, 0x3c, 0xe2, 0x04, 0xd5, 0x80, 0xb4, 0x7b, 0x0f, 0x2e, 0xe3, 0x54, + 0x0f, 0xae, 0x47, 0x8e, 0xba, 0xc5, 0x87, 0x57, 0x8f, 0xe1, 0x8f, 0x8f, 0x95, 0x0e, 0xfd, 0x17, + 0x03, 0x4c, 0x81, 0x50, 0xb6, 0x6a, 0x7b, 0x0d, 0xcf, 0xed, 0x38, 0xf5, 0xde, 0x46, 0x64, 0x4e, + 0xb5, 0x11, 0x8f, 0x1d, 0x75, 0x8b, 0xe6, 0xea, 0x3d, 0xa5, 0xc0, 0x03, 0x48, 0x8a, 0x5e, 0x84, + 0x79, 0x81, 0x75, 0xf1, 0x4e, 0x9b, 0x78, 0x36, 0x55, 0xa7, 0x85, 0x9b, 0x40, 0xe8, 0x79, 0x11, + 0x47, 0xc0, 0xbd, 0x75, 0x90, 0x0f, 0x13, 0x07, 0xc4, 0x6e, 0xec, 0x06, 0x52, 0x7d, 0x1a, 0xd1, + 0xdd, 0x42, 0x5c, 0xf8, 0x6f, 0x71, 0x9a, 0xe5, 0xc9, 0xa3, 0x6e, 0x71, 0x42, 0xfc, 0xc1, 0x92, + 0x13, 0xba, 0x0a, 0x33, 0xfc, 0x0a, 0x56, 0xb1, 0x9d, 0x46, 0xc5, 0x75, 0xb8, 0x93, 0x42, 0xa1, + 0xfc, 0x98, 0x3c, 0xf0, 0xab, 0x11, 0xe8, 0xdd, 0x6e, 0x71, 0x4a, 0xfe, 0xde, 0x3a, 0x6c, 0x13, + 0x1c, 0xab, 0x6d, 0xfe, 0x64, 0x1c, 0x40, 0x4e, 0x57, 0xd2, 0x46, 0x7f, 0x0b, 0x0a, 0x3e, 0x09, + 0x38, 0x57, 0xf1, 0x26, 0xc0, 0x9f, 0x5a, 0x64, 0x21, 0x0e, 0xe1, 0x68, 0x0f, 0x72, 0x6d, 0xab, + 0xe3, 0x13, 0x31, 0xf8, 0x57, 0x52, 0x19, 0xfc, 0x0a, 0xa5, 0xc8, 0xef, 0x5c, 0xec, 0x27, 0xe6, + 0x3c, 0xd0, 0x97, 0x0d, 0x00, 0x12, 0x1d, 0xb0, 0x91, 0x6d, 0x1f, 0x82, 0x65, 0x38, 0xa6, 0xb4, + 0x0f, 0xca, 0x33, 0x47, 0xdd, 0x22, 0x68, 0x43, 0xaf, 0xb1, 0x45, 0x07, 0x90, 0xb7, 0xe4, 0x9e, + 0x3f, 0x76, 0x1a, 0x7b, 0x3e, 0xbb, 0x0a, 0xa9, 0x49, 0xab, 0x98, 0xa1, 0xaf, 0x18, 0x30, 0xe3, + 0x93, 0x40, 0x0c, 0x15, 0xdd, 0x79, 0x84, 0xc2, 0x3b, 0xe2, 0xa4, 0xab, 0x46, 0x68, 0xf2, 0x1d, + 0x34, 0x5a, 0x86, 0x63, 0x7c, 0xa5, 0x28, 0x97, 0x89, 0x55, 0x27, 0x1e, 0xbb, 0x69, 0x0b, 0x4d, + 0x6a, 0x74, 0x51, 0x34, 0x9a, 0x4a, 0x14, 0xad, 0x0c, 0xc7, 0xf8, 0x4a, 0x51, 0x36, 0x6d, 0xcf, + 0x73, 0x85, 0x28, 0xf9, 0x94, 0x44, 0xd1, 0x68, 0x2a, 0x51, 0xb4, 0x32, 0x1c, 0xe3, 0x6b, 0x7e, + 0x7b, 0x1a, 0x66, 0xe4, 0x42, 0x0a, 0x35, 0x7b, 0x6e, 0xd8, 0xe9, 0xa3, 0xd9, 0xaf, 0xea, 0x40, + 0x1c, 0xc5, 0xa5, 0x95, 0xf9, 0x52, 0x8d, 0x2a, 0xf6, 0xaa, 0x72, 0x55, 0x07, 0xe2, 0x28, 0x2e, + 0x6a, 0x41, 0xce, 0x0f, 0x48, 0x5b, 0x3e, 0xef, 0x8e, 0xf8, 0xfa, 0x18, 0xee, 0x0f, 0xe1, 0x03, + 0x0e, 0xfd, 0xe7, 0x63, 0xce, 0x85, 0xd9, 0x26, 0x83, 0x88, 0xb9, 0x52, 0x2c, 0x8e, 0x74, 0xd6, + 0x67, 0xd4, 0x12, 0xca, 0x47, 0x23, 0x5a, 0x86, 0x63, 0xec, 0x13, 0x94, 0xfd, 0xdc, 0x29, 0x2a, + 0xfb, 0x2f, 0x43, 0xbe, 0x65, 0xdd, 0xa9, 0x76, 0xbc, 0xc6, 0xc9, 0x2f, 0x15, 0xc2, 0xf3, 0x8a, + 0x53, 0xc1, 0x8a, 0x1e, 0x7a, 0xc3, 0xd0, 0xb6, 0x9c, 0x09, 0x46, 0xfc, 0x56, 0xba, 0x5b, 0x8e, + 0x3a, 0x2b, 0xfb, 0x6e, 0x3e, 0x3d, 0xaa, 0x77, 0xfe, 0xbe, 0xab, 0xde, 0x54, 0x8d, 0xe4, 0x0b, + 0x44, 0xa9, 0x91, 0x85, 0x53, 0x55, 0x23, 0x57, 0x23, 0xcc, 0x70, 0x8c, 0x39, 0x93, 0x87, 0xaf, + 0x39, 0x25, 0x0f, 0x9c, 0xaa, 0x3c, 0xd5, 0x08, 0x33, 0x1c, 0x63, 0xde, 0xff, 0xbe, 0x39, 0x79, + 0x3a, 0xf7, 0xcd, 0xa9, 0x14, 0xee, 0x9b, 0xc7, 0xab, 0xe2, 0xd3, 0xa3, 0xaa, 0xe2, 0xe8, 0x0a, + 0xa0, 0xfa, 0xa1, 0x63, 0xb5, 0xec, 0x9a, 0xd8, 0x2c, 0xd9, 0xb1, 0x39, 0xc3, 0xec, 0x11, 0x4b, + 0x62, 0x23, 0x43, 0x6b, 0x3d, 0x18, 0x38, 0xa1, 0x16, 0x0a, 0x20, 0xdf, 0x96, 0x1a, 0xd7, 0x6c, + 0x1a, 0xb3, 0x5f, 0x6a, 0x60, 0xdc, 0x03, 0x80, 0x2e, 0x3c, 0x59, 0x82, 0x15, 0x27, 0xb4, 0x01, + 0x0b, 0x2d, 0xdb, 0xa9, 0xb8, 0x75, 0xbf, 0x42, 0x3c, 0x61, 0x6d, 0xa9, 0x92, 0x60, 0x71, 0x8e, + 0xf5, 0x0d, 0xbb, 0x41, 0x6f, 0x26, 0xc0, 0x71, 0x62, 0x2d, 0xf3, 0xff, 0x1b, 0x30, 0xb7, 0xda, + 0x74, 0x3b, 0xf5, 0x5b, 0x56, 0x50, 0xdb, 0xe5, 0x8f, 0xdf, 0xe8, 0x05, 0xc8, 0xdb, 0x4e, 0x40, + 0xbc, 0x7d, 0xab, 0x29, 0xce, 0x27, 0x53, 0xfa, 0x07, 0xac, 0x8b, 0xf2, 0xbb, 0xdd, 0xe2, 0xcc, + 0x5a, 0xc7, 0x63, 0x5e, 0xa5, 0x7c, 0xb7, 0xc2, 0xaa, 0x0e, 0xfa, 0xb6, 0x01, 0xf3, 0xfc, 0xf9, + 0x7c, 0xcd, 0x0a, 0xac, 0xeb, 0x1d, 0xe2, 0xd9, 0x44, 0x3e, 0xa0, 0x8f, 0xb8, 0x51, 0xc5, 0x65, + 0x95, 0x0c, 0x0e, 0x43, 0x45, 0x7d, 0x33, 0xce, 0x19, 0xf7, 0x0a, 0x63, 0x7e, 0x23, 0x0b, 0x0f, + 0xf6, 0xa5, 0x85, 0x96, 0x20, 0x63, 0xd7, 0x45, 0xd3, 0x41, 0xd0, 0xcd, 0xac, 0xd7, 0x71, 0xc6, + 0xae, 0xa3, 0x65, 0xa6, 0x73, 0x7a, 0xc4, 0xf7, 0xe5, 0x5b, 0x6a, 0x41, 0xa9, 0x87, 0xa2, 0x14, + 0x6b, 0x18, 0xa8, 0x08, 0xb9, 0xa6, 0xb5, 0x4d, 0x9a, 0xe2, 0x3e, 0xc1, 0xb4, 0xd8, 0x0d, 0x5a, + 0x80, 0x79, 0x39, 0xfa, 0x92, 0x01, 0xc0, 0x05, 0xa4, 0xb7, 0x11, 0x71, 0x4a, 0xe2, 0x74, 0xbb, + 0x89, 0x52, 0xe6, 0x52, 0x86, 0xff, 0xb1, 0xc6, 0x15, 0x6d, 0xc1, 0x38, 0x55, 0x68, 0xdd, 0xfa, + 0x89, 0x0f, 0x45, 0xf6, 0xc8, 0x52, 0x61, 0x34, 0xb0, 0xa0, 0x45, 0xfb, 0xca, 0x23, 0x41, 0xc7, + 0x73, 0x68, 0xd7, 0xb2, 0x63, 0x30, 0xcf, 0xa5, 0xc0, 0xaa, 0x14, 0x6b, 0x18, 0xe6, 0xbf, 0xcb, + 0xc0, 0x42, 0x92, 0xe8, 0xf4, 0xb4, 0x19, 0xe7, 0xd2, 0x8a, 0xab, 0xf1, 0xc7, 0xd3, 0xef, 0x1f, + 0xe1, 0x09, 0xa2, 0xfc, 0x25, 0x84, 0xaf, 0x9a, 0xe0, 0x8b, 0x3e, 0xae, 0x7a, 0x28, 0x73, 0xc2, + 0x1e, 0x52, 0x94, 0x63, 0xbd, 0xf4, 0x08, 0x8c, 0xf9, 0x74, 0xe4, 0xb3, 0xd1, 0x07, 0x0c, 0x36, + 0x46, 0x0c, 0x42, 0x31, 0x3a, 0x8e, 0x1d, 0x08, 0x57, 0x6f, 0x85, 0x71, 0xc3, 0xb1, 0x03, 0xcc, + 0x20, 0xe6, 0xb7, 0x32, 0xb0, 0xd4, 0xbf, 0x51, 0xe8, 0x5b, 0x06, 0x40, 0x9d, 0x5e, 0x57, 0xe8, + 0x94, 0x94, 0x9e, 0x33, 0xd6, 0x69, 0xf5, 0xe1, 0x9a, 0xe4, 0x14, 0xba, 0x51, 0xa9, 0x22, 0x1f, + 0x6b, 0x82, 0xa0, 0x27, 0xe5, 0xd4, 0xbf, 0x6a, 0xb5, 0xa4, 0x3a, 0xab, 0xea, 0x6c, 0x2a, 0x08, + 0xd6, 0xb0, 0xe8, 0x7d, 0xd4, 0xb1, 0x5a, 0xc4, 0x6f, 0x5b, 0xca, 0x97, 0x9f, 0xdd, 0x47, 0xaf, + 0xca, 0x42, 0x1c, 0xc2, 0xcd, 0x26, 0x3c, 0x3a, 0x80, 0x9c, 0x29, 0xf9, 0x55, 0x9b, 0xff, 0xcf, + 0x80, 0x73, 0xab, 0xcd, 0x8e, 0x1f, 0x10, 0xef, 0xaf, 0x8d, 0x57, 0xda, 0x5f, 0x18, 0xf0, 0x50, + 0x9f, 0x36, 0xdf, 0x07, 0xe7, 0xb4, 0x57, 0xa3, 0xce, 0x69, 0x37, 0x46, 0x9d, 0xd2, 0x89, 0xed, + 0xe8, 0xe3, 0xa3, 0x16, 0xc0, 0x34, 0xdd, 0xb5, 0xea, 0x6e, 0x23, 0xa5, 0x73, 0xf3, 0x51, 0xc8, + 0x7d, 0x8e, 0x9e, 0x3f, 0xf1, 0x39, 0xc6, 0x0e, 0x25, 0xcc, 0x61, 0xe6, 0xf3, 0x20, 0x3c, 0xb9, + 0x62, 0x8b, 0xc7, 0x18, 0x64, 0xf1, 0x98, 0xff, 0x2d, 0x03, 0x9a, 0x1d, 0xe3, 0x3e, 0x4c, 0x4a, + 0x27, 0x32, 0x29, 0x47, 0xbc, 0x83, 0x6b, 0x56, 0x99, 0x7e, 0x21, 0x1b, 0xfb, 0xb1, 0x90, 0x8d, + 0xab, 0xa9, 0x71, 0x3c, 0x3e, 0x62, 0xe3, 0x97, 0x06, 0x3c, 0x14, 0x22, 0xf7, 0x9a, 0x18, 0xef, + 0xbd, 0xc3, 0x3c, 0x03, 0x93, 0x56, 0x58, 0x4d, 0xcc, 0x01, 0x15, 0xa5, 0xa4, 0x51, 0xc4, 0x3a, + 0x5e, 0xe8, 0x20, 0x9e, 0x3d, 0xa1, 0x83, 0xf8, 0xd8, 0xf1, 0x0e, 0xe2, 0xe6, 0x1f, 0x32, 0x70, + 0xbe, 0xb7, 0x65, 0x72, 0x6d, 0x0c, 0xf6, 0x02, 0xff, 0x2c, 0x4c, 0x05, 0xa2, 0x82, 0xb6, 0xd3, + 0xab, 0x18, 0xbb, 0x2d, 0x0d, 0x86, 0x23, 0x98, 0xb4, 0x66, 0x8d, 0xaf, 0xca, 0x6a, 0xcd, 0x6d, + 0xcb, 0xf0, 0x02, 0x55, 0x73, 0x55, 0x83, 0xe1, 0x08, 0xa6, 0x72, 0xdc, 0x1c, 0x3b, 0x75, 0xc7, + 0xcd, 0x2a, 0x9c, 0x95, 0xae, 0x6a, 0x97, 0x5c, 0x6f, 0xd5, 0x6d, 0xb5, 0x9b, 0x44, 0x04, 0x18, + 0x50, 0x61, 0xcf, 0x8b, 0x2a, 0x67, 0x71, 0x12, 0x12, 0x4e, 0xae, 0x6b, 0xfe, 0x32, 0x0b, 0x67, + 0xc2, 0x6e, 0x5f, 0x75, 0x9d, 0xba, 0xcd, 0x1c, 0xfe, 0x9e, 0x83, 0xb1, 0xe0, 0xb0, 0x2d, 0x3b, + 0xfb, 0x6f, 0x48, 0x71, 0xb6, 0x0e, 0xdb, 0x74, 0xb4, 0xcf, 0x25, 0x54, 0x61, 0x46, 0x5e, 0x56, + 0x09, 0x6d, 0xa8, 0xd5, 0xc1, 0x47, 0xe0, 0xe9, 0xe8, 0x6c, 0xbe, 0xdb, 0x2d, 0x26, 0x84, 0x98, + 0x2e, 0x2b, 0x4a, 0xd1, 0x39, 0x8f, 0x6e, 0xc3, 0x4c, 0xd3, 0xf2, 0x83, 0x1b, 0xed, 0xba, 0x15, + 0x90, 0x2d, 0xbb, 0x45, 0xc4, 0x9a, 0x1b, 0xc6, 0x6b, 0x5f, 0xbd, 0x4a, 0x6f, 0x44, 0x28, 0xe1, + 0x18, 0x65, 0xb4, 0x0f, 0x88, 0x96, 0x6c, 0x79, 0x96, 0xe3, 0xf3, 0x56, 0x51, 0x7e, 0xc3, 0x47, + 0x09, 0xa8, 0x4b, 0xde, 0x46, 0x0f, 0x35, 0x9c, 0xc0, 0x01, 0x3d, 0x06, 0xe3, 0x1e, 0xb1, 0x7c, + 0x31, 0x98, 0x85, 0x70, 0xfd, 0x63, 0x56, 0x8a, 0x05, 0x54, 0x5f, 0x50, 0xe3, 0xf7, 0x58, 0x50, + 0xbf, 0x35, 0x60, 0x26, 0x1c, 0xa6, 0xfb, 0x70, 0x48, 0xb6, 0xa2, 0x87, 0xe4, 0xe5, 0xb4, 0xb6, + 0xc4, 0x3e, 0xe7, 0xe2, 0x7f, 0x1a, 0xd7, 0xdb, 0xc7, 0xbc, 0xb6, 0x3f, 0x0f, 0x05, 0xb9, 0xaa, + 0xa5, 0xf6, 0x39, 0xe2, 0x5d, 0x39, 0xa2, 0x97, 0x68, 0xd1, 0x46, 0x82, 0x09, 0x0e, 0xf9, 0xd1, + 0x63, 0xb9, 0x2e, 0x8e, 0x5c, 0x31, 0xed, 0xd5, 0xb1, 0x2c, 0x8f, 0xe2, 0xa4, 0x63, 0x59, 0xd6, + 0x41, 0x37, 0xe0, 0x5c, 0xdb, 0x73, 0x59, 0x04, 0xea, 0x1a, 0xb1, 0xea, 0x4d, 0xdb, 0x21, 0xd2, + 0x20, 0xc1, 0x9d, 0x22, 0x1e, 0x3a, 0xea, 0x16, 0xcf, 0x55, 0x92, 0x51, 0x70, 0xbf, 0xba, 0xd1, + 0xa8, 0xa9, 0xb1, 0x01, 0xa2, 0xa6, 0xfe, 0x81, 0x32, 0xfb, 0x11, 0x5f, 0xc4, 0x2e, 0x7d, 0x32, + 0xad, 0xa1, 0x4c, 0xd8, 0xd6, 0xc3, 0x29, 0x55, 0x12, 0x4c, 0xb1, 0x62, 0xdf, 0xdf, 0xb6, 0x34, + 0x7e, 0x42, 0xdb, 0x52, 0xe8, 0xfc, 0x3e, 0xf1, 0xa7, 0x74, 0x7e, 0xcf, 0xbf, 0xa7, 0x9c, 0xdf, + 0xdf, 0xcc, 0xc1, 0x5c, 0x5c, 0x03, 0x39, 0xfd, 0x88, 0xb0, 0x7f, 0x6c, 0xc0, 0x9c, 0x5c, 0x3d, + 0x9c, 0x27, 0x91, 0xaf, 0x06, 0x1b, 0x29, 0x2d, 0x5a, 0xae, 0x4b, 0xa9, 0x98, 0xe5, 0xad, 0x18, + 0x37, 0xdc, 0xc3, 0x1f, 0xbd, 0x02, 0x93, 0xca, 0xb8, 0x7e, 0xa2, 0xf0, 0xb0, 0x59, 0xa6, 0x45, + 0x85, 0x24, 0xb0, 0x4e, 0x0f, 0xbd, 0x69, 0x00, 0xd4, 0xe4, 0x31, 0x27, 0x57, 0xd7, 0xf5, 0xb4, + 0x56, 0x97, 0x3a, 0x40, 0x43, 0x65, 0x59, 0x15, 0xf9, 0x58, 0x63, 0x8c, 0xbe, 0xc1, 0xcc, 0xea, + 0x4a, 0xbb, 0xa3, 0xeb, 0x29, 0x3b, 0xba, 0x63, 0xef, 0x31, 0x8a, 0x69, 0xa8, 0x4a, 0x69, 0x20, + 0x1f, 0x47, 0x84, 0x30, 0x9f, 0x03, 0xe5, 0x8a, 0x49, 0xb7, 0x2d, 0xe6, 0x8c, 0x59, 0xb1, 0x82, + 0x5d, 0x31, 0x05, 0xd5, 0xb6, 0x75, 0x49, 0x02, 0x70, 0x88, 0x63, 0x7e, 0x16, 0x66, 0x5e, 0xf4, + 0xac, 0xf6, 0xae, 0xcd, 0xcc, 0xd7, 0xf4, 0x9e, 0xf4, 0x41, 0x98, 0xb0, 0xea, 0xf5, 0xa4, 0x88, + 0xff, 0x12, 0x2f, 0xc6, 0x12, 0x3e, 0xd8, 0x95, 0xe8, 0x27, 0x06, 0xa0, 0xf0, 0x09, 0xd0, 0x76, + 0x1a, 0x9b, 0xf4, 0xb6, 0x4f, 0xef, 0x47, 0xbb, 0xac, 0x34, 0xe9, 0x7e, 0x74, 0x59, 0x41, 0xb0, + 0x86, 0x85, 0x5e, 0x83, 0x49, 0xfe, 0xef, 0xa6, 0xba, 0xec, 0x8f, 0xec, 0xde, 0xcf, 0x0f, 0x14, + 0x26, 0x13, 0x9f, 0x85, 0x97, 0x43, 0x0e, 0x58, 0x67, 0x47, 0xbb, 0x6a, 0xdd, 0xd9, 0x69, 0x76, + 0xee, 0xd4, 0xb7, 0xc3, 0xae, 0x6a, 0x7b, 0xee, 0x8e, 0xdd, 0x24, 0xf1, 0xae, 0xaa, 0xf0, 0x62, + 0x2c, 0xe1, 0x83, 0x75, 0xd5, 0x8f, 0x0c, 0x58, 0x58, 0xf7, 0x03, 0xdb, 0x5d, 0x23, 0x7e, 0x40, + 0x8f, 0x15, 0xba, 0xf9, 0x74, 0x9a, 0x83, 0x78, 0x55, 0xaf, 0xc1, 0x9c, 0x78, 0x8e, 0xec, 0x6c, + 0xfb, 0x24, 0xd0, 0xf4, 0x78, 0xb5, 0x8e, 0x57, 0x63, 0x70, 0xdc, 0x53, 0x83, 0x52, 0x11, 0xef, + 0x92, 0x21, 0x95, 0x6c, 0x94, 0x4a, 0x35, 0x06, 0xc7, 0x3d, 0x35, 0xcc, 0x9f, 0x67, 0xe1, 0x0c, + 0x6b, 0x46, 0x2c, 0x22, 0xe2, 0x6b, 0xfd, 0x22, 0x22, 0x46, 0x5c, 0xca, 0x8c, 0xd7, 0x09, 0xe2, + 0x21, 0xfe, 0x91, 0x01, 0xb3, 0xf5, 0x68, 0x4f, 0xa7, 0x63, 0x9e, 0x49, 0x1a, 0x43, 0xee, 0x7d, + 0x15, 0x2b, 0xc4, 0x71, 0xfe, 0xe8, 0x9b, 0x06, 0xcc, 0x46, 0xc5, 0x94, 0xbb, 0xfb, 0x29, 0x74, + 0x92, 0x72, 0x97, 0x8e, 0x96, 0xfb, 0x38, 0x2e, 0x82, 0xf9, 0xb3, 0x8c, 0x18, 0xd2, 0xd3, 0x70, + 0xf7, 0x47, 0x07, 0x50, 0x08, 0x9a, 0x3e, 0x2f, 0x14, 0xad, 0x1d, 0xf1, 0x46, 0xb8, 0xb5, 0x51, + 0xe5, 0x9e, 0x00, 0xa1, 0xd2, 0x26, 0x4a, 0xa8, 0xf2, 0x29, 0x79, 0x31, 0xc6, 0xb5, 0xb6, 0x60, + 0x9c, 0xca, 0x55, 0x74, 0x6b, 0xb5, 0x12, 0x67, 0x2c, 0x4a, 0x28, 0x63, 0xc9, 0xcb, 0xfc, 0xae, + 0x01, 0x85, 0x2b, 0xae, 0xdc, 0x47, 0x3e, 0x9d, 0x82, 0xa1, 0x47, 0xe9, 0x83, 0xea, 0xc5, 0x31, + 0xbc, 0x62, 0xbc, 0x10, 0x31, 0xf3, 0x3c, 0xac, 0xd1, 0x5e, 0x66, 0xd9, 0x8c, 0x28, 0xa9, 0x2b, + 0xee, 0x76, 0x5f, 0x2b, 0xe2, 0x77, 0x72, 0x30, 0xfd, 0x92, 0x75, 0x48, 0x9c, 0xc0, 0x1a, 0xfe, + 0x90, 0x78, 0x06, 0x26, 0xad, 0x36, 0x7b, 0xd2, 0xd2, 0x74, 0xfc, 0xd0, 0x72, 0x12, 0x82, 0xb0, + 0x8e, 0x17, 0x6e, 0x68, 0x3c, 0xb9, 0x4a, 0xd2, 0x56, 0xb4, 0x1a, 0x83, 0xe3, 0x9e, 0x1a, 0xe8, + 0x0a, 0x20, 0x11, 0x2a, 0x5a, 0xaa, 0xd5, 0xdc, 0x8e, 0xc3, 0xb7, 0x34, 0x6e, 0x54, 0x51, 0x97, + 0xcd, 0xcd, 0x1e, 0x0c, 0x9c, 0x50, 0x0b, 0x7d, 0x0a, 0x16, 0x6b, 0x8c, 0xb2, 0xb8, 0x7a, 0xe8, + 0x14, 0xf9, 0xf5, 0x53, 0xb9, 0xfc, 0xaf, 0xf6, 0xc1, 0xc3, 0x7d, 0x29, 0x50, 0x49, 0xfd, 0xc0, + 0xf5, 0xac, 0x06, 0xd1, 0xe9, 0x8e, 0x47, 0x25, 0xad, 0xf6, 0x60, 0xe0, 0x84, 0x5a, 0xe8, 0x8b, + 0x50, 0x08, 0x76, 0x3d, 0xe2, 0xef, 0xba, 0xcd, 0xba, 0x70, 0x41, 0x18, 0xd1, 0xd2, 0x26, 0x46, + 0x7f, 0x4b, 0x52, 0xd5, 0xa6, 0xb7, 0x2c, 0xc2, 0x21, 0x4f, 0xe4, 0xc1, 0xb8, 0x5f, 0x73, 0xdb, + 0xc4, 0x17, 0x2a, 0xfb, 0x95, 0x54, 0xb8, 0x33, 0xcb, 0x91, 0x66, 0xe3, 0x63, 0x1c, 0xb0, 0xe0, + 0x64, 0xfe, 0x38, 0x03, 0x53, 0x3a, 0xe2, 0x00, 0x7b, 0xd3, 0x97, 0x0d, 0x98, 0xaa, 0xb9, 0x4e, + 0xe0, 0xb9, 0x4d, 0x6e, 0xbf, 0x4a, 0x47, 0xa3, 0xa0, 0xa4, 0xd6, 0x48, 0x60, 0xd9, 0x4d, 0xcd, + 0x14, 0xa6, 0xb1, 0xc1, 0x11, 0xa6, 0xe8, 0xab, 0x06, 0xcc, 0x86, 0x1e, 0x6b, 0xa1, 0x21, 0x2d, + 0x55, 0x41, 0xd4, 0x56, 0x7f, 0x31, 0xca, 0x09, 0xc7, 0x59, 0x9b, 0xdb, 0x30, 0x17, 0x1f, 0x6d, + 0xda, 0x95, 0x6d, 0x4b, 0xac, 0xf5, 0x6c, 0xd8, 0x95, 0x15, 0xcb, 0xf7, 0x31, 0x83, 0xa0, 0x27, + 0x20, 0xdf, 0xb2, 0xbc, 0x86, 0xed, 0x58, 0x4d, 0xd6, 0x8b, 0x59, 0x6d, 0x43, 0x12, 0xe5, 0x58, + 0x61, 0x98, 0x1f, 0x86, 0xa9, 0x4d, 0xcb, 0x69, 0x90, 0xba, 0xd8, 0x87, 0xef, 0x1d, 0x70, 0xf6, + 0xbb, 0x31, 0x98, 0xd4, 0xee, 0x66, 0xa7, 0x7f, 0xcf, 0x8a, 0xe4, 0xbb, 0xc8, 0xa6, 0x98, 0xef, + 0xe2, 0x65, 0x80, 0x1d, 0xdb, 0xb1, 0xfd, 0xdd, 0x13, 0x66, 0xd2, 0x60, 0x4f, 0xb4, 0x97, 0x14, + 0x05, 0xac, 0x51, 0x0b, 0xdf, 0xc1, 0x72, 0xc7, 0xe4, 0x17, 0x7a, 0xd3, 0xd0, 0x8e, 0x9b, 0xf1, + 0x34, 0xde, 0xfd, 0xb5, 0x81, 0x59, 0x96, 0xc7, 0xcf, 0x45, 0x27, 0xf0, 0x0e, 0x8f, 0x3d, 0x95, + 0xb6, 0x20, 0xef, 0x11, 0xbf, 0xd3, 0xa2, 0x37, 0xc6, 0x89, 0xa1, 0xbb, 0x81, 0x79, 0x60, 0x60, + 0x51, 0x1f, 0x2b, 0x4a, 0x4b, 0xcf, 0xc1, 0x74, 0x44, 0x04, 0x34, 0x07, 0xd9, 0x3d, 0x72, 0xc8, + 0xe7, 0x09, 0xa6, 0x3f, 0xd1, 0x42, 0xe4, 0xb5, 0x50, 0x74, 0xcb, 0xc7, 0x32, 0xcf, 0x1a, 0xa6, + 0x0b, 0x89, 0x06, 0x80, 0x93, 0x3c, 0xe6, 0xd0, 0xb1, 0x68, 0x6a, 0xa9, 0x34, 0xd4, 0x58, 0x70, + 0x3f, 0x1b, 0x0e, 0x33, 0xff, 0x30, 0x0e, 0xe2, 0x29, 0x7b, 0x80, 0xed, 0x4a, 0x7f, 0xc1, 0xca, + 0x9c, 0xe0, 0x05, 0xeb, 0x0a, 0x4c, 0xd9, 0x8e, 0x1d, 0xd8, 0x56, 0x93, 0x19, 0x77, 0xc4, 0x71, + 0x2a, 0x1d, 0x91, 0xa7, 0xd6, 0x35, 0x58, 0x02, 0x9d, 0x48, 0x5d, 0x74, 0x1d, 0x72, 0xec, 0xbc, + 0x11, 0x13, 0x78, 0xf8, 0xf7, 0x76, 0xe6, 0x6a, 0xc1, 0xa3, 0x93, 0x38, 0x25, 0x76, 0xf9, 0xe0, + 0xb9, 0x44, 0xd4, 0xf5, 0x5b, 0xcc, 0xe3, 0xf0, 0xf2, 0x11, 0x83, 0xe3, 0x9e, 0x1a, 0x94, 0xca, + 0x8e, 0x65, 0x37, 0x3b, 0x1e, 0x09, 0xa9, 0x8c, 0x47, 0xa9, 0x5c, 0x8a, 0xc1, 0x71, 0x4f, 0x0d, + 0xb4, 0x03, 0x53, 0xa2, 0x8c, 0x7b, 0x4f, 0x4d, 0x9c, 0xb0, 0x95, 0xcc, 0x4b, 0xee, 0x92, 0x46, + 0x09, 0x47, 0xe8, 0xa2, 0x0e, 0xcc, 0xdb, 0x4e, 0xcd, 0x75, 0x6a, 0xcd, 0x8e, 0x6f, 0xef, 0x93, + 0x30, 0x34, 0xe8, 0x24, 0xcc, 0xce, 0x1e, 0x75, 0x8b, 0xf3, 0xeb, 0x71, 0x72, 0xb8, 0x97, 0x03, + 0x7a, 0xc3, 0x80, 0xb3, 0x35, 0xd7, 0xf1, 0x59, 0x70, 0xfe, 0x3e, 0xb9, 0xe8, 0x79, 0xae, 0xc7, + 0x79, 0x17, 0x4e, 0xc8, 0x9b, 0xd9, 0x14, 0x57, 0x93, 0x48, 0xe2, 0x64, 0x4e, 0xe8, 0x55, 0xc8, + 0xb7, 0x3d, 0x77, 0xdf, 0xae, 0x13, 0x4f, 0x78, 0xe2, 0x6d, 0xa4, 0x91, 0x2c, 0xa4, 0x22, 0x68, + 0x86, 0x5b, 0x8f, 0x2c, 0xc1, 0x8a, 0x9f, 0xf9, 0x0e, 0xc0, 0x4c, 0x14, 0x1d, 0x7d, 0x01, 0xa0, + 0xed, 0xb9, 0x2d, 0x12, 0xec, 0x12, 0x15, 0xe2, 0x71, 0x75, 0xd4, 0x9c, 0x14, 0x92, 0x9e, 0xf4, + 0x5e, 0xa1, 0xdb, 0x45, 0x58, 0x8a, 0x35, 0x8e, 0xc8, 0x83, 0x89, 0x3d, 0x7e, 0xec, 0x0a, 0x2d, + 0xe4, 0xa5, 0x54, 0x74, 0x26, 0xc1, 0x99, 0xc5, 0x26, 0x88, 0x22, 0x2c, 0x19, 0xa1, 0x6d, 0xc8, + 0x1e, 0x90, 0xed, 0x74, 0x02, 0xa2, 0x6f, 0x11, 0x71, 0x9b, 0x29, 0x4f, 0x1c, 0x75, 0x8b, 0xd9, + 0x5b, 0x64, 0x1b, 0x53, 0xe2, 0xb4, 0x5d, 0x75, 0xfe, 0x0e, 0x2f, 0xb6, 0x8a, 0x11, 0xdb, 0x15, + 0x79, 0xd4, 0xe7, 0xed, 0x12, 0x45, 0x58, 0x32, 0x42, 0xaf, 0x42, 0xe1, 0xc0, 0xda, 0x27, 0x3b, + 0x9e, 0xeb, 0x04, 0xc2, 0x65, 0x6a, 0x44, 0xaf, 0xff, 0x5b, 0x92, 0x9c, 0xe0, 0xcb, 0x8e, 0x77, + 0x55, 0x88, 0x43, 0x76, 0x68, 0x1f, 0xf2, 0x0e, 0x39, 0xc0, 0xa4, 0x69, 0xd7, 0xd2, 0xf1, 0xb2, + 0xbf, 0x2a, 0xa8, 0x09, 0xce, 0xec, 0xdc, 0x93, 0x65, 0x58, 0xf1, 0xa2, 0x63, 0x79, 0xdb, 0xdd, + 0x16, 0x1b, 0xd5, 0x88, 0x63, 0xa9, 0x6e, 0xa6, 0x7c, 0x2c, 0xaf, 0xb8, 0xdb, 0x98, 0x12, 0xa7, + 0x6b, 0xa4, 0xa6, 0xfc, 0x75, 0xc4, 0x36, 0x75, 0x35, 0x5d, 0x3f, 0x25, 0xbe, 0x46, 0xc2, 0x52, + 0xac, 0x71, 0xa4, 0x7d, 0xdb, 0x10, 0xc6, 0x4a, 0xb1, 0x51, 0x8d, 0xd8, 0xb7, 0x51, 0xd3, 0x27, + 0xef, 0x5b, 0x59, 0x86, 0x15, 0x2f, 0xca, 0xd7, 0x16, 0x96, 0xbf, 0x74, 0xb6, 0xaa, 0xa8, 0x1d, + 0x91, 0xf3, 0x95, 0x65, 0x58, 0xf1, 0xa2, 0xfd, 0xed, 0xef, 0x1d, 0x1e, 0x58, 0xcd, 0x3d, 0xdb, + 0x69, 0x88, 0x90, 0xc5, 0x51, 0x93, 0x9b, 0xee, 0x1d, 0xde, 0xe2, 0xf4, 0xf4, 0xfe, 0x0e, 0x4b, + 0xb1, 0xc6, 0xd1, 0xfc, 0xee, 0x38, 0x4c, 0xe9, 0x49, 0xe1, 0x06, 0xd0, 0x51, 0x94, 0x5e, 0x9e, + 0x19, 0x46, 0x2f, 0xa7, 0x17, 0x31, 0xed, 0x8d, 0x45, 0x1a, 0x81, 0xd6, 0x53, 0x53, 0x4b, 0xc3, + 0x8b, 0x98, 0x56, 0xe8, 0xe3, 0x08, 0xd3, 0x21, 0xdc, 0x2e, 0xa8, 0x72, 0xc7, 0xd5, 0x9f, 0x5c, + 0x54, 0xb9, 0x8b, 0x28, 0x34, 0x4f, 0x02, 0x84, 0xc9, 0xd1, 0xc4, 0xdb, 0x9b, 0xd2, 0x1a, 0xb5, + 0xa4, 0x6d, 0x1a, 0x16, 0x7a, 0x0c, 0xc6, 0xa9, 0x82, 0x40, 0xea, 0x22, 0xee, 0x58, 0xdd, 0x76, + 0x2f, 0xb1, 0x52, 0x2c, 0xa0, 0xe8, 0x59, 0xaa, 0xcb, 0x85, 0xc7, 0xba, 0x08, 0x27, 0x5e, 0x08, + 0x75, 0xb9, 0x10, 0x86, 0x23, 0x98, 0x54, 0x74, 0x42, 0x4f, 0x61, 0xb6, 0x82, 0x34, 0xd1, 0xd9, + 0xd1, 0x8c, 0x39, 0x8c, 0x59, 0x5f, 0x62, 0xa7, 0x36, 0x9b, 0xf9, 0x39, 0xcd, 0xfa, 0x12, 0x83, + 0xe3, 0x9e, 0x1a, 0xb4, 0x31, 0xe2, 0xd9, 0x70, 0x92, 0x7b, 0x97, 0xf6, 0x79, 0xf0, 0x7b, 0x4b, + 0xbf, 0x91, 0x4c, 0xb1, 0xa1, 0xff, 0x78, 0x7a, 0x09, 0x0e, 0x07, 0xbf, 0x92, 0x8c, 0x76, 0x79, + 0xf8, 0x2c, 0xcc, 0x44, 0xf7, 0xea, 0xd4, 0xdf, 0x07, 0xfe, 0x73, 0x16, 0xce, 0x5c, 0x6d, 0xd8, + 0x4e, 0x3c, 0xe1, 0x51, 0x52, 0xe2, 0x61, 0x63, 0xd8, 0xc4, 0xc3, 0x61, 0x00, 0x93, 0xc8, 0xec, + 0x9c, 0x1c, 0xc0, 0x24, 0xd3, 0x3e, 0x47, 0x71, 0xd1, 0x6f, 0x0d, 0x78, 0xd8, 0xaa, 0x73, 0xed, + 0xd9, 0x6a, 0x8a, 0xd2, 0x90, 0xa9, 0x5c, 0xd1, 0xfe, 0x88, 0x67, 0x61, 0x6f, 0xe3, 0x97, 0x4b, + 0xc7, 0x70, 0xe5, 0x23, 0xfe, 0x01, 0xd1, 0x82, 0x87, 0x8f, 0x43, 0xc5, 0xc7, 0x8a, 0xbf, 0x74, + 0x0d, 0xde, 0x7f, 0x4f, 0x46, 0x43, 0xcd, 0x96, 0x2f, 0x1b, 0x50, 0xe0, 0xe6, 0x5b, 0x4c, 0x76, + 0xe8, 0x56, 0x61, 0xb5, 0xed, 0x9b, 0xc4, 0xf3, 0x65, 0x46, 0x34, 0xed, 0x82, 0x59, 0xaa, 0xac, + 0x0b, 0x08, 0xd6, 0xb0, 0xe8, 0x66, 0xbc, 0x67, 0x3b, 0x75, 0x31, 0x4c, 0x6a, 0x33, 0x7e, 0xc9, + 0x76, 0xea, 0x98, 0x41, 0xd4, 0x76, 0x9d, 0xed, 0x6b, 0x56, 0x79, 0xc7, 0x80, 0x19, 0x16, 0xb5, + 0x19, 0x5e, 0x7d, 0x9e, 0x51, 0x3e, 0x35, 0x5c, 0x8c, 0xf3, 0x51, 0x9f, 0x9a, 0xbb, 0xdd, 0xe2, + 0x24, 0x8f, 0xf3, 0x8c, 0xba, 0xd8, 0x7c, 0x52, 0xd8, 0x4b, 0x98, 0xe7, 0x4f, 0x66, 0xe8, 0xeb, + 0xbc, 0xb2, 0x27, 0x56, 0x25, 0x11, 0x1c, 0xd2, 0x33, 0x5f, 0x83, 0x29, 0x3d, 0xfc, 0x02, 0x3d, + 0x03, 0x93, 0x6d, 0xdb, 0x69, 0x44, 0xc3, 0xf4, 0x94, 0x4d, 0xb9, 0x12, 0x82, 0xb0, 0x8e, 0xc7, + 0xaa, 0xb9, 0x61, 0xb5, 0x98, 0x29, 0xba, 0xe2, 0xea, 0xd5, 0xc2, 0x3f, 0xe6, 0xbf, 0xc9, 0xc2, + 0x99, 0x84, 0x30, 0x1f, 0xf4, 0xa6, 0x01, 0xe3, 0x2c, 0x4a, 0x40, 0x7a, 0xcd, 0xbc, 0x92, 0x7a, + 0x28, 0xd1, 0x32, 0x0b, 0x46, 0x10, 0xf3, 0x58, 0x6d, 0x9f, 0xbc, 0x10, 0x0b, 0xe6, 0xe8, 0x9f, + 0x1a, 0x30, 0x69, 0x69, 0x4b, 0x8d, 0x3b, 0x12, 0x6d, 0xa7, 0x2f, 0x4c, 0xcf, 0xca, 0xd2, 0x1c, + 0x20, 0xc3, 0x85, 0xa4, 0xcb, 0xb2, 0xf4, 0x51, 0x98, 0xd4, 0x9a, 0x30, 0xcc, 0x0a, 0x59, 0x7a, + 0x01, 0xe6, 0x46, 0x5a, 0x61, 0x9f, 0x80, 0x61, 0x13, 0xfc, 0xd1, 0x03, 0xeb, 0x40, 0x0f, 0xa5, + 0x56, 0x3d, 0x2e, 0x62, 0xa9, 0x05, 0xd4, 0xdc, 0x86, 0xb9, 0xf8, 0xe5, 0x2e, 0xf5, 0x77, 0xf3, + 0x0f, 0xc3, 0x90, 0x29, 0xf9, 0xcc, 0x8b, 0x80, 0xb0, 0xdb, 0x6c, 0x6e, 0x5b, 0xb5, 0xbd, 0x5b, + 0xb6, 0x53, 0x77, 0x0f, 0xd8, 0x5a, 0x59, 0x81, 0x82, 0x27, 0xa2, 0xb8, 0x7c, 0xd1, 0x2c, 0xb5, + 0xd8, 0x64, 0x78, 0x97, 0x8f, 0x43, 0x1c, 0xf3, 0x67, 0x19, 0x98, 0x10, 0x21, 0x87, 0xf7, 0xc1, + 0x05, 0x79, 0x2f, 0xf2, 0x36, 0xb5, 0x9e, 0x4a, 0xa4, 0x64, 0x5f, 0xff, 0x63, 0x3f, 0xe6, 0x7f, + 0xfc, 0x52, 0x3a, 0xec, 0x8e, 0x77, 0x3e, 0x7e, 0x67, 0x0c, 0x66, 0x63, 0x21, 0x9c, 0x54, 0xe3, + 0xe9, 0xf1, 0xb9, 0xbb, 0x91, 0x6a, 0x94, 0xa8, 0x72, 0x8f, 0x3f, 0xde, 0xfd, 0xce, 0x8f, 0x24, + 0x50, 0xbd, 0x9e, 0x5a, 0xee, 0xf5, 0x3f, 0xe7, 0x52, 0x1d, 0xd6, 0x9d, 0xec, 0x7f, 0x1a, 0xf0, + 0x60, 0xdf, 0x48, 0x5f, 0x96, 0x28, 0xc6, 0x8b, 0x42, 0xc5, 0x82, 0x4c, 0x39, 0x9f, 0x81, 0x7a, + 0x28, 0x8a, 0xe7, 0xf6, 0x88, 0xb3, 0x47, 0x4f, 0xc3, 0x14, 0x3b, 0xa1, 0xe9, 0xd6, 0x14, 0x90, + 0xb6, 0xb0, 0x73, 0x33, 0x8b, 0x67, 0x55, 0x2b, 0xc7, 0x11, 0x2c, 0xf3, 0xdb, 0x06, 0x2c, 0xf6, + 0x4b, 0x1b, 0x32, 0xc0, 0xfd, 0xf2, 0xef, 0xc4, 0x7c, 0xa4, 0x8b, 0x3d, 0x3e, 0xd2, 0xb1, 0x1b, + 0xa6, 0x74, 0x87, 0xd6, 0x2e, 0x77, 0xd9, 0x7b, 0xb8, 0x00, 0x7f, 0xcd, 0x80, 0x73, 0x7d, 0x56, + 0x53, 0x8f, 0xaf, 0xbc, 0x71, 0x62, 0x5f, 0xf9, 0xcc, 0xa0, 0xbe, 0xf2, 0xe6, 0x2f, 0xb2, 0x30, + 0x27, 0xe4, 0x09, 0xd5, 0xb4, 0x67, 0x23, 0x9e, 0xe6, 0x1f, 0x88, 0x79, 0x9a, 0x2f, 0xc4, 0xf1, + 0xff, 0xec, 0x66, 0xfe, 0xde, 0x72, 0x33, 0xff, 0x63, 0x06, 0xce, 0x26, 0x66, 0x33, 0x41, 0x5f, + 0x49, 0x38, 0x1a, 0x6e, 0xa5, 0x9c, 0x36, 0x65, 0xc0, 0xc3, 0x61, 0x54, 0xdf, 0xec, 0x6f, 0xea, + 0x3e, 0xd1, 0x7c, 0xab, 0xdf, 0x39, 0x85, 0x04, 0x30, 0x43, 0xba, 0x47, 0x9b, 0xff, 0x30, 0x0b, + 0x8f, 0x0f, 0x4a, 0xe8, 0x3d, 0x1a, 0x3e, 0xe3, 0x47, 0xc2, 0x67, 0xee, 0xd3, 0xb1, 0x7d, 0x2a, + 0x91, 0x34, 0xdf, 0xcd, 0xaa, 0x63, 0xaf, 0x77, 0x7e, 0x0e, 0xf4, 0x28, 0x3a, 0x41, 0x55, 0x3b, + 0x99, 0xe3, 0x34, 0xdc, 0x0a, 0x27, 0xaa, 0xbc, 0xf8, 0x6e, 0xb7, 0x38, 0x1f, 0xc6, 0xd4, 0x8b, + 0x42, 0x2c, 0x2b, 0xa1, 0xc7, 0x21, 0xef, 0x71, 0xa8, 0x0c, 0x18, 0x10, 0x2f, 0xcb, 0xbc, 0x0c, + 0x2b, 0x28, 0xfa, 0xa2, 0xa6, 0x0b, 0x8f, 0x9d, 0x56, 0xea, 0x88, 0xe3, 0x1e, 0xcc, 0x5f, 0x81, + 0xbc, 0x2f, 0xb3, 0x95, 0xf2, 0x57, 0x8d, 0xa7, 0x06, 0x8c, 0x43, 0xa1, 0x37, 0x30, 0x99, 0xba, + 0x94, 0xb7, 0x4f, 0x25, 0x36, 0x55, 0x24, 0x91, 0xa9, 0x2e, 0x3f, 0xdc, 0x54, 0x09, 0x09, 0x17, + 0x9f, 0x5f, 0x1a, 0x30, 0x29, 0x46, 0xeb, 0x3e, 0x84, 0xc6, 0xdc, 0x8e, 0x86, 0xc6, 0x5c, 0x4c, + 0x65, 0xef, 0xe8, 0x13, 0x17, 0x73, 0x1b, 0xa6, 0xf4, 0x84, 0x56, 0xe8, 0x65, 0x6d, 0xef, 0x33, + 0x46, 0x49, 0x11, 0x23, 0x77, 0xc7, 0x70, 0x5f, 0x34, 0xbf, 0x57, 0x50, 0xbd, 0xc8, 0xae, 0x68, + 0xfa, 0x1c, 0x34, 0x8e, 0x9d, 0x83, 0xfa, 0x14, 0xc8, 0xa4, 0x3f, 0x05, 0xae, 0x43, 0x5e, 0x6e, + 0x50, 0xe2, 0x18, 0x7f, 0x54, 0x77, 0x16, 0xa4, 0xba, 0x00, 0x25, 0xa6, 0x4d, 0x5c, 0x76, 0xd5, + 0x52, 0x63, 0xa8, 0x36, 0x4e, 0x45, 0x06, 0xbd, 0x0a, 0x93, 0x07, 0xae, 0xb7, 0xd7, 0x74, 0x2d, + 0x96, 0x87, 0x18, 0xd2, 0x78, 0x9f, 0x52, 0x76, 0x33, 0xee, 0xb1, 0x7d, 0x2b, 0xa4, 0x8f, 0x75, + 0x66, 0xa8, 0x04, 0xb3, 0x2d, 0xdb, 0xc1, 0xc4, 0xaa, 0xab, 0x08, 0x98, 0x31, 0x9e, 0x28, 0x55, + 0x2a, 0xb9, 0x9b, 0x51, 0x30, 0x8e, 0xe3, 0xa3, 0xaf, 0x1a, 0x30, 0xe3, 0x45, 0x2e, 0xd5, 0x22, + 0x1b, 0x62, 0x65, 0xf4, 0xc9, 0x18, 0xbd, 0xa8, 0x73, 0x97, 0xe5, 0x68, 0x39, 0x8e, 0xf1, 0x46, + 0x9f, 0x87, 0xbc, 0x2f, 0xb2, 0x55, 0xa5, 0xf3, 0xb0, 0xa9, 0xae, 0xb0, 0x9c, 0x68, 0x38, 0x94, + 0xb2, 0x04, 0x2b, 0x86, 0x68, 0x03, 0x16, 0xa4, 0x95, 0x20, 0xf2, 0xad, 0x98, 0xf1, 0x30, 0xb9, + 0x09, 0x4e, 0x80, 0xe3, 0xc4, 0x5a, 0x54, 0xa9, 0x62, 0x89, 0xe2, 0xf8, 0x4b, 0x87, 0xf6, 0x38, + 0xc0, 0xd6, 0x5f, 0x1d, 0x0b, 0xe8, 0x71, 0x01, 0x5e, 0xf9, 0x11, 0x02, 0xbc, 0xaa, 0x70, 0x36, + 0x0e, 0x62, 0x59, 0x6b, 0x58, 0xa2, 0x1c, 0xed, 0x30, 0xab, 0x24, 0x21, 0xe1, 0xe4, 0xba, 0xe8, + 0x16, 0x14, 0x3c, 0xc2, 0xae, 0x3b, 0x25, 0xe9, 0x4a, 0x31, 0xb4, 0xd3, 0x18, 0x96, 0x04, 0x70, + 0x48, 0x8b, 0x8e, 0xbb, 0x15, 0x4d, 0x5d, 0x7a, 0x3d, 0xc5, 0xaf, 0xdd, 0x89, 0xb1, 0xef, 0x93, + 0x4d, 0xca, 0x7c, 0x77, 0x06, 0xa6, 0x23, 0xa6, 0x0e, 0xf4, 0x28, 0xe4, 0x58, 0x1a, 0x1f, 0xb6, + 0x5b, 0xe5, 0xc3, 0x1d, 0x95, 0x77, 0x0e, 0x87, 0xa1, 0xaf, 0x1b, 0x30, 0xdb, 0x8e, 0xd8, 0x96, + 0xe5, 0x46, 0x3e, 0xe2, 0xeb, 0x69, 0xd4, 0x60, 0xad, 0x25, 0xfd, 0x8e, 0x32, 0xc3, 0x71, 0xee, + 0x74, 0x3f, 0x10, 0x9e, 0x97, 0x4d, 0xe2, 0x31, 0x6c, 0xa1, 0x72, 0x29, 0x12, 0xab, 0x51, 0x30, + 0x8e, 0xe3, 0xd3, 0x11, 0x66, 0xad, 0x1b, 0xe5, 0x33, 0x58, 0x25, 0x49, 0x00, 0x87, 0xb4, 0xd0, + 0x0b, 0x30, 0x23, 0x32, 0x56, 0x56, 0xdc, 0xfa, 0x65, 0xcb, 0xdf, 0x15, 0x77, 0x0d, 0x75, 0x37, + 0x5a, 0x8d, 0x40, 0x71, 0x0c, 0x9b, 0xb5, 0x2d, 0x4c, 0x0b, 0xca, 0x08, 0x8c, 0x47, 0x73, 0xa2, + 0xaf, 0x46, 0xc1, 0x38, 0x8e, 0x8f, 0x9e, 0xd0, 0x8e, 0x21, 0xfe, 0xfa, 0xa8, 0x76, 0x83, 0x84, + 0xa3, 0xa8, 0x04, 0xb3, 0x1d, 0x76, 0x35, 0xab, 0x4b, 0xa0, 0x58, 0x8f, 0x8a, 0xe1, 0x8d, 0x28, + 0x18, 0xc7, 0xf1, 0xd1, 0x73, 0x30, 0xed, 0xd1, 0xcd, 0x56, 0x11, 0xe0, 0x4f, 0x92, 0xea, 0xc5, + 0x09, 0xeb, 0x40, 0x1c, 0xc5, 0x45, 0x2f, 0xc2, 0x7c, 0x98, 0xe0, 0x4d, 0x12, 0xe0, 0x6f, 0x94, + 0x2a, 0xdb, 0x50, 0x29, 0x8e, 0x80, 0x7b, 0xeb, 0xa0, 0xbf, 0x07, 0x73, 0x5a, 0x4f, 0xac, 0x3b, + 0x75, 0x72, 0x47, 0x24, 0xe1, 0x62, 0x9f, 0xaf, 0x58, 0x8d, 0xc1, 0x70, 0x0f, 0x36, 0xfa, 0x18, + 0xcc, 0xd4, 0xdc, 0x66, 0x93, 0xed, 0x71, 0x3c, 0x1f, 0x37, 0xcf, 0xb6, 0xc5, 0xf3, 0x92, 0x45, + 0x20, 0x38, 0x86, 0x89, 0xae, 0x00, 0x72, 0xb7, 0x7d, 0xe2, 0xed, 0x93, 0xfa, 0x8b, 0xfc, 0xc3, + 0xba, 0x54, 0xe3, 0x98, 0x8e, 0xfa, 0x7d, 0x5f, 0xeb, 0xc1, 0xc0, 0x09, 0xb5, 0x58, 0xb2, 0x22, + 0x2d, 0x4e, 0x6e, 0x26, 0x8d, 0x4f, 0x42, 0xc5, 0x0d, 0x09, 0xf7, 0x0c, 0x92, 0xf3, 0x60, 0x9c, + 0xbb, 0xe1, 0xa7, 0x93, 0x76, 0x4b, 0x4f, 0xcd, 0x1b, 0x9e, 0x11, 0xbc, 0x14, 0x0b, 0x4e, 0xe8, + 0x0b, 0x50, 0xd8, 0x96, 0x79, 0xda, 0x59, 0xae, 0xad, 0x91, 0xcf, 0xc5, 0xd8, 0x27, 0x07, 0xc2, + 0x8b, 0xb2, 0x02, 0xe0, 0x90, 0x25, 0x7a, 0x0c, 0x26, 0x2f, 0x57, 0x4a, 0x6a, 0x16, 0xce, 0xb3, + 0xd1, 0x1f, 0xa3, 0x55, 0xb0, 0x0e, 0xa0, 0x2b, 0x4c, 0xa9, 0x6f, 0x88, 0x0d, 0x71, 0x78, 0xde, + 0xf6, 0x6a, 0x63, 0x14, 0x9b, 0x3d, 0xb2, 0xe2, 0xea, 0xe2, 0x99, 0x18, 0xb6, 0x28, 0xc7, 0x0a, + 0x03, 0xbd, 0x02, 0x93, 0xe2, 0xbc, 0x60, 0x7b, 0xd3, 0xc2, 0xc9, 0x62, 0x30, 0x71, 0x48, 0x02, + 0xeb, 0xf4, 0xd8, 0xdb, 0x19, 0x4b, 0x5f, 0x4d, 0x2e, 0x75, 0x9a, 0xcd, 0xc5, 0xb3, 0x6c, 0xdf, + 0x0c, 0xdf, 0xce, 0x42, 0x10, 0xd6, 0xf1, 0xd0, 0x53, 0xd2, 0x1f, 0xe4, 0x7d, 0x91, 0xc7, 0x44, + 0xe5, 0x0f, 0xa2, 0x94, 0xee, 0x3e, 0x6e, 0xda, 0xe7, 0xee, 0xe1, 0x88, 0xb1, 0x0d, 0x4b, 0x52, + 0xe3, 0xeb, 0x5d, 0x24, 0x8b, 0x8b, 0x11, 0xa3, 0xc5, 0xd2, 0xad, 0xbe, 0x98, 0xf8, 0x18, 0x2a, + 0x68, 0x1b, 0xb2, 0x56, 0x73, 0x7b, 0xf1, 0xc1, 0x34, 0x54, 0x57, 0xf5, 0xa1, 0x6c, 0xee, 0x5a, + 0x55, 0xda, 0x28, 0x63, 0x4a, 0xdc, 0x7c, 0x23, 0xa3, 0x1e, 0x09, 0x54, 0x3a, 0xd2, 0xd7, 0xf4, + 0x59, 0x6d, 0xa4, 0xf1, 0x21, 0xd8, 0x9e, 0x8f, 0x19, 0xf0, 0x03, 0x29, 0x71, 0x4e, 0xb7, 0xd5, + 0x3a, 0x4e, 0x25, 0x3b, 0x4c, 0x34, 0xd5, 0x2a, 0xbf, 0x5c, 0x46, 0x57, 0xb1, 0xf9, 0x9b, 0xbc, + 0xb2, 0x89, 0xc5, 0x1c, 0x1c, 0x3c, 0xc8, 0xd9, 0x7e, 0x60, 0xbb, 0x29, 0xc6, 0x0b, 0xc6, 0x72, + 0x94, 0x32, 0x77, 0x64, 0x06, 0xc0, 0x9c, 0x15, 0xe5, 0xe9, 0x34, 0x6c, 0xe7, 0x8e, 0x68, 0xfe, + 0xf5, 0xd4, 0x3d, 0x17, 0x38, 0x4f, 0x06, 0xc0, 0x9c, 0x15, 0xba, 0xcd, 0x67, 0x5a, 0x3a, 0x1f, + 0xfd, 0x8d, 0x7f, 0xcb, 0x3b, 0x3a, 0xe3, 0x28, 0x2f, 0xbf, 0x65, 0x0b, 0x1d, 0x66, 0x44, 0x5e, + 0xd5, 0xcd, 0xf5, 0x24, 0x5e, 0xd5, 0xcd, 0x75, 0x4c, 0x99, 0xa0, 0xb7, 0x0c, 0x00, 0x4b, 0x7d, + 0xd4, 0x3a, 0x9d, 0x2f, 0x7f, 0xf4, 0xfb, 0x48, 0x36, 0xf7, 0x68, 0x0b, 0xa1, 0x58, 0xe3, 0x8c, + 0x5e, 0x85, 0x09, 0x8b, 0x7f, 0xb7, 0x48, 0x38, 0x67, 0xa6, 0xf3, 0x31, 0xae, 0x98, 0x04, 0xcc, + 0x2b, 0x55, 0x80, 0xb0, 0x64, 0x48, 0x79, 0x07, 0x9e, 0x45, 0x76, 0xec, 0x3d, 0xe1, 0xa5, 0x59, + 0x1d, 0x39, 0xfd, 0x38, 0x25, 0x96, 0xc4, 0x5b, 0x80, 0xb0, 0x64, 0xc8, 0xbf, 0x23, 0x6b, 0x39, + 0x96, 0x0a, 0xb9, 0x49, 0x27, 0x30, 0x4b, 0x0f, 0xe2, 0xd1, 0xbe, 0x23, 0xab, 0x33, 0xc2, 0x51, + 0xbe, 0x68, 0x1f, 0xc6, 0x2d, 0xf6, 0x45, 0x35, 0x71, 0x3f, 0xc2, 0x69, 0x7c, 0x9d, 0x2d, 0xd6, + 0x07, 0x6c, 0x73, 0x11, 0xdf, 0x6d, 0x13, 0xdc, 0xcc, 0xdf, 0x67, 0x01, 0x98, 0x08, 0x3c, 0xfc, + 0xbc, 0xc5, 0x52, 0x16, 0xee, 0xba, 0xf5, 0x74, 0x3e, 0x12, 0xa7, 0x47, 0x91, 0x83, 0xc8, 0x4f, + 0xb8, 0xeb, 0xd6, 0xb1, 0x60, 0x82, 0x1a, 0x30, 0xd6, 0xb6, 0x82, 0xdd, 0xf4, 0x43, 0xd6, 0xf3, + 0x3c, 0x0e, 0x2b, 0xd8, 0xc5, 0x8c, 0x01, 0x7a, 0xdd, 0x80, 0x09, 0x1e, 0xb4, 0x2e, 0x2d, 0xee, + 0x23, 0x3f, 0x2b, 0xcb, 0x3e, 0x5b, 0xe6, 0x91, 0xf1, 0xc2, 0xf5, 0x43, 0x1d, 0xc9, 0xa2, 0x14, + 0x4b, 0xb6, 0x4b, 0x6f, 0x1a, 0x30, 0xa5, 0xa3, 0x26, 0x38, 0x6d, 0x7c, 0x46, 0x77, 0xda, 0x48, + 0xb3, 0x3f, 0x74, 0xff, 0x8f, 0xff, 0x63, 0x80, 0xf6, 0xd5, 0xdf, 0xd0, 0x65, 0xd3, 0x18, 0xd8, + 0x65, 0x33, 0x33, 0xa4, 0xcb, 0x66, 0x76, 0x28, 0x97, 0xcd, 0xb1, 0xe1, 0x5d, 0x36, 0x73, 0xfd, + 0x5d, 0x36, 0xcd, 0xb7, 0x0d, 0x98, 0xef, 0xd9, 0x87, 0xa9, 0xda, 0xe6, 0xb9, 0x6e, 0xd0, 0xc7, + 0x53, 0x0a, 0x87, 0x20, 0xac, 0xe3, 0xa1, 0x35, 0x98, 0x13, 0x09, 0xba, 0xab, 0xed, 0xa6, 0x9d, + 0x98, 0x4e, 0x60, 0x2b, 0x06, 0xc7, 0x3d, 0x35, 0xcc, 0xff, 0x60, 0xc0, 0xa4, 0x16, 0x84, 0x48, + 0xdb, 0xc1, 0x82, 0x35, 0x85, 0x18, 0x61, 0x6e, 0x72, 0xf6, 0xc2, 0xc1, 0x61, 0xfc, 0xb1, 0xad, + 0xa1, 0xa5, 0x6f, 0x0d, 0x1f, 0xdb, 0x68, 0x29, 0x16, 0x50, 0x9e, 0x98, 0x93, 0xb4, 0x59, 0xa7, + 0x67, 0xf5, 0xc4, 0x9c, 0xa4, 0x8d, 0x19, 0x84, 0xb1, 0xa3, 0xfa, 0xab, 0xf0, 0xe6, 0xd5, 0x52, + 0xa1, 0x5b, 0x5e, 0x80, 0x39, 0x0c, 0x9d, 0x87, 0x2c, 0x71, 0xea, 0xe2, 0xb2, 0xad, 0x3e, 0x3f, + 0x76, 0xd1, 0xa9, 0x63, 0x5a, 0x6e, 0x5e, 0x83, 0xa9, 0x2a, 0xa9, 0x79, 0x24, 0x78, 0x89, 0x1c, + 0x0e, 0xfc, 0x3d, 0x33, 0x3a, 0xdb, 0x63, 0xdf, 0x33, 0xa3, 0xd5, 0x69, 0xb9, 0xf9, 0xaf, 0x0d, + 0x88, 0xe5, 0xeb, 0xd7, 0x0c, 0xef, 0x46, 0x3f, 0xc3, 0x7b, 0xc4, 0x44, 0x9c, 0x39, 0xd6, 0x44, + 0x7c, 0x05, 0x50, 0x8b, 0x2e, 0x85, 0xc8, 0xd7, 0x29, 0x84, 0x9d, 0x23, 0x0c, 0x79, 0xee, 0xc1, + 0xc0, 0x09, 0xb5, 0xcc, 0x7f, 0xc5, 0x85, 0xd5, 0x33, 0xf8, 0xdf, 0xbb, 0x03, 0x3a, 0x90, 0x63, + 0xa4, 0x84, 0xb1, 0x67, 0x44, 0x43, 0x69, 0x6f, 0xea, 0x90, 0x70, 0x20, 0xc5, 0x92, 0x67, 0xdc, + 0xcc, 0x5f, 0x70, 0x59, 0xb5, 0x14, 0xff, 0x03, 0xc8, 0xda, 0x8a, 0xca, 0x7a, 0x39, 0xad, 0xbd, + 0x32, 0x59, 0x46, 0xb4, 0x0c, 0xd0, 0x26, 0x5e, 0x8d, 0x38, 0x81, 0x74, 0x32, 0xcf, 0x89, 0xa0, + 0x20, 0x55, 0x8a, 0x35, 0x0c, 0xf3, 0x3b, 0x06, 0xcc, 0xc5, 0x3d, 0xf6, 0xd3, 0x76, 0x34, 0x8b, + 0x84, 0x15, 0x66, 0x87, 0x0f, 0x2b, 0x34, 0x5f, 0xa7, 0x42, 0x06, 0x76, 0x6d, 0xcf, 0x76, 0x78, + 0x24, 0xde, 0x8e, 0xdd, 0xa0, 0x42, 0x12, 0xf1, 0x3d, 0x31, 0x6e, 0x23, 0x54, 0x42, 0xca, 0xcf, + 0x88, 0x49, 0x38, 0x2a, 0xc1, 0xac, 0x7c, 0x19, 0x91, 0x86, 0x5d, 0x1e, 0x41, 0xac, 0x0c, 0x49, + 0x6b, 0x51, 0x30, 0x8e, 0xe3, 0x9b, 0x5f, 0x84, 0x49, 0xed, 0x10, 0x60, 0xfb, 0xe5, 0x1d, 0xab, + 0x16, 0xc4, 0xf7, 0x99, 0x8b, 0xb4, 0x10, 0x73, 0x18, 0xb3, 0x3f, 0x73, 0x57, 0xe9, 0xd8, 0x3e, + 0x23, 0x1c, 0xa4, 0x05, 0x94, 0x12, 0xf3, 0x48, 0x83, 0xdc, 0x91, 0xd9, 0x6c, 0x25, 0x31, 0x4c, + 0x0b, 0x31, 0x87, 0x99, 0x4f, 0x40, 0x5e, 0xe6, 0x79, 0x60, 0xc1, 0xd2, 0xd2, 0x36, 0xaa, 0x07, + 0x4b, 0xbb, 0x5e, 0x80, 0x19, 0xc4, 0xbc, 0x09, 0x79, 0x99, 0x8e, 0xe2, 0xde, 0xd8, 0x74, 0xe9, + 0xfb, 0x8e, 0x7d, 0xd9, 0xf5, 0x03, 0x99, 0x43, 0x83, 0x3f, 0xdf, 0x5c, 0x5d, 0x67, 0x65, 0x58, + 0x41, 0xcd, 0x79, 0x98, 0x55, 0xef, 0x32, 0xc2, 0x77, 0xf5, 0xc7, 0x59, 0x98, 0x8a, 0x7c, 0xa2, + 0xfb, 0xde, 0x6b, 0x62, 0xf0, 0xad, 0x26, 0xe1, 0x7d, 0x25, 0x3b, 0xe4, 0xfb, 0x8a, 0xfe, 0xa0, + 0x35, 0x76, 0xba, 0x0f, 0x5a, 0xb9, 0x74, 0x1e, 0xb4, 0x02, 0x98, 0xf0, 0xc5, 0x69, 0x3a, 0x9e, + 0x86, 0xa5, 0x29, 0x36, 0x62, 0x5c, 0x81, 0x97, 0x87, 0xb2, 0x64, 0x65, 0xfe, 0x20, 0x07, 0x33, + 0xd1, 0x44, 0x5c, 0x03, 0x8c, 0xe4, 0x13, 0x3d, 0x23, 0x39, 0xa4, 0x41, 0x37, 0x3b, 0xaa, 0x41, + 0x77, 0x6c, 0x54, 0x83, 0x6e, 0xee, 0x04, 0x06, 0xdd, 0x5e, 0x73, 0xec, 0xf8, 0xc0, 0xe6, 0xd8, + 0xe7, 0x95, 0x73, 0xd4, 0x44, 0xc4, 0x9b, 0x20, 0x74, 0x8e, 0x42, 0xd1, 0x61, 0x58, 0x75, 0xeb, + 0x89, 0x4e, 0x66, 0xf9, 0x7b, 0x18, 0xae, 0xbc, 0x44, 0x5f, 0xa6, 0xe1, 0xdf, 0x8c, 0xde, 0x37, + 0x84, 0x1f, 0xd3, 0x33, 0x30, 0x29, 0xe6, 0x13, 0x53, 0xe8, 0x20, 0xaa, 0x0c, 0x56, 0x43, 0x10, + 0xd6, 0xf1, 0xd8, 0xe7, 0x56, 0xa3, 0xdf, 0x97, 0x65, 0xf6, 0x71, 0xfd, 0x73, 0xab, 0xb1, 0xef, + 0xd1, 0xc6, 0xf1, 0xcd, 0xcf, 0xc3, 0xd9, 0xc4, 0xeb, 0x2a, 0xb3, 0xdf, 0x31, 0x5d, 0x83, 0xd4, + 0x05, 0x82, 0x26, 0x46, 0x2c, 0x4f, 0xf3, 0xd2, 0xad, 0xbe, 0x98, 0xf8, 0x18, 0x2a, 0xe6, 0xf7, + 0xb3, 0x30, 0x13, 0xfd, 0x56, 0x17, 0x3a, 0x50, 0xc6, 0xad, 0x54, 0xec, 0x6a, 0x9c, 0xac, 0x96, + 0xdc, 0xa9, 0xaf, 0xa5, 0xfa, 0x80, 0xcd, 0xaf, 0x6d, 0x95, 0x69, 0xea, 0xf4, 0x18, 0x0b, 0x13, + 0xb1, 0x60, 0xc7, 0x3e, 0xc7, 0x15, 0x46, 0xb8, 0x88, 0xbb, 0x61, 0xea, 0xdc, 0xc3, 0x98, 0x15, + 0xc5, 0x0a, 0x6b, 0x6c, 0xe9, 0xd9, 0xb2, 0x4f, 0x3c, 0x7b, 0xc7, 0x56, 0xdf, 0x19, 0x65, 0x3b, + 0xf7, 0x4d, 0x51, 0x86, 0x15, 0xd4, 0x7c, 0x3d, 0x03, 0xe1, 0x57, 0x95, 0xd9, 0x07, 0x6d, 0x7c, + 0x4d, 0x0f, 0x17, 0xc3, 0x76, 0x65, 0xd4, 0xaf, 0x46, 0x85, 0x14, 0x85, 0xe3, 0xaa, 0x56, 0x82, + 0x23, 0x1c, 0xff, 0x04, 0x5f, 0x53, 0xb6, 0x60, 0x36, 0x16, 0x77, 0x9c, 0x7a, 0x90, 0xc1, 0xef, + 0xb2, 0x50, 0x50, 0x91, 0xdb, 0xe8, 0xa3, 0x11, 0xa3, 0x48, 0xa1, 0xfc, 0x7e, 0xed, 0x6b, 0x0b, + 0xbb, 0x6e, 0xfd, 0x6e, 0xb7, 0x38, 0xab, 0x90, 0x63, 0x06, 0x8e, 0xf3, 0x90, 0xed, 0x78, 0xcd, + 0xf8, 0xad, 0xe7, 0x06, 0xde, 0xc0, 0xb4, 0x1c, 0xdd, 0x89, 0x5b, 0x25, 0x36, 0x53, 0x8a, 0x36, + 0xe7, 0xd7, 0x83, 0xfe, 0xd6, 0x08, 0x7a, 0x4a, 0x6e, 0xbb, 0xf5, 0xc3, 0xf8, 0xd7, 0x19, 0xca, + 0x6e, 0xfd, 0x10, 0x33, 0x08, 0x7a, 0x01, 0x66, 0x02, 0xbb, 0x45, 0xdc, 0x4e, 0xa0, 0x7f, 0xb3, + 0x36, 0x1b, 0xbe, 0xbc, 0x6e, 0x45, 0xa0, 0x38, 0x86, 0x4d, 0x4f, 0xd9, 0xdb, 0xbe, 0xeb, 0xb0, + 0x94, 0x8b, 0xe3, 0xd1, 0x67, 0x9a, 0x2b, 0xd5, 0x6b, 0x57, 0x99, 0x71, 0x46, 0x61, 0x50, 0x6c, + 0x9b, 0x85, 0x49, 0x7a, 0x44, 0x38, 0x3e, 0xcc, 0x85, 0xda, 0x36, 0x2f, 0xc7, 0x0a, 0x03, 0xad, + 0x71, 0xda, 0x54, 0x5a, 0x76, 0xa2, 0x4c, 0x95, 0x1f, 0x97, 0x74, 0x69, 0xd9, 0xdd, 0x6e, 0x71, + 0x91, 0x38, 0x35, 0xb7, 0x6e, 0x3b, 0x8d, 0x15, 0x8a, 0xb8, 0x8c, 0xad, 0x03, 0x79, 0xd4, 0xa8, + 0x9a, 0xe6, 0x0d, 0x98, 0x8d, 0x75, 0x98, 0xbc, 0xa5, 0x1a, 0xc9, 0xb7, 0xd4, 0xc1, 0x3e, 0xa8, + 0xf0, 0x6f, 0x0d, 0x98, 0xef, 0xd9, 0x02, 0x06, 0x8d, 0xa1, 0x89, 0x1f, 0x46, 0x99, 0x93, 0x1f, + 0x46, 0xd9, 0xe1, 0x0e, 0xa3, 0xf2, 0xf6, 0x4f, 0xdf, 0xbd, 0xf0, 0xc0, 0xcf, 0xdf, 0xbd, 0xf0, + 0xc0, 0xaf, 0xde, 0xbd, 0xf0, 0xc0, 0xeb, 0x47, 0x17, 0x8c, 0x9f, 0x1e, 0x5d, 0x30, 0x7e, 0x7e, + 0x74, 0xc1, 0xf8, 0xd5, 0xd1, 0x05, 0xe3, 0x7f, 0x1c, 0x5d, 0x30, 0xde, 0xfe, 0xdd, 0x85, 0x07, + 0x5e, 0x7e, 0x3e, 0x9c, 0xa0, 0x2b, 0x72, 0x82, 0xb2, 0x1f, 0x1f, 0x92, 0xd3, 0x71, 0xa5, 0xbd, + 0xd7, 0x58, 0xa1, 0x13, 0x74, 0x45, 0x95, 0xc8, 0x09, 0xfa, 0x97, 0x01, 0x00, 0x00, 0xff, 0xff, + 0x62, 0x60, 0xad, 0x52, 0xed, 0x96, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -6898,6 +6930,18 @@ func (m *MetricProvider) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.SkyWalking != nil { + { + size, err := m.SkyWalking.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } if m.Influxdb != nil { { size, err := m.Influxdb.MarshalToSizedBuffer(dAtA[:i]) @@ -8963,6 +9007,44 @@ func (m *SetMirrorRoute) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SkyWalkingMetric) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SkyWalkingMetric) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SkyWalkingMetric) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Interval) + copy(dAtA[i:], m.Interval) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Interval))) + i-- + dAtA[i] = 0x1a + i -= len(m.Query) + copy(dAtA[i:], m.Query) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Query))) + i-- + dAtA[i] = 0x12 + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *StickinessConfig) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -10842,6 +10924,10 @@ func (m *MetricProvider) Size() (n int) { l = m.Influxdb.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.SkyWalking != nil { + l = m.SkyWalking.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -11545,6 +11631,21 @@ func (m *SetMirrorRoute) Size() (n int) { return n } +func (m *SkyWalkingMetric) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Query) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Interval) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *StickinessConfig) Size() (n int) { if m == nil { return 0 @@ -12687,6 +12788,7 @@ func (this *MetricProvider) String() string { `CloudWatch:` + strings.Replace(this.CloudWatch.String(), "CloudWatchMetric", "CloudWatchMetric", 1) + `,`, `Graphite:` + strings.Replace(this.Graphite.String(), "GraphiteMetric", "GraphiteMetric", 1) + `,`, `Influxdb:` + strings.Replace(this.Influxdb.String(), "InfluxdbMetric", "InfluxdbMetric", 1) + `,`, + `SkyWalking:` + strings.Replace(this.SkyWalking.String(), "SkyWalkingMetric", "SkyWalkingMetric", 1) + `,`, `}`, }, "") return s @@ -13258,6 +13360,18 @@ func (this *SetMirrorRoute) String() string { }, "") return s } +func (this *SkyWalkingMetric) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SkyWalkingMetric{`, + `Address:` + fmt.Sprintf("%v", this.Address) + `,`, + `Query:` + fmt.Sprintf("%v", this.Query) + `,`, + `Interval:` + fmt.Sprintf("%v", this.Interval) + `,`, + `}`, + }, "") + return s +} func (this *StickinessConfig) String() string { if this == nil { return "nil" @@ -23659,6 +23773,42 @@ func (m *MetricProvider) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SkyWalking", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SkyWalking == nil { + m.SkyWalking = &SkyWalkingMetric{} + } + if err := m.SkyWalking.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -29986,6 +30136,152 @@ func (m *SetMirrorRoute) Unmarshal(dAtA []byte) error { } return nil } +func (m *SkyWalkingMetric) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SkyWalkingMetric: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SkyWalkingMetric: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Interval", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Interval = DurationString(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *StickinessConfig) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index f3c053cf36..e4ab3567e6 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -976,6 +976,9 @@ message MetricProvider { // Influxdb specifies the influxdb metric to query optional InfluxdbMetric influxdb = 10; + + // SkyWalking specifies the skywalking metric to query + optional SkyWalkingMetric skywalking = 11; } // MetricResult contain a list of the most recent measurements for a single metric along with @@ -1574,6 +1577,14 @@ message SetMirrorRoute { optional int32 percentage = 4; } +message SkyWalkingMetric { + optional string address = 1; + + optional string query = 2; + + optional string interval = 3; +} + message StickinessConfig { optional bool enabled = 1; diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 087acdcb83..28259bcb16 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -123,6 +123,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale": schema_pkg_apis_rollouts_v1alpha1_SetCanaryScale(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRoute": schema_pkg_apis_rollouts_v1alpha1_SetHeaderRoute(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetMirrorRoute": schema_pkg_apis_rollouts_v1alpha1_SetMirrorRoute(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SkyWalkingMetric": schema_pkg_apis_rollouts_v1alpha1_SkyWalkingMetric(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StickinessConfig": schema_pkg_apis_rollouts_v1alpha1_StickinessConfig(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch": schema_pkg_apis_rollouts_v1alpha1_StringMatch(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TCPRoute": schema_pkg_apis_rollouts_v1alpha1_TCPRoute(ref), @@ -2925,11 +2926,17 @@ func schema_pkg_apis_rollouts_v1alpha1_MetricProvider(ref common.ReferenceCallba Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.InfluxdbMetric"), }, }, + "skywalking": { + SchemaProps: spec.SchemaProps{ + Description: "SkyWalking specifies the skywalking metric to query", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SkyWalkingMetric"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.CloudWatchMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DatadogMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.GraphiteMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.InfluxdbMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.JobMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.KayentaMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NewRelicMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WavefrontMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetric"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.CloudWatchMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DatadogMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.GraphiteMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.InfluxdbMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.JobMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.KayentaMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NewRelicMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SkyWalkingMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WavefrontMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetric"}, } } @@ -4662,6 +4669,36 @@ func schema_pkg_apis_rollouts_v1alpha1_SetMirrorRoute(ref common.ReferenceCallba } } +func schema_pkg_apis_rollouts_v1alpha1_SkyWalkingMetric(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "address": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "query": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "interval": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_StickinessConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index dad43fb3e0..03da6695aa 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1663,6 +1663,11 @@ func (in *MetricProvider) DeepCopyInto(out *MetricProvider) { *out = new(InfluxdbMetric) **out = **in } + if in.SkyWalking != nil { + in, out := &in.SkyWalking, &out.SkyWalking + *out = new(SkyWalkingMetric) + **out = **in + } return } @@ -2538,6 +2543,22 @@ func (in *SetMirrorRoute) DeepCopy() *SetMirrorRoute { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SkyWalkingMetric) DeepCopyInto(out *SkyWalkingMetric) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SkyWalkingMetric. +func (in *SkyWalkingMetric) DeepCopy() *SkyWalkingMetric { + if in == nil { + return nil + } + out := new(SkyWalkingMetric) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StickinessConfig) DeepCopyInto(out *StickinessConfig) { *out = *in diff --git a/utils/analysis/factory.go b/utils/analysis/factory.go index 0fb57030f5..2a7dd0b7e1 100644 --- a/utils/analysis/factory.go +++ b/utils/analysis/factory.go @@ -225,6 +225,9 @@ func ValidateMetric(metric v1alpha1.Metric) error { if metric.Provider.Influxdb != nil { numProviders++ } + if metric.Provider.SkyWalking != nil { + numProviders++ + } if numProviders == 0 { return fmt.Errorf("no provider specified") } diff --git a/utils/evaluate/evaluate_test.go b/utils/evaluate/evaluate_test.go index c1a6c1b064..e058d2aa4b 100644 --- a/utils/evaluate/evaluate_test.go +++ b/utils/evaluate/evaluate_test.go @@ -126,8 +126,18 @@ func TestErrorWithInvalidReference(t *testing.T) { } func TestEvaluateArray(t *testing.T) { - floats := []float64{float64(2), float64(2)} - b, err := EvalCondition(floats, "all(result, {# > 1})") + floats := map[string]interface{}{ + "service_apdex": map[string]interface{}{ + "label": nil, + "values": map[string]interface{}{ + "values": []interface{}{float64(2), float64(2)}, + }, + }, + } + b, err := EvalCondition(floats, "all(result.service_apdex.values.values, {# > 1})") + if err != nil { + panic(err) + } assert.Nil(t, err) assert.True(t, b) } From b4bd58769c4b46f46edc2bbbfa0e16aa65d342e4 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 20 Dec 2022 12:54:12 -0600 Subject: [PATCH 37/90] docs: fix rendering by upgrading deps (#2495) * fix formating for spec Signed-off-by: zachaller * fix formating for spec Signed-off-by: zachaller * fix formating for spec Signed-off-by: zachaller * bump version Signed-off-by: zachaller * bump version Signed-off-by: zachaller * bump docs reqs Signed-off-by: zachaller * bump docs reqs Signed-off-by: zachaller * bump docs reqs Signed-off-by: zachaller * bump docs reqs Signed-off-by: zachaller * bump docs reqs Signed-off-by: zachaller * bump docs reqs Signed-off-by: zachaller * undo changes Signed-off-by: zachaller * undo changes Signed-off-by: zachaller Signed-off-by: zachaller --- docs/requirements.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 41bf890b0c..4cb80608b2 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,6 @@ -mkdocs==1.2.3 -mkdocs-material==8.1.9 -markdown_include==0.6.0 -pygments==2.11.2 -jinja2==3.0.3 +mkdocs==1.4.2 +mkdocs-material==8.5.11 +markdown_include==0.8.0 +pygments==2.13.0 +jinja2==3.1.2 markdown==3.3.7 From 9d222de2be6fb6c9218aaa75c4a80698e450c64f Mon Sep 17 00:00:00 2001 From: pashavictorovich Date: Fri, 30 Dec 2022 17:03:49 +0200 Subject: [PATCH 38/90] change version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 26aaba0e86..88c5fb891d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.0 +1.4.0 From 6454e220ad9dd5db3832b24d4a7af4a253fa6d66 Mon Sep 17 00:00:00 2001 From: pashavictorovich Date: Fri, 30 Dec 2022 17:51:38 +0200 Subject: [PATCH 39/90] change version --- .github/workflows/release.yaml | 66 ++++++---------------------------- 1 file changed, 11 insertions(+), 55 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5886e36182..abcf781290 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -90,6 +90,8 @@ jobs: platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.controller-meta.outputs.tags }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache - name: Build and push (plugin-image) uses: docker/build-push-action@v3 @@ -99,7 +101,16 @@ jobs: platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.plugin-meta.outputs.tags }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + # Temp fix + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache release-artifacts: permissions: @@ -121,7 +132,6 @@ jobs: - name: Generate release artifacts run: | make release-plugins - make checksums make manifests IMAGE_TAG=${{ github.event.inputs.tag }} - name: Generate SBOM (spdx) @@ -155,55 +165,6 @@ jobs: cd /tmp && tar -zcf sbom.tar.gz *.spdx - - name: Login to Quay.io - if: github.event_name != 'pull_request' - uses: docker/login-action@v2 - with: - registry: quay.io - username: ${{ secrets.QUAY_USERNAME }} - password: ${{ secrets.QUAY_ROBOT_TOKEN }} - - - name: Install cosign - uses: sigstore/cosign-installer@main - with: - cosign-release: 'v1.13.1' - - - name: Install crane to get digest of image - uses: imjasonh/setup-crane@v0.2 - - - name: Get digest of controller-image - run: | - echo "CONTROLLER_DIGEST=$(crane digest quay.io/argoproj/argo-rollouts:${{ github.event.inputs.tag }})" >> $GITHUB_ENV - - - name: Get digest of plugin-image - run: | - echo "PLUGIN_DIGEST=$(crane digest quay.io/argoproj/kubectl-argo-rollouts:${{ github.event.inputs.tag }})" >> $GITHUB_ENV - - - name: Sign Argo Rollouts Images - run: | - cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argo-rollouts@${{ env.CONTROLLER_DIGEST }} - cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/kubectl-argo-rollouts@${{ env.PLUGIN_DIGEST }} - env: - COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}} - COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} - - - name: Sign checksums and create public key for release assets - run: | - cosign sign-blob --key env://COSIGN_PRIVATE_KEY ./dist/argo-rollouts-checksums.txt > ./dist/argo-rollouts-checksums.sig - cosign public-key --key env://COSIGN_PRIVATE_KEY > ./dist/argo-rollouts-cosign.pub - cosign sign-blob --key env://COSIGN_PRIVATE_KEY /tmp/sbom.tar.gz > /tmp/sbom.tar.gz.sig - # Displays the public key to share. - cosign public-key --key env://COSIGN_PRIVATE_KEY - env: - COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}} - COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} - - - name: update stable tag for docs - run: | - git tag -f stable ${{ github.event.inputs.tag }} - git push -f origin stable - if: ${{ inputs.update_stable_tag }} - - name: Draft release uses: softprops/action-gh-release@v1 with: @@ -213,17 +174,12 @@ jobs: dist/kubectl-argo-rollouts-linux-amd64 dist/kubectl-argo-rollouts-linux-arm64 dist/kubectl-argo-rollouts-darwin-amd64 - dist/kubectl-argo-rollouts-darwin-arm64 dist/kubectl-argo-rollouts-windows-amd64 - dist/argo-rollouts-checksums.txt - dist/argo-rollouts-checksums.sig - dist/argo-rollouts-cosign.pub manifests/dashboard-install.yaml manifests/install.yaml manifests/namespace-install.yaml manifests/notifications-install.yaml docs/features/kustomize/rollout_cr_schema.json /tmp/sbom.tar.gz - /tmp/sbom.tar.gz.sig env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From ae9fdb427d81efe9f9de6235458df404d7f65d26 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 28 Apr 2023 09:46:35 -0500 Subject: [PATCH 40/90] docs: copy argo cd docs drop down fix (#2731) copy argo rollouts drop down fix for docs Signed-off-by: zachaller --- docs/assets/versions.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/assets/versions.js b/docs/assets/versions.js index 057ce03158..1336443d1a 100644 --- a/docs/assets/versions.js +++ b/docs/assets/versions.js @@ -9,16 +9,6 @@ setTimeout(function() { caret.innerHTML = "" caret.classList.add('dropdown-caret') div.querySelector('.rst-current-version').appendChild(caret); - div.querySelector('.rst-current-version').addEventListener('click', function() { - const classes = container.className.split(' '); - const index = classes.indexOf('shift-up'); - if (index === -1) { - classes.push('shift-up'); - } else { - classes.splice(index, 1); - } - container.className = classes.join(' '); - }); } var CSSLink = document.createElement('link'); From 1c225f99a40cb5906832898c6730cc4b11c519f2 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 14 Apr 2023 12:47:03 -0500 Subject: [PATCH 41/90] docs: fix link to plugins for traffic routers (#2719) fix docs link Signed-off-by: zachaller --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index f8159bd5d9..c7cdabc426 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -51,7 +51,7 @@ nav: - AWS ALB: features/traffic-management/alb.md - Istio: features/traffic-management/istio.md - NGINX: features/traffic-management/nginx.md - - Plugins: traffic-management/plugins.md + - Plugins: features/traffic-management/plugins.md - SMI: features/traffic-management/smi.md - Traefik: features/traffic-management/traefik.md - Analysis: From b81d682922a7393648d00a576642ee86634ac80d Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 28 Apr 2023 12:23:42 -0500 Subject: [PATCH 42/90] chore: bump k8s deps to v0.25.8 (#2712) * bump to v0.24.12 Signed-off-by: zachaller * bump to v0.26.3 Signed-off-by: zachaller * bump to v0.25.8 Signed-off-by: zachaller * add new interface functions Signed-off-by: zachaller * fix wrong dep inclusion Signed-off-by: zachaller --------- Signed-off-by: zachaller --- .../features/kustomize/rollout_cr_schema.json | 275 ++++++++ go.mod | 139 ++-- go.sum | 596 +++--------------- manifests/crds/analysis-run-crd.yaml | 56 ++ manifests/crds/analysis-template-crd.yaml | 56 ++ .../crds/cluster-analysis-template-crd.yaml | 56 ++ manifests/crds/experiment-crd.yaml | 11 + manifests/crds/rollout-crd.yaml | 11 + manifests/install.yaml | 190 ++++++ pkg/apiclient/rollout/rollout.swagger.json | 37 +- rollout/trafficrouting/apisix/mocks/apisix.go | 8 + .../trafficrouting/traefik/mocks/traefik.go | 8 + ui/src/models/rollout/generated/api.ts | 38 +- 13 files changed, 870 insertions(+), 611 deletions(-) diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index 09d0393a53..6e645d3a4c 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -323,6 +323,72 @@ "format": "int32", "type": "integer" }, + "podFailurePolicy": { + "properties": { + "rules": { + "items": { + "properties": { + "action": { + "type": "string" + }, + "onExitCodes": { + "properties": { + "containerName": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array", + "x-kubernetes-list-type": "set" + } + }, + "required": [ + "operator", + "values" + ], + "type": "object" + }, + "onPodConditions": { + "items": { + "properties": { + "status": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "status", + "type" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + } + }, + "required": [ + "action", + "onPodConditions" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + } + }, + "required": [ + "rules" + ], + "type": "object" + }, "selector": { "properties": { "matchExpressions": { @@ -2808,6 +2874,9 @@ "hostPID": { "type": "boolean" }, + "hostUsers": { + "type": "boolean" + }, "hostname": { "type": "string" }, @@ -3975,6 +4044,13 @@ }, "type": "object" }, + "matchLabelKeys": { + "items": { + "type": "string" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + }, "maxSkew": { "format": "int32", "type": "integer" @@ -3983,6 +4059,12 @@ "format": "int32", "type": "integer" }, + "nodeAffinityPolicy": { + "type": "string" + }, + "nodeTaintsPolicy": { + "type": "string" + }, "topologyKey": { "type": "string" }, @@ -4612,6 +4694,72 @@ "format": "int32", "type": "integer" }, + "podFailurePolicy": { + "properties": { + "rules": { + "items": { + "properties": { + "action": { + "type": "string" + }, + "onExitCodes": { + "properties": { + "containerName": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array", + "x-kubernetes-list-type": "set" + } + }, + "required": [ + "operator", + "values" + ], + "type": "object" + }, + "onPodConditions": { + "items": { + "properties": { + "status": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "status", + "type" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + } + }, + "required": [ + "action", + "onPodConditions" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + } + }, + "required": [ + "rules" + ], + "type": "object" + }, "selector": { "properties": { "matchExpressions": { @@ -7097,6 +7245,9 @@ "hostPID": { "type": "boolean" }, + "hostUsers": { + "type": "boolean" + }, "hostname": { "type": "string" }, @@ -8264,6 +8415,13 @@ }, "type": "object" }, + "matchLabelKeys": { + "items": { + "type": "string" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + }, "maxSkew": { "format": "int32", "type": "integer" @@ -8272,6 +8430,12 @@ "format": "int32", "type": "integer" }, + "nodeAffinityPolicy": { + "type": "string" + }, + "nodeTaintsPolicy": { + "type": "string" + }, "topologyKey": { "type": "string" }, @@ -8901,6 +9065,72 @@ "format": "int32", "type": "integer" }, + "podFailurePolicy": { + "properties": { + "rules": { + "items": { + "properties": { + "action": { + "type": "string" + }, + "onExitCodes": { + "properties": { + "containerName": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array", + "x-kubernetes-list-type": "set" + } + }, + "required": [ + "operator", + "values" + ], + "type": "object" + }, + "onPodConditions": { + "items": { + "properties": { + "status": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "status", + "type" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + } + }, + "required": [ + "action", + "onPodConditions" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + } + }, + "required": [ + "rules" + ], + "type": "object" + }, "selector": { "properties": { "matchExpressions": { @@ -11386,6 +11616,9 @@ "hostPID": { "type": "boolean" }, + "hostUsers": { + "type": "boolean" + }, "hostname": { "type": "string" }, @@ -12553,6 +12786,13 @@ }, "type": "object" }, + "matchLabelKeys": { + "items": { + "type": "string" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + }, "maxSkew": { "format": "int32", "type": "integer" @@ -12561,6 +12801,12 @@ "format": "int32", "type": "integer" }, + "nodeAffinityPolicy": { + "type": "string" + }, + "nodeTaintsPolicy": { + "type": "string" + }, "topologyKey": { "type": "string" }, @@ -15486,6 +15732,9 @@ "hostPID": { "type": "boolean" }, + "hostUsers": { + "type": "boolean" + }, "hostname": { "type": "string" }, @@ -16653,6 +16902,13 @@ }, "type": "object" }, + "matchLabelKeys": { + "items": { + "type": "string" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + }, "maxSkew": { "format": "int32", "type": "integer" @@ -16661,6 +16917,12 @@ "format": "int32", "type": "integer" }, + "nodeAffinityPolicy": { + "type": "string" + }, + "nodeTaintsPolicy": { + "type": "string" + }, "topologyKey": { "type": "string" }, @@ -19787,6 +20049,13 @@ }, "type": "object" }, + "matchLabelKeys": { + "items": { + "type": "string" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + }, "maxSkew": { "format": "int32", "type": "integer" @@ -19795,6 +20064,12 @@ "format": "int32", "type": "integer" }, + "nodeAffinityPolicy": { + "type": "string" + }, + "nodeTaintsPolicy": { + "type": "string" + }, "topologyKey": { "type": "string" }, diff --git a/go.mod b/go.mod index 2bf94a1c87..8c2601bf7d 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/antonmedv/expr v1.12.5 github.com/argoproj/notifications-engine v0.4.0 github.com/argoproj/pkg v0.13.6 - github.com/aws/aws-sdk-go-v2 v1.17.7 + github.com/aws/aws-sdk-go-v2 v1.18.0 github.com/aws/aws-sdk-go-v2/config v1.18.19 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.25.7 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.19.7 @@ -39,61 +39,62 @@ require ( google.golang.org/grpc v1.54.0 google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.24.2 - k8s.io/apiextensions-apiserver v0.24.2 - k8s.io/apimachinery v0.24.2 - k8s.io/apiserver v0.24.2 - k8s.io/cli-runtime v0.24.2 - k8s.io/client-go v0.24.2 - k8s.io/code-generator v0.24.2 - k8s.io/component-base v0.24.2 - k8s.io/klog/v2 v2.70.1 - k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 - k8s.io/kubectl v0.24.2 - k8s.io/kubernetes v1.24.2 - k8s.io/utils v0.0.0-20220706174534-f6158b442e7c + k8s.io/api v0.25.8 + k8s.io/apiextensions-apiserver v0.25.8 + k8s.io/apimachinery v0.25.8 + k8s.io/apiserver v0.25.8 + k8s.io/cli-runtime v0.25.8 + k8s.io/client-go v0.25.8 + k8s.io/code-generator v0.25.8 + k8s.io/component-base v0.25.8 + k8s.io/klog/v2 v2.80.1 + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 + k8s.io/kubectl v0.25.8 + k8s.io/kubernetes v1.25.8 + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 ) require ( + cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.27 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/PagerDuty/go-pagerduty v1.6.0 // indirect github.com/bradleyfalzon/ghinstallation/v2 v2.1.0 // indirect github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 // indirect github.com/google/go-github/v41 v41.0.0 // indirect github.com/google/go-github/v45 v45.2.0 // indirect github.com/matryer/is v1.4.0 // indirect + github.com/russross/blackfriday v1.6.0 // indirect ) require ( - cloud.google.com/go/compute v1.15.1 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.27 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect - github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/logger v0.2.1 // indirect - github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20220708192748-b73dcb041214 // indirect - github.com/aws/aws-sdk-go v1.44.39 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.18 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.18.7 // indirect + github.com/aws/aws-sdk-go v1.44.116 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.20 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.8 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.18.9 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deepmap/oapi-codegen v1.11.0 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect @@ -144,20 +145,18 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect + github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/oklog/run v1.0.0 // indirect - github.com/onsi/ginkgo v1.16.4 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.13 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/russross/blackfriday v1.6.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect github.com/slack-go/slack v0.12.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect @@ -165,7 +164,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fastjson v1.6.3 // indirect github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 // indirect - github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect + github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect golang.org/x/crypto v0.5.0 // indirect golang.org/x/mod v0.8.0 // indirect @@ -183,41 +182,41 @@ require ( gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/cluster-bootstrap v0.24.2 // indirect - k8s.io/component-helpers v0.24.2 // indirect - k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 // indirect - sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect - sigs.k8s.io/kustomize/api v0.11.5 // indirect - sigs.k8s.io/kustomize/kyaml v0.13.7 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect + k8s.io/cluster-bootstrap v0.25.8 // indirect + k8s.io/component-helpers v0.25.8 // indirect + k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/kustomize/api v0.12.1 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) replace ( github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 - k8s.io/api v0.0.0 => k8s.io/api v0.24.2 - k8s.io/apiextensions-apiserver v0.0.0 => k8s.io/apiextensions-apiserver v0.24.2 - k8s.io/apimachinery v0.0.0 => k8s.io/apimachinery v0.24.2 - k8s.io/apiserver v0.0.0 => k8s.io/apiserver v0.24.2 - k8s.io/cli-runtime v0.0.0 => k8s.io/cli-runtime v0.24.2 - k8s.io/client-go v0.0.0 => k8s.io/client-go v0.24.2 - k8s.io/cloud-provider v0.0.0 => k8s.io/cloud-provider v0.24.2 - k8s.io/cluster-bootstrap v0.0.0 => k8s.io/cluster-bootstrap v0.24.2 - k8s.io/code-generator v0.0.0 => k8s.io/code-generator v0.24.2 - k8s.io/component-base v0.0.0 => k8s.io/component-base v0.24.2 - k8s.io/component-helpers v0.0.0 => k8s.io/component-helpers v0.24.2 - k8s.io/controller-manager v0.0.0 => k8s.io/controller-manager v0.24.2 - k8s.io/cri-api v0.0.0 => k8s.io/cri-api v0.24.2 - k8s.io/csi-translation-lib v0.0.0 => k8s.io/csi-translation-lib v0.24.2 - k8s.io/kube-aggregator v0.0.0 => k8s.io/kube-aggregator v0.24.2 - k8s.io/kube-controller-manager v0.0.0 => k8s.io/kube-controller-manager v0.24.2 - k8s.io/kube-proxy v0.0.0 => k8s.io/kube-proxy v0.24.2 - k8s.io/kube-scheduler v0.0.0 => k8s.io/kube-scheduler v0.24.2 - k8s.io/kubectl v0.0.0 => k8s.io/kubectl v0.24.2 - k8s.io/kubelet v0.0.0 => k8s.io/kubelet v0.24.2 - k8s.io/legacy-cloud-providers v0.0.0 => k8s.io/legacy-cloud-providers v0.24.2 - k8s.io/metrics v0.0.0 => k8s.io/metrics v0.24.2 - k8s.io/mount-utils v0.0.0 => k8s.io/mount-utils v0.24.2 - k8s.io/pod-security-admission v0.0.0 => k8s.io/pod-security-admission v0.24.2 - k8s.io/sample-apiserver v0.0.0 => k8s.io/sample-apiserver v0.24.2 + k8s.io/api v0.0.0 => k8s.io/api v0.25.8 + k8s.io/apiextensions-apiserver v0.0.0 => k8s.io/apiextensions-apiserver v0.25.8 + k8s.io/apimachinery v0.0.0 => k8s.io/apimachinery v0.25.8 + k8s.io/apiserver v0.0.0 => k8s.io/apiserver v0.25.8 + k8s.io/cli-runtime v0.0.0 => k8s.io/cli-runtime v0.25.8 + k8s.io/client-go v0.0.0 => k8s.io/client-go v0.25.8 + k8s.io/cloud-provider v0.0.0 => k8s.io/cloud-provider v0.25.8 + k8s.io/cluster-bootstrap v0.0.0 => k8s.io/cluster-bootstrap v0.25.8 + k8s.io/code-generator v0.0.0 => k8s.io/code-generator v0.25.8 + k8s.io/component-base v0.0.0 => k8s.io/component-base v0.25.8 + k8s.io/component-helpers v0.0.0 => k8s.io/component-helpers v0.25.8 + k8s.io/controller-manager v0.0.0 => k8s.io/controller-manager v0.25.8 + k8s.io/cri-api v0.0.0 => k8s.io/cri-api v0.25.8 + k8s.io/csi-translation-lib v0.0.0 => k8s.io/csi-translation-lib v0.25.8 + k8s.io/kube-aggregator v0.0.0 => k8s.io/kube-aggregator v0.25.8 + k8s.io/kube-controller-manager v0.0.0 => k8s.io/kube-controller-manager v0.25.8 + k8s.io/kube-proxy v0.0.0 => k8s.io/kube-proxy v0.25.8 + k8s.io/kube-scheduler v0.0.0 => k8s.io/kube-scheduler v0.25.8 + k8s.io/kubectl v0.0.0 => k8s.io/kubectl v0.25.8 + k8s.io/kubelet v0.0.0 => k8s.io/kubelet v0.25.8 + k8s.io/legacy-cloud-providers v0.0.0 => k8s.io/legacy-cloud-providers v0.25.8 + k8s.io/metrics v0.0.0 => k8s.io/metrics v0.25.8 + k8s.io/mount-utils v0.0.0 => k8s.io/mount-utils v0.25.8 + k8s.io/pod-security-admission v0.0.0 => k8s.io/pod-security-admission v0.25.8 + k8s.io/sample-apiserver v0.0.0 => k8s.io/sample-apiserver v0.25.8 ) diff --git a/go.sum b/go.sum index eba6172002..0714666578 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -15,11 +13,6 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -32,7 +25,6 @@ cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGB cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= 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/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -43,18 +35,14 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-sdk-for-go v55.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest v0.11.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A= github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/adal v0.9.20 h1:gJ3E98kMpFB1MFqQCvA1yFab8vthOeD4VlFRQULxahg= github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= @@ -66,8 +54,6 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= -github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= @@ -76,11 +62,8 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/GoogleCloudPlatform/k8s-cloud-provider v1.16.1-0.20210702024009-ea6160c1d0e3/go.mod h1:8XasY4ymP2V/tn2OOV9ZadmiTE1FIB/h3W+yNlPttKw= -github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -89,11 +72,7 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PagerDuty/go-pagerduty v1.6.0 h1:am81SzvG5Pw+s3JZ5yEy6kGvsXXklTNRrGr3d8WKpsU= github.com/PagerDuty/go-pagerduty v1.6.0/go.mod h1:7eaBLzsDpK7VUvU0SJ5mohczQkoWrrr5CjDaw5gh1as= @@ -103,14 +82,12 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdko github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20220708192748-b73dcb041214 h1:MdZskg1II+YVe+9ss935i8+paqqf4KEuYcTYUWSwABI= github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20220708192748-b73dcb041214/go.mod h1:rjP7sIipbZcagro/6TCk6X0ZeFT2eyudH5+fve/cbBA= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/antonmedv/expr v1.12.5 h1:Fq4okale9swwL3OeLLs9WD9H6GbgBLJyN/NUHRv+n0E= github.com/antonmedv/expr v1.12.5/go.mod h1:FPC8iWArxls7axbVLsW+kpg1mz29A1b2M6jt+hZfDkU= github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE= @@ -118,131 +95,92 @@ github.com/argoproj/notifications-engine v0.4.0 h1:XyE4jAw0oeRQKL9vlDQBnycmqhN7E github.com/argoproj/notifications-engine v0.4.0/go.mod h1:uGas18+DbCCwjif1zSwWWuwR0xJ18FXF+c2dkhPbF2k= github.com/argoproj/pkg v0.13.6 h1:36WPD9MNYECHcO1/R1pj6teYspiK7uMQLCgLGft2abM= github.com/argoproj/pkg v0.13.6/go.mod h1:I698DoJBKuvNFaixh4vFl2C88cNIT1WS7KCbz5ewyF8= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM= -github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.44.39 h1:pMxYLqnuDidT0ZTDAhYC66fb3W3Yc+oShmfzEL4fTDI= github.com/aws/aws-sdk-go v1.44.39/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg= +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.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.17.8/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY= +github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/config v1.18.19 h1:AqFK6zFNtq4i1EYu+eC7lcKHYnZagMn6SW171la0bGw= github.com/aws/aws-sdk-go-v2/config v1.18.19/go.mod h1:XvTmGMY8d52ougvakOv1RpiTLPz9dlG/OQHsKU/cMmY= -github.com/aws/aws-sdk-go-v2/credentials v1.13.18 h1:EQMdtHwz0ILTW1hoP+EwuWhwCG1hD6l3+RWFQABET4c= github.com/aws/aws-sdk-go-v2/credentials v1.13.18/go.mod h1:vnwlwjIe+3XJPBYKu1et30ZPABG3VaXJYr8ryohpIyM= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 h1:gt57MN3liKiyGopcqgNzJb2+d9MJaKT/q1OksHNXVE4= +github.com/aws/aws-sdk-go-v2/credentials v1.13.20 h1:oZCEFcrMppP/CNiS8myzv9JgOzq2s0d3v3MXYil/mxQ= +github.com/aws/aws-sdk-go-v2/credentials v1.13.20/go.mod h1:xtZnXErtbZ8YGXC3+8WfajpMBn5Ga/3ojZdxHq6iI8o= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1/go.mod h1:lfUx8puBRdM5lVVMQlwt2v+ofiG/X6Ms+dy0UkG/kXw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2 h1:jOzQAesnBFDmz93feqKnsTHsXrlwWORNZMFHMV+WLFU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2/go.mod h1:cDh1p6XkSGSwSRIArWRc6+UqAQ7x4alQ0QfpVR6f+co= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32/go.mod h1:RudqOgadTWdcS3t/erPQo24pcVEoYyqj/kKW5Vya21I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32 h1:p5luUImdIqywn6JpQsW3tq5GNOxKmOnEpybzPx+d1lk= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26/go.mod h1:vq86l7956VgFr0/FWQ2BWnK07QC3WYsepKzy33qqY5U= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32/go.mod h1:XGhIBZDEgfqmFIugclZ6FU7v75nHhBDtzuB4xB/tEi4= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33 h1:HbH1VjUgrCdLJ+4lnnuLI4iVNRvBbBELGaJ5f69ClA8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33/go.mod h1:zG2FcwjQarWaqXSCGpgcr3RSjZ6dHGguZSppUL0XR7Q= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.25.7 h1:dkpnVfgWELJx4g6Q7GQnvm7dYqBAx3lVvJ4ylh9gsRw= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.25.7/go.mod h1:hZ0QWEIcOqKen/WqEkFGa6KxhHY6YnKQJb8POFmCpno= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.19.7 h1:XpIms0tmerNg/t6IiGrbKU6Au25CHyXqs8Yc3zOET5o= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.19.7/go.mod h1:AE8U+Wj27eSDhWhAQp0BJlUi2vIqQ7ndd/e+Hnn+qus= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 h1:5LHn8JQ0qvjD9L9JhMtylnkcw7j05GDZqM9Oin6hpr0= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25/go.mod h1:/95IA+0lMnzW6XzqYJRpjjsAbKEORVeO0anQqjd2CNU= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 h1:5V7DWLBd7wTELVz5bPpwzYy/sikk0gsgZfj40X+l5OI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 h1:uUt4XctZLhl9wBE1L8lobU3bVN8SNUP7T+olb0bWBO4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26/go.mod h1:Bd4C/4PkVGubtNe5iMXu5BNnaBi/9t/UsFspPt4ram8= github.com/aws/aws-sdk-go-v2/service/sso v1.12.6/go.mod h1:Y1VOmit/Fn6Tz1uFAeCO6Q7M2fmfXSCLeL5INVYsLuY= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6 h1:B8cauxOH1W1v7rd8RdI/MWnoR4Ze0wIHWrb90qczxj4= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.8 h1:5cb3D6xb006bPTqEfCNaEA6PPEfBXxxy4NNeX/44kGk= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.8/go.mod h1:GNIveDnP+aE3jujyUSH5aZ/rktsTM5EvtKnCqBZawdw= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6/go.mod h1:Lh/bc9XUf8CfOY6Jp5aIkQtN+j1mc+nExc+KXj9jx2s= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.7 h1:bWNgNdRko2x6gqa0blfATqAZKZokPIeM1vfmQt2pnvM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8 h1:NZaj0ngZMzsubWZbrEFSB4rgSQRbFq38Sd6KBxHuOIU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8/go.mod h1:44qFP1g7pfd+U+sQHLPalAPKnyfTZjJsYR4xIwsJy5o= github.com/aws/aws-sdk-go-v2/service/sts v1.18.7/go.mod h1:JuTnSoeePXmMVe9G8NcjjwgOKEfZ4cOjMuT2IBT/2eI= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.9 h1:Qf1aWwnsNkyAoqDqmdM3nHwN78XQjec27LjM6b9vyfI= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.9/go.mod h1:yyW88BEPXA2fGFyI2KCcZC3dNpiT0CZAHaF+i656/tQ= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= -github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bradleyfalzon/ghinstallation/v2 v2.1.0 h1:5+NghM1Zred9Z078QEZtm28G/kfDfZN/92gkDlLwGVA= github.com/bradleyfalzon/ghinstallation/v2 v2.1.0/go.mod h1:Xg3xPRN5Mcq6GDqeUVhFbjEWMb4JHCyWEeeBGEYQoTU= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/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/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= -github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +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= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= -github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= 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/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s= -github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= -github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.12/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= -github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= -github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= -github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= -github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= -github.com/coredns/caddy v1.1.0/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= -github.com/coredns/corefile-migration v1.0.14/go.mod h1:XnhgULOEouimnzgn0t4WPuFDN2/PJQcTxdWKC5eXNGE= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= @@ -250,14 +188,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeC github.com/deepmap/oapi-codegen v1.11.0 h1:f/X2NdIkaBKsSdpeuwLnY/vDI0AtPUrmB5LMgc7YD+A= github.com/deepmap/oapi-codegen v1.11.0/go.mod h1:k+ujhoQGxmQYBZBbxhOZNZf4j08qv5mC+OH+fFTnKxM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -271,45 +203,28 @@ github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRr github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= -github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/getkin/kin-openapi v0.94.0/go.mod h1:LWZfzOd7PRy8GJ1dJ6mCU6tNdSfOwRac1BUPam4aw6Q= -github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= @@ -317,7 +232,6 @@ github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -335,7 +249,6 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -344,7 +257,6 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34 github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= @@ -352,10 +264,8 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8 github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= @@ -364,19 +274,13 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -387,7 +291,6 @@ github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= @@ -405,7 +308,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -424,21 +326,14 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cadvisor v0.44.1/go.mod h1:GQ9KQfz0iNHQk3D6ftzJWK4TXabfIgM10Oy3FkR+Gzg= -github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= -github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -449,7 +344,6 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -470,7 +364,6 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -478,10 +371,6 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= @@ -494,13 +383,10 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 h1:4EZlYQIiyecYJlUbVkFXCXHz1QPhVXcHnQKAzBTPfQo= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/xNRBCxrn4h/CEB67h0kW1B0t4ooP2yrjUA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -511,14 +397,8 @@ github.com/gregdel/pushover v1.1.0/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -527,37 +407,21 @@ 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-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v1.4.9 h1:ESiK220/qE0aGxWdzKIvRH69iLiuN/PjoLTm69RoWtU= github.com/hashicorp/go-plugin v1.4.9/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= 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= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/heketi/heketi v10.3.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= -github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= @@ -568,7 +432,6 @@ github.com/influxdata/influxdb-client-go/v2 v2.12.2 h1:uYABKdrEKlYm+++qfKdbgaHKB github.com/influxdata/influxdb-client-go/v2 v2.12.2/go.mod h1:YteV91FiQxRdccyJ2cHvj2f/5sq4y4Njqu1fQzsQCOU= github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf h1:7JTmneyiNEwVBOHSjoMxiWAqB992atOeepeFYegn5RU= github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= @@ -577,8 +440,6 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -597,9 +458,6 @@ github.com/juju/ansiterm v1.0.0 h1:gmMvnZRq7JZJx6jkfSq9/+2LMrVEwGwt7UR6G+lmDEg= github.com/juju/ansiterm v1.0.0/go.mod h1:PyXUpnI3olx3bsPcHt98FGPX/KCFZ1Fi+hw1XLI6384= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -607,9 +465,7 @@ github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -633,20 +489,14 @@ github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbq github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= github.com/lestrrat-go/jwx v1.2.24/go.mod h1:zoNuZymNl5lgdcu6P7K6ie2QRll5HVfF4xwxBBK1NxY= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0= github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg= github.com/machinebox/graphql v0.2.2 h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkBZfo= github.com/machinebox/graphql v0.2.2/go.mod h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailgun/mailgun-go v2.0.0+incompatible/go.mod h1:NWTyU+O4aczg/nsGhQnvHL6v2n5Gy6Sv5tNDVvC6FbU= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -672,43 +522,28 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/minio-go/v7 v7.0.29/go.mod h1:x81+AX5gHSfCSqw7jxRKHvxUXMlE5uKX0Vb75Xk5yYg= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/ipvs v1.0.1/go.mod h1:2pngiyseZbIKXNv7hsKj3O9UEz30c53MT9005gt2hxQ= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/sys/mountinfo v0.6.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -716,16 +551,12 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -735,13 +566,9 @@ github.com/newrelic/newrelic-client-go v1.1.0/go.mod h1:RYMXt7hgYw7nzuXIGd2BH0F1 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -749,33 +576,20 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runc v1.1.1/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.13 h1:nV98dkBpqaYbDnhefmOQ+Rn4hE+jD6AtjYHXaU5WyJI= github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.13/go.mod h1:4OjcxgwdXzezqytxN534MooNmrxRD50geWZxTD7845s= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -783,17 +597,13 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -802,31 +612,20 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -834,35 +633,23 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/servicemeshinterface/smi-sdk-go v0.5.0 h1:9cZdhvGbGDlmnp9qqmcQL+RL6KZ3IzHfDLoA5Axg8n0= github.com/servicemeshinterface/smi-sdk-go v0.5.0/go.mod h1:nm1Slf3pfaZPP3g2tE/K5wDmQ1uWVSP0p3uu5rQAQLc= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/slack-go/slack v0.12.1 h1:X97b9g2hnITDtNsNe5GkGx6O2/Sz/uC20ejRZN6QxOw= github.com/slack-go/slack v0.12.1/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= @@ -870,31 +657,17 @@ github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5Pse github.com/spaceapegames/go-wavefront v1.8.1 h1:Xuby0uBfw1WVxD9d+l8Gh+zINqnBfd0RJT8e/3i3vBM= github.com/spaceapegames/go-wavefront v1.8.1/go.mod h1:GtdIjtJ0URkfPmaKx0+7vMSDvT/MON9v+4pbdagA8As= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 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= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= -github.com/storageos/go-api v2.2.0+incompatible/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -912,22 +685,14 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc= @@ -935,68 +700,28 @@ github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLr github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 h1:qqllXPzXh+So+mmANlX/gCJrgo+1kQyshMoQ+NASzm0= github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0/go.mod h1:2rx5KE5FLD0HRfkkpyn8JwbVLBdhgeiOb2D2D9LLKM4= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= -github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= -go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= -go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= -go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= -go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -1004,28 +729,20 @@ golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/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-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= @@ -1033,8 +750,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20210220032938-85be41e4509f/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1047,21 +762,14 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= @@ -1070,17 +778,13 @@ golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1105,19 +809,13 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -1129,16 +827,7 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1158,8 +847,6 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h 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= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1170,31 +857,26 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1207,41 +889,21 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220406155245-289d7a0edf71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1258,7 +920,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -1268,18 +929,13 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb 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= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1297,8 +953,6 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1306,7 +960,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1327,18 +980,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= @@ -1352,12 +995,6 @@ gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45/go.mod h1:41y72mzHT gomodules.xyz/notify v0.1.1 h1:1tTuoyswmPvzqPCTEDQK8SZ3ukCxLsonAAwst2+y1a0= gomodules.xyz/notify v0.1.1/go.mod h1:QgQyU4xEA/plJcDeT66J2Go2V7U4c0pD9wjo7HfFil4= gomodules.xyz/version v0.1.0/go.mod h1:Y8xuV02mL/45psyPKG3NCVOwvAOy6T5Kx0l3rCjKSjU= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= -gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1374,13 +1011,6 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1402,7 +1032,6 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1411,7 +1040,6 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1421,27 +1049,11 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= 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.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -1452,15 +1064,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/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.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= @@ -1491,21 +1096,12 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1524,7 +1120,6 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1534,107 +1129,68 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.17.8/go.mod h1:N++Llhs8kCixMUoCaXXAyMMPbo8dDVnh+IQ36xZV2/0= k8s.io/api v0.18.8/go.mod h1:d/CXqwWv+Z2XEG1LgceeDmHQwpUJhROPx16SlxJgERY= -k8s.io/api v0.24.2 h1:g518dPU/L7VRLxWfcadQn2OnsiGWVOadTLpdnqgY2OI= -k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= -k8s.io/apiextensions-apiserver v0.24.2 h1:/4NEQHKlEz1MlaK/wHT5KMKC9UKYz6NZz6JE6ov4G6k= -k8s.io/apiextensions-apiserver v0.24.2/go.mod h1:e5t2GMFVngUEHUd0wuCJzw8YDwZoqZfJiGOW6mm2hLQ= +k8s.io/api v0.25.8 h1:pcbnWkCcmjNhp6OEKqR+ojO0CJydpOOw7WiWedjLJAU= +k8s.io/api v0.25.8/go.mod h1:FaJqAtI13XOERtpLOQTkW3SiSf0lqsUohYqaxCyHI18= +k8s.io/apiextensions-apiserver v0.25.8 h1:PBji7zCXwYoEabNcNOfvb3asd5LIwZKh1mowrbwn010= +k8s.io/apiextensions-apiserver v0.25.8/go.mod h1:3wN73ddXCwLTE1exhoBiWp5G3u6xRfoNt0cKTHZ5KGE= k8s.io/apimachinery v0.17.8/go.mod h1:Lg8zZ5iC/O8UjCqW6DNhcQG2m4TdjF9kwG3891OWbbA= k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig= -k8s.io/apimachinery v0.24.2 h1:5QlH9SL2C8KMcrNJPor+LbXVTaZRReml7svPEh4OKDM= -k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apiserver v0.24.2 h1:orxipm5elPJSkkFNlwH9ClqaKEDJJA3yR2cAAlCnyj4= -k8s.io/apiserver v0.24.2/go.mod h1:pSuKzr3zV+L+MWqsEo0kHHYwCo77AT5qXbFXP2jbvFI= -k8s.io/cli-runtime v0.24.2 h1:KxY6tSgPGsahA6c1/dmR3uF5jOxXPx2QQY6C5ZrLmtE= -k8s.io/cli-runtime v0.24.2/go.mod h1:1LIhKL2RblkhfG4v5lZEt7FtgFG5mVb8wqv5lE9m5qY= +k8s.io/apimachinery v0.25.8 h1:c4kI9xm0U5nid8sBpBvM+2VHlv4Af8KnbhZIodZF/54= +k8s.io/apimachinery v0.25.8/go.mod h1:ZTl0drTQaFi5gMM3snYI5tWV1XJmRH1gfnDx2QCLsxk= +k8s.io/apiserver v0.25.8 h1:ZTYdLdouAu8D6h9QavMaQZiAV+EfWK87VGdOyb6RZMQ= +k8s.io/apiserver v0.25.8/go.mod h1:IJ1r0vqXxwa+3QbrxAHWqdmoGZnVDDMzWtIK9ju3maI= +k8s.io/cli-runtime v0.25.8 h1:3+I4zgdcY0KoCAWgqfQEMkhKOK35ailULxeTMcrBAfs= +k8s.io/cli-runtime v0.25.8/go.mod h1:Kbi+0tb9s/Gtsp3HfMJ/P20K3MYeC4t/CMDaV4pZiJQ= k8s.io/client-go v0.17.8/go.mod h1:SJsDS64AAtt9VZyeaQMb4Ck5etCitZ/FwajWdzua5eY= k8s.io/client-go v0.18.8/go.mod h1:HqFqMllQ5NnQJNwjro9k5zMyfhZlOwpuTLVrxjkYSxU= -k8s.io/client-go v0.24.2 h1:CoXFSf8if+bLEbinDqN9ePIDGzcLtqhfd6jpfnwGOFA= -k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= -k8s.io/cloud-provider v0.24.2/go.mod h1:a7jyWjizk+IKbcIf8+mX2cj3NvpRv9ZyGdXDyb8UEkI= -k8s.io/cluster-bootstrap v0.24.2 h1:p177dIhDst4INUWBZgTnqSad8oJiUdKo0cLLVU24AzE= -k8s.io/cluster-bootstrap v0.24.2/go.mod h1:eIHV338K03vBm3u/ROZiNXxWJ4AJRoTR9PEUhcTvYkg= +k8s.io/client-go v0.25.8 h1:PruqsI6qccbowI5wjeNosyE1BiKViChRWVOvCZtYnXY= +k8s.io/client-go v0.25.8/go.mod h1:Wiu5CQCaOqWugLrdvl04HK90P0QMc4oxQ3BXoJGjD+A= +k8s.io/cluster-bootstrap v0.25.8 h1:2JoXlDAnki1rmYMdrExP5tYXJgJhCERYHtAbucjZgs8= +k8s.io/cluster-bootstrap v0.25.8/go.mod h1:O7q/A8Os259t1Tm2S9Zn9XipZ9eej0AfApj1htCT0Lc= k8s.io/code-generator v0.18.8/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= -k8s.io/code-generator v0.24.2 h1:EGeRWzJrpwi6T6CvoNl0spM6fnAnOdCr0rz7H4NU1rk= -k8s.io/code-generator v0.24.2/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= -k8s.io/component-base v0.24.2 h1:kwpQdoSfbcH+8MPN4tALtajLDfSfYxBDYlXobNWI6OU= -k8s.io/component-base v0.24.2/go.mod h1:ucHwW76dajvQ9B7+zecZAP3BVqvrHoOxm8olHEg0nmM= -k8s.io/component-helpers v0.24.2 h1:gtXmI/TjVINtkAdZn7m5p8+Vd0Mk4d1q8kwJMMLBdwY= -k8s.io/component-helpers v0.24.2/go.mod h1:TRQPBQKfmqkmV6c0HAmUs8cXVNYYYLsXy4zu8eODi9g= -k8s.io/controller-manager v0.24.2/go.mod h1:hpwCof4KxP4vrw/M5QiVxU6Zmmggmr1keGXtjGHF+vc= -k8s.io/cri-api v0.24.2/go.mod h1:t3tImFtGeStN+ES69bQUX9sFg67ek38BM9YIJhMmuig= -k8s.io/csi-translation-lib v0.24.2/go.mod h1:pdHc2CYLViQYYsOqOp79hjKYi8J4NZ7vpiVzn1SqBrg= +k8s.io/code-generator v0.25.8 h1:rhj7PQgiTdDiV2D9Ep0wHRppQ/jrG7DDJ5vPpEtRtck= +k8s.io/code-generator v0.25.8/go.mod h1:DHfpdhSUrwqF0f4oLqCtF8gYbqlndNetjBEz45nWzJI= +k8s.io/component-base v0.25.8 h1:lQ5Ouw7lupdpXn5slRjAeHnlMK/aAEbPf9jjSWbOD3c= +k8s.io/component-base v0.25.8/go.mod h1:MkC9Lz4fXoGOgB2WhFBU4zjiviIEeJS3sVhTxX9vt6s= +k8s.io/component-helpers v0.25.8 h1:jTi68SNaCis1s4//S7CXOtmzIOqhiY5CUroZuD2+OEg= +k8s.io/component-helpers v0.25.8/go.mod h1:+EZENL02v1dJXJvAYXZfAldATLviWL7Y/K3Pw8LB3MU= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 h1:TT1WdmqqXareKxZ/oNXEUSwKlLiHzPMyB0t8BaFeBYI= -k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08= +k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= -k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-aggregator v0.24.2/go.mod h1:Ju2jNDixn+vqeeKEBfjfpc204bO1pbdXX0N9knCxeMQ= -k8s.io/kube-controller-manager v0.24.2/go.mod h1:KDE0yqiEvxYiO0WRpPA4rVx8AcK1vsWydUF37AJ9lTI= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29/go.mod h1:F+5wygcW0wmRTnM3cOgIqGivxkwSWIWT5YdsDbeAOaU= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661/go.mod h1:daOouuuwd9JXpv1L7Y34iV3yf6nxzipkKMWWlqlvK9M= -k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 h1:yEQKdMCjzAOvGeiTwG4hO/hNVNtDOuUFvMUZ0OlaIzs= -k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8/go.mod h1:mbJ+NSUoAhuR14N0S63bPkh8MGVSo3VYSGZtH/mfMe0= -k8s.io/kube-proxy v0.24.2/go.mod h1:bozS2ufl/Ns6s40Ue34eV7rqyLVygi5usSmCgW7rFU8= -k8s.io/kube-scheduler v0.24.2/go.mod h1:DRa+aeXKSYUUOHHIc/9EcaO9+FW5FydaOfPSvaSW5Ko= -k8s.io/kubectl v0.24.2 h1:+RfQVhth8akUmIc2Ge8krMl/pt66V7210ka3RE/p0J4= -k8s.io/kubectl v0.24.2/go.mod h1:+HIFJc0bA6Tzu5O/YcuUt45APAxnNL8LeMuXwoiGsPg= -k8s.io/kubelet v0.24.2/go.mod h1:Xm9DkWQjwOs+uGOUIIGIPMvvmenvj0lDVOErvIKOOt0= -k8s.io/kubernetes v1.24.2 h1:AyjtHzSysliKR04Km91njmk2yaKmOa3ZISQZCIGUnVI= -k8s.io/kubernetes v1.24.2/go.mod h1:8e8maMiZzBR2/8Po5Uulx+MXZUYJuN3vtKwD4Ct1Xi0= -k8s.io/legacy-cloud-providers v0.24.2/go.mod h1:sgkasgIP2ZOew8fzoOq0mQLVXJ4AmB57IUbFUjzPWEo= -k8s.io/metrics v0.24.2/go.mod h1:5NWURxZ6Lz5gj8TFU83+vdWIVASx7W8lwPpHYCqopMo= -k8s.io/mount-utils v0.24.2/go.mod h1:XrSqB3a2e8sq+aU+rlbcBtQ3EgcuDk5RP9ZsGxjoDrI= -k8s.io/pod-security-admission v0.24.2/go.mod h1:znnuDHWWWvh/tpbYYPwTsd4y//qHi3cOX+wGxET/mMI= -k8s.io/sample-apiserver v0.24.2/go.mod h1:mf8qgDdu450wqpCJOkSAmoTgU4PIMAcfa5uTBwmJekE= -k8s.io/system-validators v1.7.0/go.mod h1:gP1Ky+R9wtrSiFbrpEPwWMeYz9yqyy1S/KOh0Vci7WI= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/kubectl v0.25.8 h1:i6nlpU5LQyg9J19mKihJo1oE7FE7+Zg1cF4TOpJQmEQ= +k8s.io/kubectl v0.25.8/go.mod h1:IPmVLfTvFIZKl0vwyl0LkegIbk2jsnaVmkpDgDymCPI= +k8s.io/kubernetes v1.25.8 h1:RQ3Rf3aScxhg/xDT1GebWFHOtYodM83Q/Yxvgku39G4= +k8s.io/kubernetes v1.25.8/go.mod h1:mEIT8S9Ir6R4R8N6VLmfxcNFAmGU2hEtV780TuPYlug= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220706174534-f6158b442e7c h1:hFZO68mv/0xe8+V0gRT9BAq3/31cKjjeVv4nScriuBk= -k8s.io/utils v0.0.0-20220706174534-f6158b442e7c/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= -modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= -modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= -modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= -modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= -sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 h1:2sgAQQcY0dEW2SsQwTXhQV4vO6+rSslYx8K3XmM5hqQ= -sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= -sigs.k8s.io/kustomize/api v0.11.4/go.mod h1:k+8RsqYbgpkIrJ4p9jcdPqe8DprLxFUUO0yNOq8C+xI= -sigs.k8s.io/kustomize/api v0.11.5 h1:vLDp++YAX7iy2y2CVPJNy9pk9CY8XaUKgHkjbVtnWag= -sigs.k8s.io/kustomize/api v0.11.5/go.mod h1:2UDpxS6AonWXow2ZbySd4AjUxmdXLeTlvGBC46uSiq8= -sigs.k8s.io/kustomize/cmd/config v0.10.6/go.mod h1:/S4A4nUANUa4bZJ/Edt7ZQTyKOY9WCER0uBS1SW2Rco= -sigs.k8s.io/kustomize/kustomize/v4 v4.5.4/go.mod h1:Zo/Xc5FKD6sHl0lilbrieeGeZHVYCA4BzxeAaLI05Bg= -sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg= -sigs.k8s.io/kustomize/kyaml v0.13.7 h1:/EZ/nPaLUzeJKF/BuJ4QCuMVJWiEVoI8iftOHY3g3tk= -sigs.k8s.io/kustomize/kyaml v0.13.7/go.mod h1:6K+IUOuir3Y7nucPRAjw9yth04KSWBnP5pqUTGwj/qU= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= +sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index a4316fa4f9..920eaff7b5 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -232,6 +232,51 @@ spec: parallelism: format: int32 type: integer + podFailurePolicy: + properties: + rules: + items: + properties: + action: + type: string + onExitCodes: + properties: + containerName: + type: string + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + - values + type: object + onPodConditions: + items: + properties: + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + required: + - action + - onPodConditions + type: object + type: array + x-kubernetes-list-type: atomic + required: + - rules + type: object selector: properties: matchExpressions: @@ -1824,6 +1869,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -2571,12 +2618,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index 528e3f6fc7..e60e521f1f 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -228,6 +228,51 @@ spec: parallelism: format: int32 type: integer + podFailurePolicy: + properties: + rules: + items: + properties: + action: + type: string + onExitCodes: + properties: + containerName: + type: string + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + - values + type: object + onPodConditions: + items: + properties: + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + required: + - action + - onPodConditions + type: object + type: array + x-kubernetes-list-type: atomic + required: + - rules + type: object selector: properties: matchExpressions: @@ -1820,6 +1865,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -2567,12 +2614,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index cfc93db1ba..3849f1f3b8 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -228,6 +228,51 @@ spec: parallelism: format: int32 type: integer + podFailurePolicy: + properties: + rules: + items: + properties: + action: + type: string + onExitCodes: + properties: + containerName: + type: string + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + - values + type: object + onPodConditions: + items: + properties: + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + required: + - action + - onPodConditions + type: object + type: array + x-kubernetes-list-type: atomic + required: + - rules + type: object selector: properties: matchExpressions: @@ -1820,6 +1865,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -2567,12 +2614,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/crds/experiment-crd.yaml b/manifests/crds/experiment-crd.yaml index f856a4b9a9..5fb7940b31 100644 --- a/manifests/crds/experiment-crd.yaml +++ b/manifests/crds/experiment-crd.yaml @@ -1720,6 +1720,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -2467,12 +2469,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index bbd547baee..2b026746b6 100755 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -2456,6 +2456,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -3203,12 +3205,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/install.yaml b/manifests/install.yaml index 8ac2ebaaca..7d9ae8ac33 100755 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -233,6 +233,51 @@ spec: parallelism: format: int32 type: integer + podFailurePolicy: + properties: + rules: + items: + properties: + action: + type: string + onExitCodes: + properties: + containerName: + type: string + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + - values + type: object + onPodConditions: + items: + properties: + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + required: + - action + - onPodConditions + type: object + type: array + x-kubernetes-list-type: atomic + required: + - rules + type: object selector: properties: matchExpressions: @@ -1825,6 +1870,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -2572,12 +2619,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: @@ -3124,6 +3180,51 @@ spec: parallelism: format: int32 type: integer + podFailurePolicy: + properties: + rules: + items: + properties: + action: + type: string + onExitCodes: + properties: + containerName: + type: string + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + - values + type: object + onPodConditions: + items: + properties: + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + required: + - action + - onPodConditions + type: object + type: array + x-kubernetes-list-type: atomic + required: + - rules + type: object selector: properties: matchExpressions: @@ -4716,6 +4817,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -5463,12 +5566,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: @@ -5901,6 +6013,51 @@ spec: parallelism: format: int32 type: integer + podFailurePolicy: + properties: + rules: + items: + properties: + action: + type: string + onExitCodes: + properties: + containerName: + type: string + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + - values + type: object + onPodConditions: + items: + properties: + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + required: + - action + - onPodConditions + type: object + type: array + x-kubernetes-list-type: atomic + required: + - rules + type: object selector: properties: matchExpressions: @@ -7493,6 +7650,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -8240,12 +8399,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: @@ -10170,6 +10338,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -10917,12 +11087,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: @@ -13511,6 +13690,8 @@ spec: type: boolean hostPID: type: boolean + hostUsers: + type: boolean hostname: type: string imagePullSecrets: @@ -14258,12 +14439,21 @@ spec: type: string type: object type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic maxSkew: format: int32 type: integer minDomains: format: int32 type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string topologyKey: type: string whenUnsatisfiable: diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index b47f017c91..134bfbf595 100755 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -2220,7 +2220,7 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.ContainerPort" }, - "title": "List of ports to expose from the container. Exposing a port here gives\nthe system additional information about the network connections a\ncontainer uses, but is primarily informational. Not specifying a port here\nDOES NOT prevent that port from being exposed. Any port which is\nlistening on the default \"0.0.0.0\" address inside a container will be\naccessible from the network.\nCannot be updated.\n+optional\n+patchMergeKey=containerPort\n+patchStrategy=merge\n+listType=map\n+listMapKey=containerPort\n+listMapKey=protocol" + "title": "List of ports to expose from the container. Not specifying a port here\nDOES NOT prevent that port from being exposed. Any port which is\nlistening on the default \"0.0.0.0\" address inside a container will be\naccessible from the network.\nModifying this array with strategic merge patch may corrupt the data.\nFor more information See https://github.com/kubernetes/kubernetes/issues/108255.\nCannot be updated.\n+optional\n+patchMergeKey=containerPort\n+patchStrategy=merge\n+listType=map\n+listMapKey=containerPort\n+listMapKey=protocol" }, "envFrom": { "type": "array", @@ -2467,7 +2467,7 @@ "description": "If set, the name of the container from PodSpec that this ephemeral container targets.\nThe ephemeral container will be run in the namespaces (IPC, PID, etc) of this container.\nIf not set then the ephemeral container uses the namespaces configured in the Pod spec.\n\nThe container runtime must implement support for this feature. If the runtime does not\nsupport namespace targeting then the result of setting this field is undefined.\n+optional" } }, - "description": "An EphemeralContainer is a temporary container that you may add to an existing Pod for\nuser-initiated activities such as debugging. Ephemeral containers have no resource or\nscheduling guarantees, and they will not be restarted when they exit or when a Pod is\nremoved or restarted. The kubelet may evict a Pod if an ephemeral container causes the\nPod to exceed its resource allocation.\n\nTo add an ephemeral container, use the ephemeralcontainers subresource of an existing\nPod. Ephemeral containers may not be removed or restarted.\n\nThis is a beta feature available on clusters that haven't disabled the EphemeralContainers feature gate." + "description": "An EphemeralContainer is a temporary container that you may add to an existing Pod for\nuser-initiated activities such as debugging. Ephemeral containers have no resource or\nscheduling guarantees, and they will not be restarted when they exit or when a Pod is\nremoved or restarted. The kubelet may evict a Pod if an ephemeral container causes the\nPod to exceed its resource allocation.\n\nTo add an ephemeral container, use the ephemeralcontainers subresource of an existing\nPod. Ephemeral containers may not be removed or restarted." }, "k8s.io.api.core.v1.EphemeralContainerCommon": { "type": "object", @@ -3343,7 +3343,7 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.EphemeralContainer" }, - "title": "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing\npod to perform user-initiated actions such as debugging. This list cannot be specified when\ncreating a pod, and it cannot be modified by updating the pod spec. In order to add an\nephemeral container to an existing pod, use the pod's ephemeralcontainers subresource.\nThis field is beta-level and available on clusters that haven't disabled the EphemeralContainers feature gate.\n+optional\n+patchMergeKey=name\n+patchStrategy=merge" + "title": "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing\npod to perform user-initiated actions such as debugging. This list cannot be specified when\ncreating a pod, and it cannot be modified by updating the pod spec. In order to add an\nephemeral container to an existing pod, use the pod's ephemeralcontainers subresource.\n+optional\n+patchMergeKey=name\n+patchStrategy=merge" }, "restartPolicy": { "type": "string", @@ -3495,7 +3495,11 @@ }, "os": { "$ref": "#/definitions/k8s.io.api.core.v1.PodOS", - "description": "Specifies the OS of the containers in the pod.\nSome pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset:\n-securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset:\n- spec.hostPID\n- spec.hostIPC\n- spec.securityContext.seLinuxOptions\n- spec.securityContext.seccompProfile\n- spec.securityContext.fsGroup\n- spec.securityContext.fsGroupChangePolicy\n- spec.securityContext.sysctls\n- spec.shareProcessNamespace\n- spec.securityContext.runAsUser\n- spec.securityContext.runAsGroup\n- spec.securityContext.supplementalGroups\n- spec.containers[*].securityContext.seLinuxOptions\n- spec.containers[*].securityContext.seccompProfile\n- spec.containers[*].securityContext.capabilities\n- spec.containers[*].securityContext.readOnlyRootFilesystem\n- spec.containers[*].securityContext.privileged\n- spec.containers[*].securityContext.allowPrivilegeEscalation\n- spec.containers[*].securityContext.procMount\n- spec.containers[*].securityContext.runAsUser\n- spec.containers[*].securityContext.runAsGroup\n+optional\nThis is a beta field and requires the IdentifyPodOS feature" + "description": "Specifies the OS of the containers in the pod.\nSome pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset:\n-securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset:\n- spec.hostPID\n- spec.hostIPC\n- spec.hostUsers\n- spec.securityContext.seLinuxOptions\n- spec.securityContext.seccompProfile\n- spec.securityContext.fsGroup\n- spec.securityContext.fsGroupChangePolicy\n- spec.securityContext.sysctls\n- spec.shareProcessNamespace\n- spec.securityContext.runAsUser\n- spec.securityContext.runAsGroup\n- spec.securityContext.supplementalGroups\n- spec.containers[*].securityContext.seLinuxOptions\n- spec.containers[*].securityContext.seccompProfile\n- spec.containers[*].securityContext.capabilities\n- spec.containers[*].securityContext.readOnlyRootFilesystem\n- spec.containers[*].securityContext.privileged\n- spec.containers[*].securityContext.allowPrivilegeEscalation\n- spec.containers[*].securityContext.procMount\n- spec.containers[*].securityContext.runAsUser\n- spec.containers[*].securityContext.runAsGroup\n+optional" + }, + "hostUsers": { + "type": "boolean", + "title": "Use the host's user namespace.\nOptional: Default to true.\nIf set to true or not present, the pod will be run in the host user namespace, useful\nfor when the pod needs a feature only available to the host user namespace, such as\nloading a kernel module with CAP_SYS_MODULE.\nWhen set to false, a new userns is created for the pod. Setting false is useful for\nmitigating container breakout vulnerabilities even allowing users to run their\ncontainers as root without actually having root privileges on the host.\nThis field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature.\n+k8s:conversion-gen=false\n+optional" } }, "description": "PodSpec is a description of a pod." @@ -4059,7 +4063,7 @@ }, "topologyKey": { "type": "string", - "description": "TopologyKey is the key of node labels. Nodes that have a label with this key\nand identical values are considered to be in the same topology.\nWe consider each \u003ckey, value\u003e as a \"bucket\", and try to put balanced number\nof pods into each bucket.\nWe define a domain as a particular instance of a topology.\nAlso, we define an eligible domain as a domain whose nodes match the node selector.\ne.g. If TopologyKey is \"kubernetes.io/hostname\", each Node is a domain of that topology.\nAnd, if TopologyKey is \"topology.kubernetes.io/zone\", each zone is a domain of that topology.\nIt's a required field." + "description": "TopologyKey is the key of node labels. Nodes that have a label with this key\nand identical values are considered to be in the same topology.\nWe consider each \u003ckey, value\u003e as a \"bucket\", and try to put balanced number\nof pods into each bucket.\nWe define a domain as a particular instance of a topology.\nAlso, we define an eligible domain as a domain whose nodes meet the requirements of\nnodeAffinityPolicy and nodeTaintsPolicy.\ne.g. If TopologyKey is \"kubernetes.io/hostname\", each Node is a domain of that topology.\nAnd, if TopologyKey is \"topology.kubernetes.io/zone\", each zone is a domain of that topology.\nIt's a required field." }, "whenUnsatisfiable": { "type": "string", @@ -4072,7 +4076,22 @@ "minDomains": { "type": "integer", "format": "int32", - "description": "MinDomains indicates a minimum number of eligible domains.\nWhen the number of eligible domains with matching topology keys is less than minDomains,\nPod Topology Spread treats \"global minimum\" as 0, and then the calculation of Skew is performed.\nAnd when the number of eligible domains with matching topology keys equals or greater than minDomains,\nthis value has no effect on scheduling.\nAs a result, when the number of eligible domains is less than minDomains,\nscheduler won't schedule more than maxSkew Pods to those domains.\nIf value is nil, the constraint behaves as if MinDomains is equal to 1.\nValid values are integers greater than 0.\nWhen value is not nil, WhenUnsatisfiable must be DoNotSchedule.\n\nFor example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same\nlabelSelector spread as 2/2/2:\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P P | P P | P P |\n+-------+-------+-------+\nThe number of domains is less than 5(MinDomains), so \"global minimum\" is treated as 0.\nIn this situation, new pod with the same labelSelector cannot be scheduled,\nbecause computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones,\nit will violate MaxSkew.\n\nThis is an alpha field and requires enabling MinDomainsInPodTopologySpread feature gate.\n+optional" + "description": "MinDomains indicates a minimum number of eligible domains.\nWhen the number of eligible domains with matching topology keys is less than minDomains,\nPod Topology Spread treats \"global minimum\" as 0, and then the calculation of Skew is performed.\nAnd when the number of eligible domains with matching topology keys equals or greater than minDomains,\nthis value has no effect on scheduling.\nAs a result, when the number of eligible domains is less than minDomains,\nscheduler won't schedule more than maxSkew Pods to those domains.\nIf value is nil, the constraint behaves as if MinDomains is equal to 1.\nValid values are integers greater than 0.\nWhen value is not nil, WhenUnsatisfiable must be DoNotSchedule.\n\nFor example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same\nlabelSelector spread as 2/2/2:\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P P | P P | P P |\n+-------+-------+-------+\nThe number of domains is less than 5(MinDomains), so \"global minimum\" is treated as 0.\nIn this situation, new pod with the same labelSelector cannot be scheduled,\nbecause computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones,\nit will violate MaxSkew.\n\nThis is a beta field and requires the MinDomainsInPodTopologySpread feature gate to be enabled (enabled by default).\n+optional" + }, + "nodeAffinityPolicy": { + "type": "string", + "description": "NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector\nwhen calculating pod topology spread skew. Options are:\n- Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations.\n- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.\n\nIf this value is nil, the behavior is equivalent to the Honor policy.\nThis is a alpha-level feature enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.\n+optional" + }, + "nodeTaintsPolicy": { + "type": "string", + "description": "NodeTaintsPolicy indicates how we will treat node taints when calculating\npod topology spread skew. Options are:\n- Honor: nodes without taints, along with tainted nodes for which the incoming pod\nhas a toleration, are included.\n- Ignore: node taints are ignored. All nodes are included.\n\nIf this value is nil, the behavior is equivalent to the Ignore policy.\nThis is a alpha-level feature enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.\n+optional" + }, + "matchLabelKeys": { + "type": "array", + "items": { + "type": "string" + }, + "title": "MatchLabelKeys is a set of pod label keys to select the pods over which\nspreading will be calculated. The keys are used to lookup values from the\nincoming pod labels, those key-value labels are ANDed with labelSelector\nto select the group of existing pods over which spreading will be calculated\nfor the incoming pod. Keys that don't exist in the incoming pod labels will\nbe ignored. A null or empty list means only match against labelSelector.\n+listType=atomic\n+optional" } }, "description": "TopologySpreadConstraint specifies how to spread matching pods among the given topology." @@ -4363,7 +4382,7 @@ "type": "string" } }, - "description": "Quantity is a fixed-point representation of a number.\nIt provides convenient marshaling/unmarshaling in JSON and YAML,\nin addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n\u003cquantity\u003e ::= \u003csignedNumber\u003e\u003csuffix\u003e\n (Note that \u003csuffix\u003e may be empty, from the \"\" case in \u003cdecimalSI\u003e.)\n\u003cdigit\u003e ::= 0 | 1 | ... | 9\n\u003cdigits\u003e ::= \u003cdigit\u003e | \u003cdigit\u003e\u003cdigits\u003e\n\u003cnumber\u003e ::= \u003cdigits\u003e | \u003cdigits\u003e.\u003cdigits\u003e | \u003cdigits\u003e. | .\u003cdigits\u003e\n\u003csign\u003e ::= \"+\" | \"-\"\n\u003csignedNumber\u003e ::= \u003cnumber\u003e | \u003csign\u003e\u003cnumber\u003e\n\u003csuffix\u003e ::= \u003cbinarySI\u003e | \u003cdecimalExponent\u003e | \u003cdecimalSI\u003e\n\u003cbinarySI\u003e ::= Ki | Mi | Gi | Ti | Pi | Ei\n (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\u003cdecimalSI\u003e ::= m | \"\" | k | M | G | T | P | E\n (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\u003cdecimalExponent\u003e ::= \"e\" \u003csignedNumber\u003e | \"E\" \u003csignedNumber\u003e\n\nNo matter which of the three exponent forms is used, no quantity may represent\na number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal\nplaces. Numbers larger or more precise will be capped or rounded up.\n(E.g.: 0.1m will rounded up to 1m.)\nThis may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix\nit had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\".\nThis means that Exponent/suffix will be adjusted up or down (with a\ncorresponding increase or decrease in Mantissa) such that:\n a. No precision is lost\n b. No fractional digits will be emitted\n c. The exponent (or suffix) is as large as possible.\nThe sign will be omitted unless the number is negative.\n\nExamples:\n 1.5 will be serialized as \"1500m\"\n 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a\nfloating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed,\nbut will be re-emitted in their canonical form. (So always use canonical\nform, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without\nwriting some sort of special handling code in the hopes that that will\ncause implementors to also use a fixed point implementation.\n\n+protobuf=true\n+protobuf.embed=string\n+protobuf.options.marshal=false\n+protobuf.options.(gogoproto.goproto_stringer)=false\n+k8s:deepcopy-gen=true\n+k8s:openapi-gen=true" + "description": "Quantity is a fixed-point representation of a number.\nIt provides convenient marshaling/unmarshaling in JSON and YAML,\nin addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n```\n\u003cquantity\u003e ::= \u003csignedNumber\u003e\u003csuffix\u003e\n\n\t(Note that \u003csuffix\u003e may be empty, from the \"\" case in \u003cdecimalSI\u003e.)\n\n\u003cdigit\u003e ::= 0 | 1 | ... | 9\n\u003cdigits\u003e ::= \u003cdigit\u003e | \u003cdigit\u003e\u003cdigits\u003e\n\u003cnumber\u003e ::= \u003cdigits\u003e | \u003cdigits\u003e.\u003cdigits\u003e | \u003cdigits\u003e. | .\u003cdigits\u003e\n\u003csign\u003e ::= \"+\" | \"-\"\n\u003csignedNumber\u003e ::= \u003cnumber\u003e | \u003csign\u003e\u003cnumber\u003e\n\u003csuffix\u003e ::= \u003cbinarySI\u003e | \u003cdecimalExponent\u003e | \u003cdecimalSI\u003e\n\u003cbinarySI\u003e ::= Ki | Mi | Gi | Ti | Pi | Ei\n\n\t(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\n\u003cdecimalSI\u003e ::= m | \"\" | k | M | G | T | P | E\n\n\t(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\n\u003cdecimalExponent\u003e ::= \"e\" \u003csignedNumber\u003e | \"E\" \u003csignedNumber\u003e\n```\n\nNo matter which of the three exponent forms is used, no quantity may represent\na number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal\nplaces. Numbers larger or more precise will be capped or rounded up.\n(E.g.: 0.1m will rounded up to 1m.)\nThis may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix\nit had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\".\nThis means that Exponent/suffix will be adjusted up or down (with a\ncorresponding increase or decrease in Mantissa) such that:\n\n- No precision is lost\n- No fractional digits will be emitted\n- The exponent (or suffix) is as large as possible.\n\nThe sign will be omitted unless the number is negative.\n\nExamples:\n\n- 1.5 will be serialized as \"1500m\"\n- 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a\nfloating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed,\nbut will be re-emitted in their canonical form. (So always use canonical\nform, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without\nwriting some sort of special handling code in the hopes that that will\ncause implementors to also use a fixed point implementation.\n\n+protobuf=true\n+protobuf.embed=string\n+protobuf.options.marshal=false\n+protobuf.options.(gogoproto.goproto_stringer)=false\n+k8s:deepcopy-gen=true\n+k8s:openapi-gen=true" }, "k8s.io.apimachinery.pkg.apis.meta.v1.FieldsV1": { "type": "object", @@ -4524,10 +4543,6 @@ }, "title": "Must be empty before the object is deleted from the registry. Each entry\nis an identifier for the responsible component that will remove the entry\nfrom the list. If the deletionTimestamp of the object is non-nil, entries\nin this list can only be removed.\nFinalizers may be processed and removed in any order. Order is NOT enforced\nbecause it introduces significant risk of stuck finalizers.\nfinalizers is a shared field, any actor with permission can reorder it.\nIf the finalizer list is processed in order, then this can lead to a situation\nin which the component responsible for the first finalizer in the list is\nwaiting for a signal (field value, external system, or other) produced by a\ncomponent responsible for a finalizer later in the list, resulting in a deadlock.\nWithout enforced ordering finalizers are free to order amongst themselves and\nare not vulnerable to ordering changes in the list.\n+optional\n+patchStrategy=merge" }, - "clusterName": { - "type": "string", - "description": "Deprecated: ClusterName is a legacy field that was always cleared by\nthe system and never used; it will be removed completely in 1.25.\n\nThe name in the go struct is changed to help clients detect\naccidental use.\n\n+optional" - }, "managedFields": { "type": "array", "items": { diff --git a/rollout/trafficrouting/apisix/mocks/apisix.go b/rollout/trafficrouting/apisix/mocks/apisix.go index 5931fb456a..c884167412 100644 --- a/rollout/trafficrouting/apisix/mocks/apisix.go +++ b/rollout/trafficrouting/apisix/mocks/apisix.go @@ -133,3 +133,11 @@ func (f *FakeClient) Namespace(string) dynamic.ResourceInterface { func (f *FakeDynamicClient) Resource(schema.GroupVersionResource) dynamic.NamespaceableResourceInterface { return &FakeClient{IsListError: f.IsListError} } + +func (f *FakeClient) Apply(ctx context.Context, name string, obj *unstructured.Unstructured, options metav1.ApplyOptions, subresources ...string) (*unstructured.Unstructured, error) { + return nil, nil +} + +func (f *FakeClient) ApplyStatus(ctx context.Context, name string, obj *unstructured.Unstructured, options metav1.ApplyOptions) (*unstructured.Unstructured, error) { + return nil, nil +} diff --git a/rollout/trafficrouting/traefik/mocks/traefik.go b/rollout/trafficrouting/traefik/mocks/traefik.go index e1ce30a648..aedfd659cd 100644 --- a/rollout/trafficrouting/traefik/mocks/traefik.go +++ b/rollout/trafficrouting/traefik/mocks/traefik.go @@ -97,3 +97,11 @@ func (f *FakeClient) Namespace(string) dynamic.ResourceInterface { func (f *FakeDynamicClient) Resource(schema.GroupVersionResource) dynamic.NamespaceableResourceInterface { return &FakeClient{} } + +func (f *FakeClient) Apply(ctx context.Context, name string, obj *unstructured.Unstructured, options metav1.ApplyOptions, subresources ...string) (*unstructured.Unstructured, error) { + return nil, nil +} + +func (f *FakeClient) ApplyStatus(ctx context.Context, name string, obj *unstructured.Unstructured, options metav1.ApplyOptions) (*unstructured.Unstructured, error) { + return nil, nil +} diff --git a/ui/src/models/rollout/generated/api.ts b/ui/src/models/rollout/generated/api.ts index e95c8a4899..4146a6b4cc 100755 --- a/ui/src/models/rollout/generated/api.ts +++ b/ui/src/models/rollout/generated/api.ts @@ -2648,7 +2648,7 @@ export interface K8sIoApiCoreV1EnvVarSource { secretKeyRef?: K8sIoApiCoreV1SecretKeySelector; } /** - * An EphemeralContainer is a temporary container that you may add to an existing Pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a Pod is removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. This is a beta feature available on clusters that haven't disabled the EphemeralContainers feature gate. + * An EphemeralContainer is a temporary container that you may add to an existing Pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a Pod is removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. * @export * @interface K8sIoApiCoreV1EphemeralContainer */ @@ -3933,6 +3933,12 @@ export interface K8sIoApiCoreV1PodSpec { * @memberof K8sIoApiCoreV1PodSpec */ os?: K8sIoApiCoreV1PodOS; + /** + * + * @type {boolean} + * @memberof K8sIoApiCoreV1PodSpec + */ + hostUsers?: boolean; } /** * @@ -4678,7 +4684,7 @@ export interface K8sIoApiCoreV1TopologySpreadConstraint { */ maxSkew?: number; /** - * TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a \"bucket\", and try to put balanced number of pods into each bucket. We define a domain as a particular instance of a topology. Also, we define an eligible domain as a domain whose nodes match the node selector. e.g. If TopologyKey is \"kubernetes.io/hostname\", each Node is a domain of that topology. And, if TopologyKey is \"topology.kubernetes.io/zone\", each zone is a domain of that topology. It's a required field. + * TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a \"bucket\", and try to put balanced number of pods into each bucket. We define a domain as a particular instance of a topology. Also, we define an eligible domain as a domain whose nodes meet the requirements of nodeAffinityPolicy and nodeTaintsPolicy. e.g. If TopologyKey is \"kubernetes.io/hostname\", each Node is a domain of that topology. And, if TopologyKey is \"topology.kubernetes.io/zone\", each zone is a domain of that topology. It's a required field. * @type {string} * @memberof K8sIoApiCoreV1TopologySpreadConstraint */ @@ -4696,11 +4702,29 @@ export interface K8sIoApiCoreV1TopologySpreadConstraint { */ labelSelector?: K8sIoApimachineryPkgApisMetaV1LabelSelector; /** - * MinDomains indicates a minimum number of eligible domains. When the number of eligible domains with matching topology keys is less than minDomains, Pod Topology Spread treats \"global minimum\" as 0, and then the calculation of Skew is performed. And when the number of eligible domains with matching topology keys equals or greater than minDomains, this value has no effect on scheduling. As a result, when the number of eligible domains is less than minDomains, scheduler won't schedule more than maxSkew Pods to those domains. If value is nil, the constraint behaves as if MinDomains is equal to 1. Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: +-------+-------+-------+ | zone1 | zone2 | zone3 | +-------+-------+-------+ | P P | P P | P P | +-------+-------+-------+ The number of domains is less than 5(MinDomains), so \"global minimum\" is treated as 0. In this situation, new pod with the same labelSelector cannot be scheduled, because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, it will violate MaxSkew. This is an alpha field and requires enabling MinDomainsInPodTopologySpread feature gate. +optional + * MinDomains indicates a minimum number of eligible domains. When the number of eligible domains with matching topology keys is less than minDomains, Pod Topology Spread treats \"global minimum\" as 0, and then the calculation of Skew is performed. And when the number of eligible domains with matching topology keys equals or greater than minDomains, this value has no effect on scheduling. As a result, when the number of eligible domains is less than minDomains, scheduler won't schedule more than maxSkew Pods to those domains. If value is nil, the constraint behaves as if MinDomains is equal to 1. Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: +-------+-------+-------+ | zone1 | zone2 | zone3 | +-------+-------+-------+ | P P | P P | P P | +-------+-------+-------+ The number of domains is less than 5(MinDomains), so \"global minimum\" is treated as 0. In this situation, new pod with the same labelSelector cannot be scheduled, because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, it will violate MaxSkew. This is a beta field and requires the MinDomainsInPodTopologySpread feature gate to be enabled (enabled by default). +optional * @type {number} * @memberof K8sIoApiCoreV1TopologySpreadConstraint */ minDomains?: number; + /** + * NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector when calculating pod topology spread skew. Options are: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. If this value is nil, the behavior is equivalent to the Honor policy. This is a alpha-level feature enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. +optional + * @type {string} + * @memberof K8sIoApiCoreV1TopologySpreadConstraint + */ + nodeAffinityPolicy?: string; + /** + * NodeTaintsPolicy indicates how we will treat node taints when calculating pod topology spread skew. Options are: - Honor: nodes without taints, along with tainted nodes for which the incoming pod has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. If this value is nil, the behavior is equivalent to the Ignore policy. This is a alpha-level feature enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. +optional + * @type {string} + * @memberof K8sIoApiCoreV1TopologySpreadConstraint + */ + nodeTaintsPolicy?: string; + /** + * + * @type {Array} + * @memberof K8sIoApiCoreV1TopologySpreadConstraint + */ + matchLabelKeys?: Array; } /** * @@ -5102,7 +5126,7 @@ export interface K8sIoApiCoreV1WindowsSecurityContextOptions { hostProcess?: boolean; } /** - * Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. The serialization format is: ::= (Note that may be empty, from the \"\" case in .) ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) ::= m | \"\" | k | M | G | T | P | E (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) ::= \"e\" | \"E\" No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. Before serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: a. No precision is lost b. No fractional digits will be emitted c. The exponent (or suffix) is as large as possible. The sign will be omitted unless the number is negative. Examples: 1.5 will be serialized as \"1500m\" 1.5Gi will be serialized as \"1536Mi\" Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. +protobuf=true +protobuf.embed=string +protobuf.options.marshal=false +protobuf.options.(gogoproto.goproto_stringer)=false +k8s:deepcopy-gen=true +k8s:openapi-gen=true + * Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. The serialization format is: ``` ::= (Note that may be empty, from the \"\" case in .) ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) ::= m | \"\" | k | M | G | T | P | E (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) ::= \"e\" | \"E\" ``` No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. Before serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: - No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible. The sign will be omitted unless the number is negative. Examples: - 1.5 will be serialized as \"1500m\" - 1.5Gi will be serialized as \"1536Mi\" Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. +protobuf=true +protobuf.embed=string +protobuf.options.marshal=false +protobuf.options.(gogoproto.goproto_stringer)=false +k8s:deepcopy-gen=true +k8s:openapi-gen=true * @export * @interface K8sIoApimachineryPkgApiResourceQuantity */ @@ -5310,12 +5334,6 @@ export interface K8sIoApimachineryPkgApisMetaV1ObjectMeta { * @memberof K8sIoApimachineryPkgApisMetaV1ObjectMeta */ finalizers?: Array; - /** - * Deprecated: ClusterName is a legacy field that was always cleared by the system and never used; it will be removed completely in 1.25. The name in the go struct is changed to help clients detect accidental use. +optional - * @type {string} - * @memberof K8sIoApimachineryPkgApisMetaV1ObjectMeta - */ - clusterName?: string; /** * ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like \"ci-cd\". The set of fields is always in the version that the workflow used when modifying the object. +optional * @type {Array} From 73e7ffb9df7274b30d5229609bc9109a4d8894c0 Mon Sep 17 00:00:00 2001 From: Clayton Walker Date: Tue, 11 Apr 2023 16:07:27 -0600 Subject: [PATCH 43/90] fix(controller): Add klog logrus bridge. Fixes #2707. (#2701) * Add klog logrus bridge Signed-off-by: Clayton Walker * Pull klog bridge out to log util Signed-off-by: Clayton Walker * Upgrade logrusr to v4 Signed-off-by: Clayton Walker * Simplify logging Signed-off-by: Clayton Walker --------- Signed-off-by: Clayton Walker --- cmd/kubectl-argo-rollouts/main.go | 3 +++ cmd/rollouts-controller/main.go | 1 + go.mod | 5 +++-- go.sum | 10 ++++++---- utils/log/log.go | 7 +++++++ utils/log/log_test.go | 13 +++++++++++++ 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/cmd/kubectl-argo-rollouts/main.go b/cmd/kubectl-argo-rollouts/main.go index e5bc3121f6..b7d9a02d0a 100644 --- a/cmd/kubectl-argo-rollouts/main.go +++ b/cmd/kubectl-argo-rollouts/main.go @@ -3,6 +3,8 @@ package main import ( "os" + logutil "github.com/argoproj/argo-rollouts/utils/log" + log "github.com/sirupsen/logrus" "k8s.io/cli-runtime/pkg/genericclioptions" _ "k8s.io/client-go/plugin/pkg/client/auth/azure" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" @@ -15,6 +17,7 @@ import ( func main() { klog.InitFlags(nil) + logutil.SetKLogLogger(log.New()) streams := genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr} o := options.NewArgoRolloutsOptions(streams) root := cmd.NewCmdArgoRollouts(o) diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index 671cc8681d..bb3cfeba1a 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -83,6 +83,7 @@ func newCommand() *cobra.Command { if logFormat != "" { log.SetFormatter(createFormatter(logFormat)) } + logutil.SetKLogLogger(log.New()) logutil.SetKLogLevel(klogLevel) log.WithField("version", version.GetVersion()).Info("Argo Rollouts starting") diff --git a/go.mod b/go.mod index 8c2601bf7d..e27edc0f27 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.25.7 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.19.7 github.com/blang/semver v3.5.1+incompatible + github.com/bombsimon/logrusr/v4 v4.0.0 github.com/evanphx/json-patch/v5 v5.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/gogo/protobuf v1.3.2 @@ -104,7 +105,7 @@ require ( github.com/fatih/color v1.7.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-errors/errors v1.4.2 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.21.1 // indirect @@ -170,7 +171,7 @@ require ( golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect - golang.org/x/sys v0.6.0 // indirect + golang.org/x/sys v0.7.0 // indirect golang.org/x/term v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.3.0 // indirect diff --git a/go.sum b/go.sum index 0714666578..a0237c9b7f 100644 --- a/go.sum +++ b/go.sum @@ -152,6 +152,8 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bombsimon/logrusr/v4 v4.0.0 h1:Pm0InGphX0wMhPqC02t31onlq9OVyJ98eP/Vh63t1Oo= +github.com/bombsimon/logrusr/v4 v4.0.0/go.mod h1:pjfHC5e59CvjTBIU3V3sGhFWFAnsnhOR03TRc6im0l8= github.com/bradleyfalzon/ghinstallation/v2 v2.1.0 h1:5+NghM1Zred9Z078QEZtm28G/kfDfZN/92gkDlLwGVA= github.com/bradleyfalzon/ghinstallation/v2 v2.1.0/go.mod h1:Xg3xPRN5Mcq6GDqeUVhFbjEWMb4JHCyWEeeBGEYQoTU= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= @@ -247,8 +249,8 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -907,8 +909,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220406155245-289d7a0edf71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= diff --git a/utils/log/log.go b/utils/log/log.go index f2b36b078c..049f26f935 100644 --- a/utils/log/log.go +++ b/utils/log/log.go @@ -5,6 +5,8 @@ import ( "strconv" "strings" + "github.com/bombsimon/logrusr/v4" + log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" @@ -28,6 +30,11 @@ const ( NamespaceKey = "namespace" ) +// SetKLogLogger set the klog logger for the k8s go-client +func SetKLogLogger(logger *log.Logger) { + klog.SetLogger(logrusr.New(logger)) +} + // SetKLogLevel set the klog level for the k8s go-client func SetKLogLevel(klogLevel int) { klog.InitFlags(nil) diff --git a/utils/log/log_test.go b/utils/log/log_test.go index 74f8e27647..fa969ebb93 100644 --- a/utils/log/log_test.go +++ b/utils/log/log_test.go @@ -6,6 +6,8 @@ import ( "strings" "testing" + "k8s.io/klog/v2" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -274,3 +276,14 @@ func TestWithVersionFields(t *testing.T) { assert.True(t, strings.Contains(logMessage, "generation=2")) assert.True(t, strings.Contains(logMessage, "resourceVersion=123")) } + +func TestKLogLogger(t *testing.T) { + buf := bytes.NewBufferString("") + logger := log.New() + logger.SetOutput(buf) + SetKLogLogger(logger) + defer klog.ClearLogger() + klog.Info("Logging from klog") + logMessage := buf.String() + assert.Contains(t, logMessage, "Logging from klog") +} From a402042090889a20316da2ce1a12ce6e6d9b05e6 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 28 Apr 2023 10:46:48 -0500 Subject: [PATCH 44/90] fix: change logic of analysis run to better handle errors (#2695) * change logic of analysis run to better haneld errors Signed-off-by: zachaller * change logic to not call GetMetaData if not nil like the old behavior Signed-off-by: zachaller * move code closer to usage Signed-off-by: zachaller * change logic to not always call GetMetadata keeps original behavior Signed-off-by: zachaller * fix logic Signed-off-by: zachaller * cleanup Signed-off-by: zachaller * add test Signed-off-by: zachaller --------- Signed-off-by: zachaller --- analysis/analysis.go | 40 ++++++++++++++++++------------------- analysis/controller_test.go | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/analysis/analysis.go b/analysis/analysis.go index 4e98556794..c826280d19 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -321,26 +321,10 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa //redact secret values from logs logger := logutil.WithRedactor(*logutil.WithAnalysisRun(run).WithField("metric", t.metric.Name), secrets) - resultsLock.Lock() - metricResult := analysisutil.GetResult(run, t.metric.Name) - resultsLock.Unlock() - - provider, err := c.newProvider(*logger, t.metric) - if err != nil { - log.Errorf("Error in getting metric provider :%v", err) - return err - } - if metricResult == nil { - metricResult = &v1alpha1.MetricResult{ - Name: t.metric.Name, - Phase: v1alpha1.AnalysisPhaseRunning, - DryRun: dryRunMetricsMap[t.metric.Name], - Metadata: provider.GetMetadata(t.metric), - } - } - var newMeasurement v1alpha1.Measurement - if err != nil { + provider, providerErr := c.newProvider(*logger, t.metric) + if providerErr != nil { + log.Errorf("Error in getting metric provider :%v", providerErr) if t.incompleteMeasurement != nil { newMeasurement = *t.incompleteMeasurement } else { @@ -348,7 +332,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa newMeasurement.StartedAt = &startedAt } newMeasurement.Phase = v1alpha1.AnalysisPhaseError - newMeasurement.Message = err.Error() + newMeasurement.Message = providerErr.Error() } else { if t.incompleteMeasurement == nil { newMeasurement = provider.Run(run, t.metric) @@ -366,12 +350,28 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa } } + resultsLock.Lock() + metricResult := analysisutil.GetResult(run, t.metric.Name) + resultsLock.Unlock() + if metricResult == nil { + metricResult = &v1alpha1.MetricResult{ + Name: t.metric.Name, + Phase: v1alpha1.AnalysisPhaseRunning, + DryRun: dryRunMetricsMap[t.metric.Name], + } + + if provider != nil && providerErr == nil { + metricResult.Metadata = provider.GetMetadata(t.metric) + } + } + if newMeasurement.Phase.Completed() { logger.Infof("Measurement Completed. Result: %s", newMeasurement.Phase) if newMeasurement.FinishedAt == nil { finishedAt := timeutil.MetaNow() newMeasurement.FinishedAt = &finishedAt } + switch newMeasurement.Phase { case v1alpha1.AnalysisPhaseSuccessful: metricResult.Successful++ diff --git a/analysis/controller_test.go b/analysis/controller_test.go index 8d5efe11f9..cde8ba853e 100644 --- a/analysis/controller_test.go +++ b/analysis/controller_test.go @@ -3,6 +3,7 @@ package analysis import ( "context" "encoding/json" + "fmt" "reflect" "testing" "time" @@ -317,6 +318,44 @@ func TestNoReconcileForAnalysisRunWithDeletionTimestamp(t *testing.T) { f.run(getKey(ar, t)) } +func TestFailedToCreateProviderError(t *testing.T) { + f := newFixture(t) + defer f.Close() + + ar := &v1alpha1.AnalysisRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.AnalysisRunSpec{ + Metrics: []v1alpha1.Metric{ + { + Name: "metric1", + Provider: v1alpha1.MetricProvider{ + Plugin: map[string]json.RawMessage{"mypluginns/myplugin": []byte(`{"invalid": "json"}`)}, + }, + }, + }, + }, + } + f.analysisRunLister = append(f.analysisRunLister, ar) + f.objects = append(f.objects, ar) + + c, i, k8sI := f.newController(noResyncPeriodFunc) + c.newProvider = func(logCtx log.Entry, metric v1alpha1.Metric) (metric.Provider, error) { + return nil, fmt.Errorf("failed to create provider") + } + + pi := f.expectPatchAnalysisRunAction(ar) + + f.runController(getKey(ar, t), true, false, c, i, k8sI) + + updatedAr := f.getPatchedAnalysisRun(pi) + + assert.Equal(t, v1alpha1.AnalysisPhaseError, updatedAr.Status.MetricResults[0].Measurements[0].Phase) + assert.Equal(t, "failed to create provider", updatedAr.Status.MetricResults[0].Measurements[0].Message) +} + func TestRun(t *testing.T) { f := newFixture(t) defer f.Close() From ea685ce25d68516439d4e09debe0c9b5854ee6eb Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sun, 30 Apr 2023 23:20:46 -0500 Subject: [PATCH 45/90] fix(controller): Fix for rollouts getting stuck in loop (#2689) * possible fix for sutck rollouts Signed-off-by: zachaller * add comments Signed-off-by: zachaller * add comments Signed-off-by: zachaller * update comments Signed-off-by: zachaller --------- Signed-off-by: zachaller --- rollout/controller.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/rollout/controller.go b/rollout/controller.go index 1fa0c73ce0..b5d8122ac3 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -413,13 +413,18 @@ func (c *Controller) syncHandler(ctx context.Context, key string) error { } err = roCtx.reconcile() - if roCtx.newRollout != nil { - c.writeBackToInformer(roCtx.newRollout) - } if err != nil { logCtx.Errorf("roCtx.reconcile err %v", err) + // return an err here so that we do not update the informer cache with a "bad" rollout object, for the case when + // we get an error during reconciliation but c.newRollout still gets updated this can happen in syncReplicaSetRevision + // https://github.com/argoproj/argo-rollouts/issues/2522#issuecomment-1492181154 I also believe there are other cases + // that newRollout can get updated while we get an error during reconciliation + return err } - return err + if roCtx.newRollout != nil { + c.writeBackToInformer(roCtx.newRollout) + } + return nil } // writeBackToInformer writes a just recently updated Rollout back into the informer cache. From 5b61b73e6745eb285a8e25432a2ddb8175149da8 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 5 May 2023 09:29:54 -0500 Subject: [PATCH 46/90] fix: istio dropping fields during removing of managed routes (#2692) * fix for dropping fields during removing routes Signed-off-by: zachaller * add comment and rename Signed-off-by: zachaller * add a light weight cast check Signed-off-by: zachaller * improve logic by adding type casting check Signed-off-by: zachaller * add docs Signed-off-by: zachaller --------- Signed-off-by: zachaller --- rollout/trafficrouting/istio/istio.go | 26 +++++++++++++--------- rollout/trafficrouting/istio/istio_test.go | 21 +++++++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/rollout/trafficrouting/istio/istio.go b/rollout/trafficrouting/istio/istio.go index c13426782b..0449c62dff 100644 --- a/rollout/trafficrouting/istio/istio.go +++ b/rollout/trafficrouting/istio/istio.go @@ -1391,8 +1391,8 @@ func (r *Reconciler) orderRoutes(istioVirtualService *unstructured.Unstructured) // splitManagedRoutesAndNonManagedRoutes This splits the routes from an istio virtual service into two slices // one slice contains all the routes that are also in the rollouts managedRoutes object and one that contains routes // that where only in the virtual service (aka routes that where manually added by user) -func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes, httpRouteI []interface{}) (httpRoutesWithinManagedRoutes []VirtualServiceHTTPRoute, httpRoutesNotWithinManagedRoutes []VirtualServiceHTTPRoute, err error) { - var httpRoutes []VirtualServiceHTTPRoute +func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes, httpRouteI []interface{}) (httpRoutesWithinManagedRoutes []map[string]interface{}, httpRoutesNotWithinManagedRoutes []map[string]interface{}, err error) { + var httpRoutes []map[string]interface{} jsonHttpRoutes, err := json.Marshal(httpRouteI) if err != nil { @@ -1406,7 +1406,10 @@ func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes for _, route := range httpRoutes { var found bool = false for _, managedRoute := range managedRoutes { - if route.Name == managedRoute.Name { + // Not checking the cast success here is ok because it covers the case when the route has no name + // when there is no name the cast return an empty string and will just not match the managed route + name, _ := route["name"].(string) + if name == managedRoute.Name { httpRoutesWithinManagedRoutes = append(httpRoutesWithinManagedRoutes, route) found = true break @@ -1423,11 +1426,11 @@ func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes // getOrderedVirtualServiceRoutes This returns an []interface{} of istio virtual routes where the routes are ordered based // on the rollouts managedRoutes field. We take the routes from the rollouts managedRoutes field order them and place them on top // of routes that are manually defined within the virtual service (aka. routes that users have defined manually) -func getOrderedVirtualServiceRoutes(httpRouteI []interface{}, managedRoutes []v1alpha1.MangedRoutes, httpRoutesWithinManagedRoutes []VirtualServiceHTTPRoute, httpRoutesNotWithinManagedRoutes []VirtualServiceHTTPRoute) ([]interface{}, error) { - var orderedManagedRoutes []VirtualServiceHTTPRoute +func getOrderedVirtualServiceRoutes(httpRouteI []interface{}, managedRoutes []v1alpha1.MangedRoutes, httpRoutesWithinManagedRoutes []map[string]interface{}, httpRoutesNotWithinManagedRoutes []map[string]interface{}) ([]interface{}, error) { + var orderedManagedRoutes []map[string]interface{} for _, route := range managedRoutes { for _, managedRoute := range httpRoutesWithinManagedRoutes { - if route.Name == managedRoute.Name { + if route.Name == managedRoute["name"] { orderedManagedRoutes = append(orderedManagedRoutes, managedRoute) } } @@ -1436,13 +1439,16 @@ func getOrderedVirtualServiceRoutes(httpRouteI []interface{}, managedRoutes []v1 orderedVirtualServiceHTTPRoutes := append(orderedManagedRoutes, httpRoutesNotWithinManagedRoutes...) var orderedInterfaceVSVCHTTPRoutes []interface{} - for _, routeTyped := range orderedVirtualServiceHTTPRoutes { + for _, routeMap := range orderedVirtualServiceHTTPRoutes { for _, route := range httpRouteI { r := route.(map[string]interface{}) - // No need to check if exist because the empty string returned on cast failure is good for this check - name, _ := r["name"].(string) - if name == routeTyped.Name { + // Not checking the cast success here is ok because it covers the case when the route has no name + name, rNameOK := r["name"].(string) + routeMapName, RMapNameOK := routeMap["name"].(string) + // The second or clause is for the case when we have a route that has no name set because this field + // is optional in istio virtual service if there is only one route + if name == routeMapName || (!rNameOK && !RMapNameOK) { orderedInterfaceVSVCHTTPRoutes = append(orderedInterfaceVSVCHTTPRoutes, route) } } diff --git a/rollout/trafficrouting/istio/istio_test.go b/rollout/trafficrouting/istio/istio_test.go index fa4330f363..b13d472944 100644 --- a/rollout/trafficrouting/istio/istio_test.go +++ b/rollout/trafficrouting/istio/istio_test.go @@ -883,6 +883,27 @@ func TestHttpReconcileHeaderRouteWithExtra(t *testing.T) { _, found = r2["corsPolicy"] assert.True(t, found) + r.RemoveManagedRoutes() + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + + routes, found, err = unstructured.NestedSlice(iVirtualService.Object, "spec", "http") + assert.NoError(t, err) + assert.True(t, found) + + r0 = routes[0].(map[string]interface{}) + route, found = r0["route"].([]interface{}) + assert.True(t, found) + + port1 = route[0].(map[string]interface{})["destination"].(map[string]interface{})["port"].(map[string]interface{})["number"] + assert.True(t, port1 == float64(8443)) + + r2 = routes[1].(map[string]interface{}) + _, found = r2["retries"] + assert.True(t, found) + _, found = r2["corsPolicy"] + assert.True(t, found) + } func TestReconcileUpdateHeader(t *testing.T) { From bb30c9efed63bc6bd1990474b3adedcafc79600b Mon Sep 17 00:00:00 2001 From: Justin Marquis <34fathombelow@protonmail.com> Date: Wed, 17 May 2023 10:01:31 -0700 Subject: [PATCH 47/90] ci: use keyless signing for main and release branches (#2783) * ci: use keyless signing for main and release branches Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> * fix typo Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> --------- Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> --- .github/workflows/docker-publish.yml | 162 +++++++++------------------ .github/workflows/image-reuse.yaml | 153 +++++++++++++++++++++++++ 2 files changed, 205 insertions(+), 110 deletions(-) create mode 100644 .github/workflows/image-reuse.yaml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 183c8ef4d6..28afaeb95f 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -9,38 +9,32 @@ on: # Run tests for any PRs. pull_request: -permissions: - contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: {} jobs: - docker: + set-vars: + permissions: + contents: read runs-on: ubuntu-latest + outputs: + controller-meta-tags: ${{ steps.controller-meta.outputs.tags }} + plugin-meta-tags: ${{ steps.plugin-meta.outputs.tags }} + platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} steps: - - name: Checkout - uses: actions/checkout@v3.1.0 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - with: - config-inline: | - [worker.oci] - gc = false - - name: Docker meta (controller) id: controller-meta uses: docker/metadata-action@v4 with: images: | quay.io/argoproj/argo-rollouts - # ghcr.io/argoproj/argo-rollouts tags: | - type=ref,event=branch - flavor: | - latest=${{ github.ref == 'refs/heads/master' }} + type=ref,event=branch,enable=${{ github.ref != 'refs/heads/master'}} + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} - name: Docker meta (plugin) id: plugin-meta @@ -48,27 +42,9 @@ jobs: with: images: | quay.io/argoproj/kubectl-argo-rollouts - # ghcr.io/argoproj/kubectl-argo-rollouts tags: | - type=ref,event=branch - flavor: | - latest=${{ github.ref == 'refs/heads/master' }} - - # - name: Login to GitHub Container Registry - # if: github.event_name != 'pull_request' - # uses: docker/login-action@v2 - # with: - # registry: ghcr.io - # username: ${{ github.repository_owner }} - # password: ${{ secrets.GITHUB_TOKEN }} - - - name: Login to Quay.io - if: github.event_name != 'pull_request' - uses: docker/login-action@v2 - with: - registry: quay.io - username: ${{ secrets.QUAY_USERNAME }} - password: ${{ secrets.QUAY_ROBOT_TOKEN }} + type=ref,event=branch,enable=${{ github.ref != 'refs/heads/master'}} + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} # avoid building linux/arm64 for PRs since it takes so long - name: Set Platform Matrix @@ -79,73 +55,39 @@ jobs: then PLATFORM_MATRIX=$PLATFORM_MATRIX,linux/arm64 fi - echo "::set-output name=platform-matrix::$PLATFORM_MATRIX" - - - name: Build and push (controller-image) - uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4.0.0 - with: - platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.controller-meta.outputs.tags }} - provenance: false - sbom: false - - - name: Build and push (plugin-image) - uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4.0.0 - with: - target: kubectl-argo-rollouts - platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.plugin-meta.outputs.tags }} - provenance: false - sbom: false - - - name: Install cosign - uses: sigstore/cosign-installer@main - with: - cosign-release: 'v1.13.1' - - - name: Install crane to get digest of image - uses: imjasonh/setup-crane@v0.3 - - - name: Get digest of controller-image - run: | - if [[ "${{ github.ref == 'refs/heads/master' }}" ]] - then - echo "CONTROLLER_DIGEST=$(crane digest quay.io/argoproj/argo-rollouts:latest)" >> $GITHUB_ENV - fi - if [[ "${{ github.ref != 'refs/heads/master' }}" ]] - then - echo "CONTROLLER_DIGEST=$(crane digest ${{ steps.controller-meta.outputs.tags }})" >> $GITHUB_ENV - fi - if: github.event_name != 'pull_request' - - - name: Get digest of plugin-image - run: | - if [[ "${{ github.ref == 'refs/heads/master' }}" ]] - then - echo "PLUGIN_DIGEST=$(crane digest quay.io/argoproj/kubectl-argo-rollouts:latest)" >> $GITHUB_ENV - fi - if [[ "${{ github.ref != 'refs/heads/master' }}" ]] - then - echo "PLUGIN_DIGEST=$(crane digest ${{ steps.plugin-meta.outputs.tags }})" >> $GITHUB_ENV - fi - if: github.event_name != 'pull_request' - - - name: Sign Argo Rollouts Images - run: | - cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argo-rollouts@${{ env.CONTROLLER_DIGEST }} - cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/kubectl-argo-rollouts@${{ env.PLUGIN_DIGEST }} - env: - COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}} - COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} - if: ${{ github.event_name == 'push' }} - - - name: Display the public key to share. - run: | - # Displays the public key to share - cosign public-key --key env://COSIGN_PRIVATE_KEY - env: - COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}} - COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} - if: ${{ github.event_name == 'push' }} + echo "platform-matrix=$PLATFORM_MATRIX" >> $GITHUB_OUTPUT + + build-and-push-controller-image: + needs: [set-vars] + permissions: + contents: read + packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags + id-token: write # for creating OIDC tokens for signing. + uses: ./.github/workflows/image-reuse.yaml + with: + quay_image_name: ${{ needs.set-vars.outputs.controller-meta-tags }} + # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) + go-version: 1.19 + platforms: ${{ needs.set-vars.outputs.platforms }} + push: ${{ github.event_name != 'pull_request' }} + secrets: + quay_username: ${{ secrets.QUAY_USERNAME }} + quay_password: ${{ secrets.QUAY_ROBOT_TOKEN }} + + build-and-push-plugin-image: + needs: [set-vars] + permissions: + contents: read + packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags + id-token: write # for creating OIDC tokens for signing. + uses: ./.github/workflows/image-reuse.yaml + with: + quay_image_name: ${{ needs.set-vars.outputs.plugin-meta-tags }} + # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) + go-version: 1.19 + platforms: ${{ needs.set-vars.outputs.platforms }} + push: ${{ github.event_name != 'pull_request' }} + target: kubectl-argo-rollouts + secrets: + quay_username: ${{ secrets.QUAY_USERNAME }} + quay_password: ${{ secrets.QUAY_ROBOT_TOKEN }} diff --git a/.github/workflows/image-reuse.yaml b/.github/workflows/image-reuse.yaml new file mode 100644 index 0000000000..744d4f5f4c --- /dev/null +++ b/.github/workflows/image-reuse.yaml @@ -0,0 +1,153 @@ +name: Publish and Sign Container Image +on: + workflow_call: + inputs: + go-version: + required: true + type: string + quay_image_name: + required: false + type: string + ghcr_image_name: + required: false + type: string + docker_image_name: + required: false + type: string + platforms: + required: true + type: string + default: linux/amd64 + push: + required: true + type: boolean + default: false + target: + required: false + type: string + + secrets: + quay_username: + required: false + quay_password: + required: false + ghcr_username: + required: false + ghcr_password: + required: false + docker_username: + required: false + docker_password: + required: false + + outputs: + image-digest: + description: "sha256 digest of container image" + value: ${{ jobs.publish.outputs.image-digest }} + +permissions: {} + +jobs: + publish: + permissions: + contents: read + packages: write # Used to push images to `ghcr.io` if used. + id-token: write # Needed to create an OIDC token for keyless signing + runs-on: ubuntu-22.04 + outputs: + image-digest: ${{ steps.image.outputs.digest }} + steps: + - name: Checkout code + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.3.0 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + if: ${{ github.ref_type == 'tag'}} + + - name: Checkout code + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.3.0 + if: ${{ github.ref_type != 'tag'}} + + - name: Setup Golang + uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + with: + go-version: ${{ inputs.go-version }} + + - name: Install cosign + uses: sigstore/cosign-installer@204a51a57a74d190b284a0ce69b44bc37201f343 # v3.0.3 + with: + cosign-release: 'v2.0.2' + + - uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0 + - uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2.5.0 + + - name: Setup tags for container image as a CSV type + run: | + IMAGE_TAGS=$(for str in \ + ${{ inputs.quay_image_name }} \ + ${{ inputs.ghcr_image_name }} \ + ${{ inputs.docker_image_name}}; do + echo -n "${str}",;done | sed 's/,$//') + + echo $IMAGE_TAGS + echo "TAGS=$IMAGE_TAGS" >> $GITHUB_ENV + + - name: Setup image namespace for signing, strip off the tag + run: | + TAGS=$(for tag in \ + ${{ inputs.quay_image_name }} \ + ${{ inputs.ghcr_image_name }} \ + ${{ inputs.docker_image_name}}; do + echo -n "${tag}" | awk -F ":" '{print $1}' -;done) + + echo $TAGS + echo 'SIGNING_TAGS<> $GITHUB_ENV + echo $TAGS >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + + - name: Login to Quay.io + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0 + with: + registry: quay.io + username: ${{ secrets.quay_username }} + password: ${{ secrets.quay_password }} + if: ${{ inputs.quay_image_name && inputs.push }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0 + with: + registry: ghcr.io + username: ${{ secrets.ghcr_username }} + password: ${{ secrets.ghcr_password }} + if: ${{ inputs.ghcr_image_name && inputs.push }} + + - name: Login to dockerhub Container Registry + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0 + with: + username: ${{ secrets.docker_username }} + password: ${{ secrets.docker_password }} + if: ${{ inputs.docker_image_name && inputs.push }} + + - name: Build and push container image + id: image + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 #v4.0.0 + with: + context: . + platforms: ${{ inputs.platforms }} + push: ${{ inputs.push }} + tags: ${{ env.TAGS }} + target: ${{ inputs.target }} + provenance: false + sbom: false + + - name: Sign container images + run: | + for signing_tag in $SIGNING_TAGS; do + cosign sign \ + -a "repo=${{ github.repository }}" \ + -a "workflow=${{ github.workflow }}" \ + -a "sha=${{ github.sha }}" \ + --yes \ + "$signing_tag"@${{ steps.image.outputs.digest }} + done + if: ${{ inputs.push }} From 0322914d79aaf6d7f76550c73a4ce2de184ea564 Mon Sep 17 00:00:00 2001 From: Alex Eftimie Date: Sun, 14 May 2023 05:58:33 +0200 Subject: [PATCH 48/90] fix: properly wrap Datadog API v2 request body (#2771) (#2775) * Datadog: properly wrap request body Signed-off-by: Alex Eftimie * Use milliseconds in v2 calls to datadog Signed-off-by: Alex Eftimie --------- Signed-off-by: Alex Eftimie --- metricproviders/datadog/datadog.go | 27 ++++++++++++++--------- metricproviders/datadog/datadogV2_test.go | 16 +++++++------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/metricproviders/datadog/datadog.go b/metricproviders/datadog/datadog.go index 232dc59083..00f9c8a8ac 100644 --- a/metricproviders/datadog/datadog.go +++ b/metricproviders/datadog/datadog.go @@ -56,6 +56,10 @@ type datadogQuery struct { QueryType string `json:"type"` } +type datadogRequest struct { + Data datadogQuery `json:"data"` +} + type datadogResponseV1 struct { Series []struct { Pointlist [][]float64 `json:"pointlist"` @@ -182,17 +186,18 @@ func (p *Provider) createRequest(query string, apiVersion string, now int64, int return &http.Request{Method: "GET"}, nil } else if apiVersion == "v2" { - queryBody, err := json.Marshal(datadogQuery{ - QueryType: "timeseries_request", - Attributes: datadogQueryAttributes{ - From: now - interval, - To: now, - Queries: []map[string]string{{ - "data_source": "metrics", - "query": query, - }}, - }, - }) + queryBody, err := json.Marshal(datadogRequest{ + Data: datadogQuery{ + QueryType: "timeseries_request", + Attributes: datadogQueryAttributes{ + From: (now - interval) * 1000, + To: now * 1000, + Queries: []map[string]string{{ + "data_source": "metrics", + "query": query, + }}, + }, + }}) if err != nil { return nil, fmt.Errorf("Could not parse your JSON request: %v", err) } diff --git a/metricproviders/datadog/datadogV2_test.go b/metricproviders/datadog/datadogV2_test.go index c6e04fab3d..11a82411c7 100644 --- a/metricproviders/datadog/datadogV2_test.go +++ b/metricproviders/datadog/datadogV2_test.go @@ -245,28 +245,28 @@ func TestRunSuiteV2(t *testing.T) { t.Errorf("\nreceived no bytes in request: %v", err) } - var reqBody datadogQuery + var reqBody datadogRequest err = json.Unmarshal(bodyBytes, &reqBody) if err != nil { t.Errorf("\nCould not parse JSON request body: %v", err) } - actualQuery := reqBody.Attributes.Queries[0]["query"] - actualFrom := reqBody.Attributes.From - actualTo := reqBody.Attributes.To + actualQuery := reqBody.Data.Attributes.Queries[0]["query"] + actualFrom := reqBody.Data.Attributes.From + actualTo := reqBody.Data.Attributes.To if actualQuery != "avg:kubernetes.cpu.user.total{*}" { t.Errorf("\nquery expected avg:kubernetes.cpu.user.total{*} but got %s", actualQuery) } - if actualFrom != unixNow()-test.expectedIntervalSeconds { - t.Errorf("\nfrom %d expected be equal to %d", actualFrom, unixNow()-test.expectedIntervalSeconds) + if actualFrom != (unixNow()-test.expectedIntervalSeconds)*1000 { + t.Errorf("\nfrom %d expected be equal to %d", actualFrom, (unixNow()-test.expectedIntervalSeconds)*1000) } else if err != nil { t.Errorf("\nfailed to parse from: %v", err) } - if actualTo != unixNow() { - t.Errorf("\nto %d was expected be equal to %d", actualTo, unixNow()) + if actualTo != unixNow()*1000 { + t.Errorf("\nto %d was expected be equal to %d", actualTo, unixNow()*1000) } else if err != nil { t.Errorf("\nfailed to parse to: %v", err) } From 839f05d46f838c04b44eff0e573227d40e89ac7d Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 24 May 2023 13:20:21 -0500 Subject: [PATCH 49/90] fix: make new alb fullName field optional for backward compatability (#2806) fix: make new field optional Signed-off-by: zachaller --- manifests/crds/rollout-crd.yaml | 3 --- manifests/install.yaml | 3 --- pkg/apiclient/rollout/rollout.swagger.json | 3 ++- pkg/apis/rollouts/v1alpha1/generated.proto | 2 ++ pkg/apis/rollouts/v1alpha1/openapi_generated.go | 9 +++++---- pkg/apis/rollouts/v1alpha1/types.go | 6 ++++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 2b026746b6..7deff0db60 100755 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -3274,7 +3274,6 @@ spec: type: string required: - arn - - fullName - name type: object loadBalancer: @@ -3287,7 +3286,6 @@ spec: type: string required: - arn - - fullName - name type: object stableTargetGroup: @@ -3300,7 +3298,6 @@ spec: type: string required: - arn - - fullName - name type: object type: object diff --git a/manifests/install.yaml b/manifests/install.yaml index 7d9ae8ac33..2fa3de0411 100755 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -14508,7 +14508,6 @@ spec: type: string required: - arn - - fullName - name type: object loadBalancer: @@ -14521,7 +14520,6 @@ spec: type: string required: - arn - - fullName - name type: object stableTargetGroup: @@ -14534,7 +14532,6 @@ spec: type: string required: - arn - - fullName - name type: object type: object diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 134bfbf595..ace101ef6e 100755 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -704,7 +704,8 @@ "type": "string" }, "fullName": { - "type": "string" + "type": "string", + "title": "FullName is the full name of the resource\n+optional" } } }, diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index 30e6874d3c..f52e9b3566 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -291,6 +291,8 @@ message AwsResourceRef { optional string arn = 2; + // FullName is the full name of the resource + // +optional optional string fullName = 3; } diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 6cd83f8ed1..d9a399e40f 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -1053,13 +1053,14 @@ func schema_pkg_apis_rollouts_v1alpha1_AwsResourceRef(ref common.ReferenceCallba }, "fullName": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "FullName is the full name of the resource", + Default: "", + Type: []string{"string"}, + Format: "", }, }, }, - Required: []string{"name", "arn", "fullName"}, + Required: []string{"name", "arn"}, }, }, } diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 0e5c192be1..17febd8bd7 100755 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -994,8 +994,10 @@ type ALBStatus struct { } type AwsResourceRef struct { - Name string `json:"name" protobuf:"bytes,1,opt,name=name"` - ARN string `json:"arn" protobuf:"bytes,2,opt,name=arn"` + Name string `json:"name" protobuf:"bytes,1,opt,name=name"` + ARN string `json:"arn" protobuf:"bytes,2,opt,name=arn"` + // FullName is the full name of the resource + // +optional FullName string `json:"fullName" protobuf:"bytes,3,opt,name=fullName"` } From ba7f997ac4d9689312bdb8b6e07f8a5847538201 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 15 Jun 2023 11:21:37 -0500 Subject: [PATCH 50/90] fix: resolve args to metric in garbage collection function (#2843) * resolve args to metric in garbage collection function Signed-off-by: zachaller * remove incorrectly added test, this moved to a function Signed-off-by: zachaller * re-trigger Signed-off-by: zachaller * add context to errors Signed-off-by: zachaller * better error message Signed-off-by: zachaller * better error message Signed-off-by: zachaller --------- Signed-off-by: zachaller --- analysis/analysis.go | 7 ++- analysis/analysis_test.go | 98 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/analysis/analysis.go b/analysis/analysis.go index c826280d19..fb307e62e0 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -711,8 +711,13 @@ func calculateNextReconcileTime(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Me func (c *Controller) garbageCollectMeasurements(run *v1alpha1.AnalysisRun, measurementRetentionMetricNamesMap map[string]*v1alpha1.MeasurementRetention, limit int) error { var errors []error + resolvedArgsMetric, err := getResolvedMetricsWithoutSecrets(run.Spec.Metrics, run.Spec.Args) + if err != nil { + return fmt.Errorf("failed to resolve args on metrics during garbage collection: %w", err) + } + metricsByName := make(map[string]v1alpha1.Metric) - for _, metric := range run.Spec.Metrics { + for _, metric := range resolvedArgsMetric { metricsByName[metric.Name] = metric } diff --git a/analysis/analysis_test.go b/analysis/analysis_test.go index ed12da2dca..cec3446b89 100644 --- a/analysis/analysis_test.go +++ b/analysis/analysis_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/argoproj/argo-rollouts/metric" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -1099,6 +1101,102 @@ func TestTrimMeasurementHistory(t *testing.T) { } } +func TestGarbageCollectArgResolution(t *testing.T) { + f := newFixture(t) + defer f.Close() + c, _, _ := f.newController(noResyncPeriodFunc) + + c.newProvider = func(logCtx log.Entry, metric v1alpha1.Metric) (metric.Provider, error) { + assert.Equal(t, "https://prometheus.kubeaddons:8080", metric.Provider.Prometheus.Address) + return f.provider, nil + } + + f.provider.On("GarbageCollect", mock.Anything, mock.Anything, mock.Anything).Return(nil) + run := &v1alpha1.AnalysisRun{ + Spec: v1alpha1.AnalysisRunSpec{ + Metrics: []v1alpha1.Metric{ + { + Name: "metric1", + Interval: "60s", + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{ + Address: "https://prometheus.kubeaddons:{{args.port}}", + }, + }, + }, + { + Name: "metric2", + Interval: "60s", + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{ + Address: "https://prometheus.kubeaddons:{{args.port}}", + }, + }, + }, + }, + }, + Status: v1alpha1.AnalysisRunStatus{ + Phase: v1alpha1.AnalysisPhaseRunning, + MetricResults: []v1alpha1.MetricResult{ + { + Name: "metric1", + Phase: v1alpha1.AnalysisPhaseRunning, + Measurements: []v1alpha1.Measurement{ + { + Value: "1", + Phase: v1alpha1.AnalysisPhaseSuccessful, + StartedAt: timePtr(metav1.NewTime(time.Now().Add(-60 * time.Second))), + FinishedAt: timePtr(metav1.NewTime(time.Now().Add(-60 * time.Second))), + }, + { + Value: "2", + Phase: v1alpha1.AnalysisPhaseSuccessful, + StartedAt: timePtr(metav1.NewTime(time.Now().Add(-60 * time.Second))), + FinishedAt: timePtr(metav1.NewTime(time.Now().Add(-60 * time.Second))), + }, + }, + }, + { + Name: "metric2", + Measurements: []v1alpha1.Measurement{ + { + Value: "2", + Phase: v1alpha1.AnalysisPhaseSuccessful, + StartedAt: timePtr(metav1.NewTime(time.Now().Add(-60 * time.Second))), + FinishedAt: timePtr(metav1.NewTime(time.Now().Add(-60 * time.Second))), + }, + { + Value: "3", + Phase: v1alpha1.AnalysisPhaseSuccessful, + StartedAt: timePtr(metav1.NewTime(time.Now().Add(-30 * time.Second))), + FinishedAt: timePtr(metav1.NewTime(time.Now().Add(-30 * time.Second))), + }, + { + Value: "4", + Phase: v1alpha1.AnalysisPhaseSuccessful, + StartedAt: timePtr(metav1.NewTime(time.Now().Add(-30 * time.Second))), + FinishedAt: timePtr(metav1.NewTime(time.Now().Add(-30 * time.Second))), + }, + }, + }, + }, + }, + } + run.Spec.Args = append(run.Spec.Args, v1alpha1.Argument{ + Name: "port", + Value: pointer.String("8080"), + }) + var measurementRetentionMetricsMap = map[string]*v1alpha1.MeasurementRetention{} + measurementRetentionMetricsMap["metric2"] = &v1alpha1.MeasurementRetention{MetricName: "metric2", Limit: 2} + err := c.garbageCollectMeasurements(run, measurementRetentionMetricsMap, 1) + assert.Nil(t, err) + assert.Len(t, run.Status.MetricResults[0].Measurements, 1) + assert.Equal(t, "2", run.Status.MetricResults[0].Measurements[0].Value) + assert.Len(t, run.Status.MetricResults[1].Measurements, 2) + assert.Equal(t, "3", run.Status.MetricResults[1].Measurements[0].Value) + assert.Equal(t, "4", run.Status.MetricResults[1].Measurements[1].Value) +} + func TestResolveMetricArgsUnableToSubstitute(t *testing.T) { f := newFixture(t) defer f.Close() From 804e8fe3d28a342ab315c9cb05b0bb66a30f6786 Mon Sep 17 00:00:00 2001 From: Justin Marquis <34fathombelow@protonmail.com> Date: Wed, 12 Jul 2023 12:14:36 -0700 Subject: [PATCH 51/90] ci: generate attestations during a release (#2785) * ci: use keyless signing for main and release branches Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> * fix typo Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> * ci: generate attestations during a release Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> * add release trigger script Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> --------- Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> Signed-off-by: zachaller Co-authored-by: zachaller Signed-off-by: zachaller --- .github/workflows/README.md | 39 +++ .github/workflows/release.yaml | 368 ++++++++++++++----------- docs/release-action.png | Bin 48610 -> 0 bytes docs/releasing.md | 63 +++-- docs/{ => security}/security.md | 0 docs/security/signed-release-assets.md | 116 ++++++++ hack/trigger-release.sh | 56 ++++ mkdocs.yml | 4 +- 8 files changed, 457 insertions(+), 189 deletions(-) create mode 100644 .github/workflows/README.md delete mode 100644 docs/release-action.png rename docs/{ => security}/security.md (100%) create mode 100644 docs/security/signed-release-assets.md create mode 100755 hack/trigger-release.sh diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000000..158a90d4c1 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,39 @@ +# Workflows + +| Workflow | Description | +|---------------------|-----------------------------------------------------------------| +| changelog.yml | Updates changelog when a release is published | +| codeql.yaml | CodeQL analysis | +| docker-publish.yaml | Build container image for PR's & publish for push events | +| image-reuse.yaml | Build, push, and Sign container images | +| go.yaml | lint, build, codegen | +| pr-title-check.yaml | Lint PR for semantic information | +| init-release.yaml | Build manifests and version then create a PR for release branch | +| release.yaml | Build images, cli-binaries, provenances, and post actions | + + +# Reusable workflows + +## image-reuse.yaml + +- The resuable workflow can be used to publish or build images with multiple container registries(Quay,GHCR, dockerhub), and then sign them with cosign when an image is published. +- A GO version `must` be specified e.g. 1.19 +- The image name for each registry *must* contain the tag. Note: multiple tags are allowed for each registry using a CSV type. +- Multiple platforms can be specified e.g. linux/amd64,linux/arm64 +- Images are not published by default. A boolean value must be set to `true` to push images. +- An optional target can be specified. + +| Inputs | Description | Type | Required | Defaults | +|-------------------|-------------------------------------|-------------|----------|-----------------| +| go-version | Version of Go to be used | string | true | none | +| quay_image_name | Full image name and tag | CSV, string | false | none | +| ghcr_image_name | Full image name and tag | CSV, string | false | none | +| docker_image_name | Full image name and tag | CSV, string | false | none | +| platforms | Platforms to build (linux/amd64) | CSV, string | false | linux/amd64 | +| push | Whether to push image/s to registry | boolean | false | false | +| target | Target build stage | string | false | none | + +| Outputs | Description | Type | +|-------------|------------------------------------------|-------| +|image-digest | Image digest of image container created | string| + diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 919cd7c51c..ceaf0b0d49 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,132 +1,178 @@ name: Release - on: - workflow_dispatch: - inputs: - tag: - description: Git tag to build release from - required: true - update_stable_tag: - description: 'Update stable tag' - required: true - type: boolean - default: 'false' -permissions: - contents: read + push: + tags: + - 'v*' + +permissions: {} + +env: + GOLANG_VERSION: '1.19' # Note: go-version must also be set in job controller-image.with.go-version & plugin-image.with.go-version. jobs: - release-images: + controller-image: + permissions: + contents: read + packages: write # Required and used to push images to `ghcr.io` if used. + id-token: write # For creating OIDC tokens for signing. + uses: ./.github/workflows/image-reuse.yaml + with: + quay_image_name: quay.io/argoproj/argo-rollouts:${{ github.ref_name }} + # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) + go-version: 1.19 + platforms: linux/amd64,linux/arm64 + push: true + secrets: + quay_username: ${{ secrets.QUAY_USERNAME }} + quay_password: ${{ secrets.QUAY_ROBOT_TOKEN }} + + plugin-image: + permissions: + contents: read + packages: write # Required and used to push images to `ghcr.io` if used. + id-token: write # For creating OIDC tokens for signing. + uses: ./.github/workflows/image-reuse.yaml + with: + quay_image_name: quay.io/argoproj/kubectl-argo-rollouts:${{ github.ref_name }} + # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) + go-version: 1.19 + platforms: linux/amd64,linux/arm64 + push: true + target: kubectl-argo-rollouts + secrets: + quay_username: ${{ secrets.QUAY_USERNAME }} + quay_password: ${{ secrets.QUAY_ROBOT_TOKEN }} + + controller-image-provenance: + needs: + - controller-image + permissions: + actions: read # for detecting the Github Actions environment. + id-token: write # for creating OIDC tokens for signing. + packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues) + # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.6.0 + with: + image: quay.io/argoproj/argo-rollouts + digest: ${{ needs.controller-image.outputs.image-digest }} + secrets: + registry-username: ${{ secrets.QUAY_USERNAME }} + registry-password: ${{ secrets.QUAY_ROBOT_TOKEN }} + + plugin-image-provenance: + needs: + - plugin-image + permissions: + actions: read # for detecting the Github Actions environment. + id-token: write # for creating OIDC tokens for signing. + packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues) + # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.6.0 + with: + image: quay.io/argoproj/kubectl-argo-rollouts + digest: ${{ needs.plugin-image.outputs.image-digest }} + secrets: + registry-username: ${{ secrets.QUAY_USERNAME }} + registry-password: ${{ secrets.QUAY_ROBOT_TOKEN }} + + + release-artifacts: + permissions: + contents: write # for softprops/action-gh-release to create GitHub release runs-on: ubuntu-latest + outputs: + hashes: ${{ steps.hash.outputs.hashes }} steps: - name: Checkout - uses: actions/checkout@v3.1.0 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: - ref: ${{ github.event.inputs.tag }} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} - - name: Get SHA - id: get-sha - run: echo "::set-output name=sha::$(git log -1 --format='%H')" + - name: Setup Golang + uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + with: + go-version: ${{ env.GOLANG_VERSION }} - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - with: - config-inline: | - [worker.oci] - gc = false + uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2.5.0 - - name: Print Disk Usage + - name: Generate release artifacts run: | - df -ah - docker buildx du + make release-plugins + make checksums + make manifests IMAGE_TAG=${{ github.ref_name }} - - name: Docker meta (controller) - id: controller-meta - uses: docker/metadata-action@v4 - with: - images: | - quay.io/argoproj/argo-rollouts - # ghcr.io/argoproj/argo-rollouts - tags: | - type=semver,pattern={{version}},prefix=v,value=${{ github.event.inputs.tag }} - flavor: | - latest=false - - - name: Docker meta (plugin) - id: plugin-meta - uses: docker/metadata-action@v4 - with: - images: | - quay.io/argoproj/kubectl-argo-rollouts - # ghcr.io/argoproj/kubectl-argo-rollouts - tags: | - type=semver,pattern={{version}},prefix=v,value=${{ github.event.inputs.tag }} - flavor: | - latest=false - - # - name: Login to GitHub Container Registry - # if: github.event_name != 'pull_request' - # uses: docker/login-action@v2 - # with: - # registry: ghcr.io - # username: ${{ github.repository_owner }} - # password: ${{ secrets.GITHUB_TOKEN }} - - - name: Login to Quay.io - if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + - name: Draft release + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 with: - registry: quay.io - username: ${{ secrets.QUAY_USERNAME }} - password: ${{ secrets.QUAY_ROBOT_TOKEN }} + tag_name: ${{ github.event.inputs.tag }} + draft: true + files: | + dist/kubectl-argo-rollouts-linux-amd64 + dist/kubectl-argo-rollouts-linux-arm64 + dist/kubectl-argo-rollouts-darwin-amd64 + dist/kubectl-argo-rollouts-darwin-arm64 + dist/kubectl-argo-rollouts-windows-amd64 + dist/argo-rollouts-checksums.txt + manifests/dashboard-install.yaml + manifests/install.yaml + manifests/namespace-install.yaml + manifests/notifications-install.yaml + docs/features/kustomize/rollout_cr_schema.json + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push (controller-image) - uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4.0.0 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.controller-meta.outputs.tags }} - provenance: false - sbom: false - - - name: Build and push (plugin-image) - uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4.0.0 - with: - context: . - target: kubectl-argo-rollouts - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.plugin-meta.outputs.tags }} - provenance: false - sbom: false + - name: Generate hashes for provenance + id: hash + run: | + echo "hashes=$(sha256sum ./dist/kubectl-argo-rollouts-* ./manifests/*.yaml | base64 -w0)" >> "$GITHUB_OUTPUT" - release-artifacts: + release-artifacts-provenance: + needs: + - release-artifacts permissions: - contents: write # for softprops/action-gh-release to create GitHub release + actions: read # for detecting the Github Actions environment + id-token: write # Needed for provenance signing and ID + contents: write # Needed for release uploads + # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.6.0 + with: + base64-subjects: "${{ needs.release-artifacts.outputs.hashes }}" + provenance-name: "argo-rollouts.intoto.jsonl" + upload-assets: true + draft-release: true + + generate-sbom: + name: Create Sbom and sign assets + needs: + - release-artifacts + - release-artifacts-provenance + permissions: + contents: write # Needed for release uploads + id-token: write # Needed for signing Sbom runs-on: ubuntu-latest - needs: release-images - steps: - - name: Checkout - uses: actions/checkout@v3.1.0 + - name: Checkout code + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.3.0 with: - ref: ${{ github.event.inputs.tag }} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Golang - uses: actions/setup-go@v4 + uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0 with: - go-version: 1.19 + go-version: ${{ env.GOLANG_VERSION }} - - name: Generate release artifacts - run: | - make release-plugins - make checksums - make manifests IMAGE_TAG=${{ github.event.inputs.tag }} + - name: Install cosign + uses: sigstore/cosign-installer@204a51a57a74d190b284a0ce69b44bc37201f343 # v3.0.3 + with: + cosign-release: 'v2.0.2' - name: Generate SBOM (spdx) id: spdx-builder @@ -138,8 +184,8 @@ jobs: # comma delimited list of project relative folders to inspect for package # managers (gomod, yarn, npm). PROJECT_FOLDERS: ".,./ui" - # full qualified name of the docker image to be inspected - DOCKER_IMAGE: quay.io/argoproj/argo-rollouts:${{ github.event.inputs.tag }} + # full qualified name of the container image to be inspected + CONTAINER_IMAGE: quay.io/argoproj/argo-rollouts:${{ github.event.inputs.tag }} run: | yarn install --cwd ./ui @@ -152,82 +198,74 @@ jobs: generator -p $folder -o /tmp done - # Generate SPDX for binaries analyzing the docker image - if [[ ! -z $DOCKER_IMAGE ]]; then - bom generate -o /tmp/bom-docker-image.spdx -i $DOCKER_IMAGE + # Generate SPDX for binaries analyzing the container image + if [[ ! -z CONTAINER_IMAGE ]]; then + bom generate -o /tmp/bom-docker-image.spdx -i $CONTAINER_IMAGE fi cd /tmp && tar -zcf sbom.tar.gz *.spdx - - name: Login to Quay.io - if: github.event_name != 'pull_request' - uses: docker/login-action@v2 - with: - registry: quay.io - username: ${{ secrets.QUAY_USERNAME }} - password: ${{ secrets.QUAY_ROBOT_TOKEN }} + - name: Sign SBOM + run: | + cosign sign-blob \ + --output-certificate=/tmp/sbom.tar.gz.pem \ + --output-signature=/tmp/sbom.tar.gz.sig \ + --yes \ + /tmp/sbom.tar.gz - - name: Install cosign - uses: sigstore/cosign-installer@main + - name: Upload SBOM and signature assets + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - cosign-release: 'v1.13.1' + tag_name: ${{ github.ref_name }} + draft: true + files: | + /tmp/sbom.tar.* - - name: Install crane to get digest of image - uses: imjasonh/setup-crane@v0.3 + post-release: + needs: + - release-artifacts + - generate-sbom + permissions: + contents: write # Needed to push commit to update stable tag + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.3.0 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} - - name: Get digest of controller-image + - name: Setup Git author information run: | - echo "CONTROLLER_DIGEST=$(crane digest quay.io/argoproj/argo-rollouts:${{ github.event.inputs.tag }})" >> $GITHUB_ENV + set -ue + git config --global user.email 'ci@argoproj.com' + git config --global user.name 'CI' - - name: Get digest of plugin-image + - name: Check if tag is the latest version and not a pre-release run: | - echo "PLUGIN_DIGEST=$(crane digest quay.io/argoproj/kubectl-argo-rollouts:${{ github.event.inputs.tag }})" >> $GITHUB_ENV + set -xue + # Fetch all tag information + git fetch --prune --tags --force - - name: Sign Argo Rollouts Images - run: | - cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argo-rollouts@${{ env.CONTROLLER_DIGEST }} - cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/kubectl-argo-rollouts@${{ env.PLUGIN_DIGEST }} - env: - COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}} - COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} + LATEST_TAG=$(git -c 'versionsort.suffix=-rc' tag --list --sort=version:refname | tail -n1) - - name: Sign checksums and create public key for release assets - run: | - cosign sign-blob --key env://COSIGN_PRIVATE_KEY ./dist/argo-rollouts-checksums.txt > ./dist/argo-rollouts-checksums.sig - cosign public-key --key env://COSIGN_PRIVATE_KEY > ./dist/argo-rollouts-cosign.pub - cosign sign-blob --key env://COSIGN_PRIVATE_KEY /tmp/sbom.tar.gz > /tmp/sbom.tar.gz.sig - # Displays the public key to share. - cosign public-key --key env://COSIGN_PRIVATE_KEY - env: - COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}} - COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} + PRE_RELEASE=false + # Check if latest tag is a pre-release + if echo $LATEST_TAG | grep -E -- '-rc[0-9]+$';then + PRE_RELEASE=true + fi - - name: update stable tag for docs + # Ensure latest tag matches github.ref_name & not a pre-release + if [[ $LATEST_TAG == ${{ github.ref_name }} ]] && [[ $PRE_RELEASE != 'true' ]];then + echo "TAG_STABLE=true" >> $GITHUB_ENV + else + echo "TAG_STABLE=false" >> $GITHUB_ENV + fi + + - name: Update stable tag to latest version run: | - git tag -f stable ${{ github.event.inputs.tag }} + git tag -f stable ${{ github.ref_name }} git push -f origin stable - if: ${{ inputs.update_stable_tag }} - - - name: Draft release - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ github.event.inputs.tag }} - draft: true - files: | - dist/kubectl-argo-rollouts-linux-amd64 - dist/kubectl-argo-rollouts-linux-arm64 - dist/kubectl-argo-rollouts-darwin-amd64 - dist/kubectl-argo-rollouts-darwin-arm64 - dist/kubectl-argo-rollouts-windows-amd64 - dist/argo-rollouts-checksums.txt - dist/argo-rollouts-checksums.sig - dist/argo-rollouts-cosign.pub - manifests/dashboard-install.yaml - manifests/install.yaml - manifests/namespace-install.yaml - manifests/notifications-install.yaml - docs/features/kustomize/rollout_cr_schema.json - /tmp/sbom.tar.gz - /tmp/sbom.tar.gz.sig - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: ${{ env.TAG_STABLE == 'true' }} \ No newline at end of file diff --git a/docs/release-action.png b/docs/release-action.png deleted file mode 100644 index 6c0dc61f5ffbee0e7065fd3dcf3c73cdf5b3113e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48610 zcmdqIgHGz{HHH_{EFba#iq&?Vgu`JY8p&3`MR!OQWgNf5Vvr8 ztnBQ0_Tk{REV< zDjM;Sp#1MUdXKNhBDrJe#ulYRd?=Nk!Kj+mNe{y$e8mu9jn0j^p;X>8rTz8;0cnr= zc;I{8E2MnsMHUee^DH?`KFQ-yn1sYb7~idYf4Zmspu$7rA{mOvoUbP^tX)D-QAJk@Oen*)@#7o{no4C7zT`6ob^);HV)L1QT;^;n=w$h|->BYRWKK6_b|MAYo>tx7w80H@s=CDR z@V#7Ev0kSG+OdBHr<~F%p(ZZ7&HM!Ux@fn$JJPwn+FJ+%*k^o3LCQ48fd2`DcJs^` zBkZdu%&=&32a}s1X6=jDaS{1nM?stkD+9%x2o9*+S+S|Hyf8CfURSR=(X!i;6I}N? z*@|8Y44ft20|jdpSr9)|Bf+HJUkY}0!Kk6Y+MHM^O6xTUg29N-BHqH`1T#&-w|_#) zct-pU#_%oT4_H_V0_nH9A4xvKqJy4c4n4m$6=8s*H6>nzt@tFWhI-ih`VCHFaPqeo zuh7}vAARHVhI!tL&JmCf$@?`N)v!P{SHj2G4#Ap$|(UI2R>AyP7N;Q1u_M4 z3cBN4g%4b1D9h-);$l+tAGjxF%E;Rh(Im_#iTAl<-pPNYs)8l{l*U17^(pubeCG?5 zFrCkBZzwwvYC`P4NxfnAf8PCKBMfm9{|7wE2Me_k2FDbEsJIJBgrY4qc?L{7vP z;0g)eB0;sTvg|U6S;bj;9z124naS@q_>E$MSYxua(zO!KvN{DvQ`P%qU}Z3dFUbR% z)IgcJ66ZJp9o_TfnBf7O*GwFU9D|&D94(yG8P~cj+JyEI9$)Uv&FdH!g^#U{$sACd zQCH$g2UNbjd8L)ZIF5@SW4_7dBGYQrD%CpEO5BRMD%bhK7}fdxb^qWd!VR21LO13{ zWKVEVSU$}VCK!1<#1t+(L26N&Sx1GH%E)fiUS-8c30u&NHk_D30pY=jtGeuP>LJI54iOW1@ z-DWXmstOCJG&p7Iq|ZN^!b$YBWBXk+%t{HorQ$#)L+#R!^a5K|%RuDdp^9v5WS0aY=nixK)%@n^o!e z3_Pt-<>*?i8V~&=0p-Yn55-eVwjzx#jvkIdj*(Y^C!#0vq*A$nT)14kT)B2>qjskx zr#7dS)7HGSb+a!2F1oJ!JNSThQPrT*z}iQ|XHxHN-p4+7d|njB6sFW?*hkkFE^9&U zRg@~rE87xNH{ialxh*oVplpimhn*+iG|a29INO`z+&J8|n>0jvwHq^H$G*mSBnpT^Vni`p|y?z)N_!8!*;pjG+ z=5S=+G2gs))s$OKy5Lm1X5?4#V0IsSwRUAfNl_ z#s_%#CkJHv4?Y|}T>NbR$@v)kSp4`*35_m$=@SY1n-{vIlh^>17wAb*$*g>0np9D4 z>ts86>x_llu-R^@f7fnwCM{oILa$ffg#|VlBX=_6M=0*sir30CT-aXpaSdIILQCwg z$Z}lA2^LZf1_IJ{vNY3pvW~MlMSNoR#w)*d?f9Kn-qdRR)VM142cW5lWC*6><<2L? zsj33RDAh1PD85`g+}f64ROL{a&%LSR%wAO__y|!iBPh?gT>MI?rfG~43FNzzUs$$T zYFP(-jT;edRtQWrol7N2&QTVaa1C$^8j;$oyKKK~x?I>puePdM?|H7D+*;ySeY*U) ziTdd0{9G-4jjB;l)2E6LRo~Xa_R&Z~i9(N1!h0_7Ysvx508O5cQz}1qek7(F!3lzh_$UIyhNwK2pT3J@jm{_84`7tYv!!E%q(B znb!`ke-9wKSGWpzOnlm2dkDNYuzz94WLMXu*Q9z>c<38c_%!=Q{6u^>xE2us5%H++ z(2t0On22bOxP`A*IjN*h>O8!L{7Q6n-C@16N2aZK2k8}+z{StKko+?eG~wldn82!A z{09?H@=`K(r%-)2{lOJ)$M+|7ClB;+D(+sb?j%ohTMO^$n^d*)fr3p<$%}f60v>|b zVCnRaN4uFj+}y;X4TL6!UR_6JvT-_ z@6!`Mm+q9}PBiB6#w^F=kzA5?Jo+D8CgOj_PiBvPql_3}Jxrro97yDhjWIvl)H1*>-D7m0~we|>y+54@ebu^(*ttf@xoZD^B@LMFH;Hm;{JF4&iMSc=td21?Gb%%-aZI zn0GaBA1hI8tudc)c9bzBCBSSj%}uFsL6NV9=dI@Phe>Uf$&{75c;R4lP(Ce8mzNJO zmzUQz0Y0L`?2lxg9F)pn`MCdOp=;{3d?tiu6Kp&p{?;iFLS_UJbAtf&ly=s`dT3R}}**Lq) zn`&!AA0WR0=()kb;L-j%Vda4|KcM~3+iL2%>nbY=nmaqPy|!>Rvt;vjeDkXx7-4Tg z=&hrr`)dksM+YZ2L2nVN-!%lG_rD&qQ&Ie`;%+ZOrK_w)A?569Nx{d)!Nx%)ib6p_ zA?#{lB?y$3{iiwfmk5=OyZakKc6Ki>FE%f3HfL9Bc1{5S0d@{9b}lYfXbo03A1C+M z-mFe;)PFkpUq8~8ZsxAGZ`^I2ohW|w``XOe!(D`m>eoR3e*VnU(%bgGk(}KAAqz?% z`>zsqPBsqqfBS|u75?>9P|eoc(m_w!))C4x=oq3r0vy7>>;HdB{u}YHmb(A7z~Gd7yi>wnEe;!e{tdun}0ur@>vu`nEhXwiK0xl zQ0zd(NMb9kstLV9mF)Ki0{w=@V=%w2(9?*JPA!HS21Xo4URpxa8}>LC@hy(ba#)Y0 z*AnfXgY1K97dQPE?r1$u`V=Wl%x9*bbDj~XVQ>^g5K@27q0MY4&HF$@Yn`TiY~l>j zRQ6C^&t1#S47j%_=>Y18iR7W1=xFUdG=nM>S`%TA6aGEKMKFho66Ude^3vb|Z~u3Q zV}D4v2p5N=`S(z(g=YXkqVnnKVX-LwcR(xg|62ok^Z(aM2`=yzOrs#zHKuYFBWf+& z;v^j{MlCHZ!Ua{&2zb{}abx2=&D~u^V~NBaeBR`rTX;$78?EDP@sj%1Wj<8D85S%J zPf@sAi9dXolo}bul@Aa2kcP}-Hw{F|_A0~XEKZoe7_+$i!|-9uGQ$o-ChZ4D>H_6# zp45R@V#UNejj~4^92}Yj3`M8}K}sJA3nfQJM?jhnj2c1nX;pKM6t4P{g$+CWj=8Sc z<(eN7N+hE#<$uf6E>yffi&jAv|F9YL0u>|`{t~FEsmZ)&Rs1+l&|#%zM|B>HiS5@rLmTZ^v@udQWuY?ffuFB6 zVOLCNO`faNIf%n)J_gz+0#R%q*6s6he<>6Z4{Qt}tAVhFSc&sgVR72jbF>hARX9R` z>3I^ZzQQ?v|G)`gv|i9xtX*F9mN-%&K=k*qqVJq_R`9;3T|HG=M>l1l~M7I1--DlEI?bp43^6{viz_{(&vD z5m=qydU-0cZA=?tTbk>c0Q)eJqGDGU=yX778q&D(d~IhAKVP+d%ExVQ7`ZgB#&W*e zA_UyFXOfZ~9zUtqvhH6*vU()mLU3_-k}Q@!3FKHO0z*h<YN-$PZ|9v*_eFe@m(I<1QKmB~A zRx^=|;*6j^BX9~%sb)^jw5vOlBM&hAQRC#`xYC&DweGJ>#A|0U>Qd?pU%?EbcIwf{ z3;eDZFwI$XmX;^tdF}C5@~}_c8WCq&P-+bOkHw!w2)@GtN{es!pX^2`8rHj)llXwo zuQ1QKRYfQb9M;#;Dl00c?|poH_*h%9E0s7%rH}&i1r(Jh8PnKuI{<-EwJK=Mdso!P zWFxdA?2LNMLF0LqR9}e8<)!3nYI77|!$l>;T(-A@Xyl`}O%crxv|9ym^pk_E`mFSd6Dly|>Eo6BHNDQGM%hxg<3(i8o^JQ@r|(;_A&+%~;IvA%9;LGm@^JEiD$`YJ zs*f6?z7tltfwDojkN4!@^Tv3w1Y##bHs{XUw6VeQe*Bk-$ttfTB5k)K9C{v~?PNRm z%s|BauUT#9DpDPf)~+|w6~l}Q;#CDVy$L;sW%$sAN^|CQ0w2%V1y3$*^A#i{g4fyg zT2$ynuUfxmoM$=`6RtS7R3F#fpH5$cMW{j$cj#TTq=cE2}oFiedepN<-4%%D*^Hfh_7p6*CRsl1z|<{2M! zR;1dpiSn$4hf{}h@TUY2>5$CR1SyA_S6Z5yLo$7A$?;;3v(4D6y&(nJPOakVD`*+wCCH3ap3e|-+4BR= zL%W&z*WTokcnbB?KqW9eA|vD zLHE@;Q%?>?J5`U+u^JE;w-CuaK`gqhlVs-FLSJxJ_DuX4pN$LXoS~EY2j{Hs;dBMX z`tm%EFxMUiq=-Ovl6S}roG3S*ek9`!6c@NO0pw^F9BLA%(6D@mdJ%`y4BXR&AwAS_ zuMF{H@hD|1a51$VYGSr-7B(K~E48ar5Xt-(*Q1GRI%L~D52~o!R~$Q7qioOPct^Vh z7j_;kce?9}EL)7c=JsywA5C2M)#Z)?{Ncm>g@1gLay@&7e)w~c+();0$;#e<58sOc z)aI?@qx{SMO}<68h)OV9-NrWwpsnq`Ywx^kzs?|R*?sS|o-|+GHMn_zHT`Y-@#4Z& zpzyj*o65xdigC$3S$X@BNzHme{O?+gOo@6(H&jj&kglcVe14-4HE*Y(cF)c=jZp%rNU&3j`;TzJsf(*8Nvb?IkV@S zU4E#6=1pzt0Q+RN6}sOJO_>`Ugcj7QCVlzUit6omf(<8koIxlD=*a@4o7WG?ZKj=0 zZ@#!($0U(;oLOC(ofx_waQHmEk9WU{VI)5~&$Y^=sVcpz4RR{lCBhsvaOyNp7rK7e z>+3-GY|}J(m7x)3^(pTrJDuOjf?|BIM>vn6 z$C$^(GO=?7XZPUf%2{Wnj#=wn)aY(TQ9RZ)J0ijSTZr0BotB)!k)*7PBhIw@>g#5S z-~N08C;XuXz+6HcWx*RrjMexfhEe z;XC;X;^9Vt#hnkQes}6W(+r##F&NqHuH%?=EKOd#+1U&qhAbFYAGNE`Y__b@Ad-5& zb;EPU=R#rZ_gpH*AB`L&FTFORlu2>h%k`W+=tZXn^@4Ti#OR6LS12+Z;wza!ylr%S z7`dN7>@4??vjFtjB*DXRp`G{fVt5f^>nNea$^^tQoSzq+TE8<1DM`@J{-DNXtY#+c zr-e$?+g$Irp9!F7K$=ZYkenVrJ(Guz@aM9u@IT+xA&O(RXRC%%n9f}yTjh8dXQZSJ zSR1^w3VSrRE8(YOqa11XxjvmfQgeQ>rx7n!!M?jAT6%Pr?cAyIQe=^s*bmaQu<{xu zUKsoqYU@v%g6656L$Y#`7j8A{Ogxp3i< zZs@l!8l6Mz>lnO_1MY3$dSqU0L^XT2lU5$;Jo*Qn?V~sT-voRvPm>V6k@#n027E~FndD_+bM;?;z?H$^; zS?dfj(^yfQ*s^ua0m-<)7_We*zWALB<}S)-uXL(159V;EvkbBCX6_fU!6S$S*zNi< zIhd5)-&Q52&%}&FmVP2Uv)!Jn*NITb_dFbS-NbM{pl?h(Wz9;N50BYuX8;{^cR0lV z_BK8kBU>aTn3dB=lZ@fz7={3r#yhTgmM-p?lLNR%)-ty}XhGxwKO$l$UOey5?izoHi#A9qC>PX2tt0j7BP|Xl=rfl}U zP~r3`+!Nprzu&AUdc`LV=6NfKr6F=V#4G1~z&{=A*84sjdqpQS3kRv}Xank-a7A@% z0CI(FjHh;KT+)9}mSPlXwkhFs+FVr`2@X6^$u2Yb*&yqyVpYcyBV?@BGWCCU5+#( z;}vt2C&cfRu4YtC1?Zh6@d}$o9=qa)r#G(60>+Fy&x?)xw#Ph4fgc5KLD&#xjiB3I ze4n4gr6<%^qNO=I(Qs67LYtV*{)c_&>*Q`P4)X3vK3Eb+-i@G69Jr;YrpiCTK4Zma zISoqB;@RmgAA#C5c42IfCHl?-xqKx)=8%FLZ%s`rtZ zn^wfG=d|7Y9Lnn3ito=#2MuD`x{qB=1T;4M&EckFqrz7_l|yh&%sRg#(_hzhBBGH{ zJWL>|^0^grY5lU+1t#8SB6Mb%XbXW2zVh#uCY$vT@oYOzI~#mQXGQ3Q%zI{Ns|A=r zIFm6CC-uLhGPO$hLq)(Ez~~3uIn!6pYhTnc>iVnYQT98UdM|2_lLfDS2#&h!5GkMV-N}-+Ybdr9JI8>MxUhe2=>;!CLk)czAes6K+L(x$G zM6mh8j;jB@M9266gnx~Sz3XQbTX^XCdqrtVeVg@Jo~`+8Fi@%e&3=*Kg2iEn^D&&p zk;E7yrE-4AcgrmitNee0V+yr&$t-CvAXB~n zEs9>NO``khEa#y?7|@QT4~1ItmGk4qbhW`kgpFO82k*h@&K9o^zDX+2dv64d#F-on zV3bW~{ zrnK~BH3>xW%7}-Z8)=|G!r^Eey9@a#r9oCp;$I$C0x2{}w&aq(IJ!!yhPEBu>a7D% zwi5ipV@VmyUWB9O=60j}dkx0OhY95oCI6lz?ucC$_dymL2yQ3=W+f#Iq)jbSjg(nC zKIJTm{+g`?J#@C7>-<;kuQ4KMEAtYxu>cpBje_ve!Uo-jKD zL&T6Z9CCuVD|`j@+u^2T_Rtp1u}mQyu{`!eFgkt1ce6w6=`V%&w>I5;(mXC=B+plA ze>+h_3UEhwk976jl7b%l49Z#akA9yTu&{)b;cO`q*j}^hb!g+U=rc^0iAM=KU=~|X z_0QtOETFT3A`v)%(o^2;7Ch&-W5qwR{}?qLq!hMXRxL|=kn$1VbcI%>VH=AvBC>^W zu(ugO?Ip8zRRT1PAaA^F1)TMyhJ;XSA7l`=OEzBaJ+ylVXllAet& zJkvZ&Vw4tYvEGc;bb(ZOn8$giKGqNi+!PJxV!zCxN1Oe8P2xK|(&7(#LfJ;7oM?IM zVF@Lw(%c&2MJD;QqojWVa(#L=Ej_y8=)i^TDX3G<6dD@Z6sVH-7M?3vJZI5V#N!o1 z%( zE6F9VHLSqM;J{+k;a+~O9|lr@Ym@)*xMuzM^A>2V&K8^1m;%jo_4gY>r-y926FOfT zB6~I1;TmPNY68RkE58R_3n&!yyS+=|+8b?_6qcK9lPz^VohFIXVV02w=|cnkD*dME zY$I}NL853$cY#>204?aT(1X2D!aFfH#v@VbPf~X%5H8g|U9o?p2OP>{zb>h0TO=D> z|Mb}#fhIv69(Y|1Ia(NriW*h^Pf2Wyu=wOxJRA^%7eB9+9Nx!m7(r|HcaWZCsX3n_YiTjf?GcqR9M&m2? z-zluEe3PbgLoSc7b!U`O)G7>Zypoyi+W&}_9W8(FbSy}U@diVep5M;=b?P51I*aYiETyg3CYp+?R15n!{GsWYFPE`(jR|gm4cyMkJD8 zn^wIj`NN1=0oVxJ-F7WtIo^0}1w(RY#fTle>|y7MFeNe#O+x*O%Bk22AOC zCU%nxlqit8I`=TUQ-O5jkS+7=WdX3lj7S5ZfvtWG)HwRsJ>3d-*c{6|%j-|Bp5zc{ zxA3~s<#z($k8wSW6&Eguw$sOq#6;e-m$$4csoq`I&S`e^ai(AQXqBN3;o%MD&QrWrQzA3Dcq_Mk^m>ZBi>HQyglV%uBLJh7?WR6M= zKGB1Q*gb1rW^w;)?5RZo~|N zVrDYJjE1m^1~+3~YX84|b49-8q#Cl>9%*W~x4c!RwPfT)>u+sMG2&DZl0`ZxKYodF z{}Py@VJ;KQw*{umC=TVRL!t|!@_UEG{i12}sX`lPcA@bgOT=aNb%_d_*S{SDC<5Rq zib54+4VoNkh>hx8n^JV-6wKWjE4~Xv&Lz$*x*qbxJc4Fh6YIr^gO9lOJd>qrUwS0J zyC3GQvAMb-M= z@rOE9`qZ)t%&8f49WvNW7Ki!|4MOEUAc5LyvbJpxYDR&kX6UB#_f7@^IY6?rTBty7 z@?G^*^A__qj+dt+W)QYYftm*NxT7rtzAyM`z zDN$xky0v1aHHhEW;JeaeeRmOoOhra`(GPO;x$-9>^fZS-O^$u z=p$uqR?Nk*Spb>W?u=vHj}}asXEZ!4S(Svn++(d9&GJpjF&bIT?jkMqwmg}#V93%) zNy!=U9x_t-RP_z6xs0@7Tdj_mHv3G}J}k zX=+lm2NHl9eDhwDBmP*#Ut_S|aGM=8J6DE!ZnYJc*G4~QE}ZgCg~-QdE{!w~;{O;f5tP^`xrt&+GH!^ZDtK%!*)Cuc2$vPj1*sJr2Hmoi-;I5w`)!4O zQ5lELP^M-syWoeNVJ0K{9_cf1S(6DRi|(q$^qEUsY!fYWxh&fnoig#8C2yz5b|*cP z5I$p>04{Tfx&uq8FBLeuZgPW0D<~yZPq( z3|As1tRq8hB}WZU`tB*B-Ug8uCb_;A&YI)4EIDTI2Q z*q!y&3GMg^VIdv}tU}7)ICfbJds7Td5q{f4=*k~VLjO%hb~~O>IpmXqZ4PH~J$trKaX>e#g9&&{%66oyj%SGuhZ z4wR6k4;4EP*a?cY!(XTlBl4G(6(n<+*7YXO-V8cstw(AvntblsH+>oZmlYric9)iY ze=?9hP4r5c$NWXPMk5Otb*YZ3bPh`+Ky+}yELT^mx5?MC2(=tnOpD`-j85G_JMP14 z3m#3D6e~fj8WKgx0Oj`B540w9SkSF<&P}{3+)BwW2WGeyg8wSgIQEbZb_S8o+%abW z3jnIZ(B3eD!wN)gfM)wmhnt9WvtI#R8$ml}s6acT`u9S+8%$uc{z!!3NsOAEJN z3U{qaEr(kdb15ohi~3P?t5$KRz)e%gZcJD}a+7uU9Z?GSxg8#vl`XrcA*hizc>Y%w(g z;$G2z9tM|;TZPVAzd1DP3`$Cx(xqCq2`I+VOqDk-zSGd6jJ-(73%j#y|K$8XrGdp7 zqJhgxkYANKo0&7AF8-c#V8=h_Nl|iCIa{ydg8)q3&}F(H8oiUfb?Mh+&b^DEYvR+l zL&IAE6|k6P`g6!fqyvJnW$ zG%N6IOQSL?rX+=9&8 z8Y#T2q?G4hd1*lBmb2B{qJ{kG>R_bAsm~*G?QV_+Eh*o}vO)w$*#DCNMX&?SM_=Vg z7Nc&USC{Zcbjp_aAXBbQc_J{kl*`CVS|5r?)&L-v`=)p86+u@Fl_j-qokeLGi2Q8E z)K-+`9jAyTj`Uw30&yn{4j>A>q0Xdi#jFLr!}>G#R05RPd1(a*h;B}^$r4BPESgFC z&t7hgvf`S2;4f4CzhmclFzu-J;ox<~zNY@n6aa<*mth$>>4H>+@-A*oJ|w64fqTt6)wN zg7+S-=?ivIQQP_ZZLNRDO%UgSqf^i?NPEXLxKa!U`*l*uON&={3i$+n4a;_uv)EW| zmLAlL;t7YHci{I7{$mmGyuEPwLt#DcbXkR=V52>&a#XatsMvqY>|1!(Xz}58pkAXz zTh#<}%Je{WXLMz7%HiPovRvw?EDwP47mbcmK^ZPC6mCagw-T=L#2};%lD$3m-?ZMw zzYTE6UjQhetb`1D(NPvto`KPj(d6W{G_(P8j2fxxvo`wOx^hbVhx5Y=wq*acgod_w z!AqBTHsyu}i^fJ7=7r-mUi~9XQh0V&8{3nuB?V?6P1JIOPq8uWib9!46;7YX%8+cA zuyUm-d2Me0M5e#Jk~Vo5$*5|Oix334%Ux-oLoQJaq zjwM7R7dH=;tYG}{{&xWP8*Jd3|JDTH(lwU=lr!`|)d$RV9D8W!%XWpW@pBN$$*8Ew zs@G;<0%OC-|F!5e2}kfT2{js+Kz5!;W)+I!JX<@S@0eZ0x^t|HoS*^WDXV=PI{6k; z^v)SStV$}-uD?a??f*4s&Rfjsq|ct4@)vhm=8ENb+ST!!yC2?^rE-5^cD}H_oclPX zR!?1|?HB7)fsz*$MueobRA&(E6lD&OlD?Js?`;!M_=I$zbIBykshPKbDP_n%@J^O4 zY?_2o%ktu)^PMQA2l?Dl7ztr$*s{DzS>=Qlt&j)v><}Y}=-FSoKw*tcK>6Tm+y?AT z@LpzTjazRbW|T=yU7)^J0Dtz+58`1y$?TM;71+)|mUz zh$FNZouWR(Om^89^Q1q-2_oY9duD^kA)z?QS(0XiSaRFhg03jpFEY!{)hC!-c96;i zC8MyW6*4RVqSf!i;Y)$q6sJ=Naw#3YJW7|H5>3ViNZOR*a@sLWOTuogm0n(Poz{!%LqLrBJcD5k1>+JU0NP z>;K`nF69Y^Z@NffcEN{I+_41RJF>O#5!e_!wX>y;xOys9o-oahVnNBIWfDp>pVIM$ zDfKm+k#ZzP@+EtVpZ}toD1r^?G4O!6lpbHWmy7)J6X0T~i|5U>sOVnFpx9Co%5*nt zq6LpQBjBj;E{N7qX ztx+u@i2WP2AI$b&QGkHzCnQ^X$dG831JM*%Y(TDJIme~slv7Dd4)7pJr2Aby(y>tv zlA!K@1B?y+`^~w8H>B+Ew_}vS;AyOVpAqLxB+;~~p8D3o!O7Uzr%j*0L{3Ab7c44O z492fd1wAL5v!~Pw#b@~rq7&c!YX)s9pHOW5lRmN?_9etT@!!$9@w!%bq`ind)#D!DyBr=k0s7A6c4R zqnGKbdnHdF@?ut6G_jY+wN{o-%Sl?QFAQospXCZ;T~ zQ)E;iQUqwV(>E26ZhZBne`lu>Lz9y)83nbV|ChC62I&(@VX6ZP?sduT1zQO*X|-Y! z!qC{tJw1e=X(4^qu81-PO}W$V=5e*Ga)%ks%}_-s^=_MgQNQyFmKsF5QZ9G(QNFd9 zPvPwIgE}y|7#QoFg;D_T|5~HrxKGlKCtY1}M&RVzk!=ti#@642sD8o)R!399@~Q)eUjL};Qb7%ule)!_*Lnp` z)hVIpWqjMN(bW6fYl`toYJO!6?ZRPuoL8#d6xlx%?-Fe0xka2Kt3UO#*B8mO*U zZqLi+z;b&V3v}pZ?l#+1(5o{GZM2(H&~I`m$7a^*IP|KxMny#di9Za_qb*!qzYCo% zQ_pj^*$}O)r8PK%z5lbUs|CQlrtGhjl9B*=m#1kYV+e+cGZ8|l%8VzuaWEhw;TMo} zTwr5?(u}4g9pA$TvP5-=82^OurwJTNnT?=)fzjx16@kv3Q(?crEdgk~@lcRYCS)+5 z&!<6|zq(m`NtWnlTyHOjo;(m7S@LFWPG_i`K0kv8bLg1VD>fp z;_8U~=mCmOVd``4(KsV_RbwX%SU8by$z?=%x*uhCg?R7}^KS%Nceqcic@6b;y=)v@ zrTm?5rU+J||AxYNjN!EZfF1WP%RGRUQg4o|d>5zb=jSMR=NIMaMG9qGo*V21f~4dX zuQg{SE4uMn$71BJDs^fTNj=y4)(7$P0~8+H#^$dU*D?j%(n#FBowIo$Mb}VVrwT=JR1A?s&hyZ6oA$H?Dz5z%tB!r+UUs4TsVN{!841iHlftSPsMd8 zvOd`2RdADwrIPU(+L>mj$lsE;08dXQXyQ9xXqU^!cA9 zAylD|1W2hM4Z9=YoR-BG6EeNxe*lRtCN8c zL<4n~Iv(|)RkRcB^6uC6P=u-TPv!yWA3OUH5JIOreYjgH*5v>{(RstJ*lFLdI6%-v zf*A_c7+%j+%mMZE3gYz}Z3@Oy*^lN^M^we0s;*mBu1o~k6BF741{T)~3(fSJ?25nU zK*Dpp?M(dcCQ1WA*Xkvidt+mCg* zO&qK@v_X-FhLHQC^#F|rq59kxC#EdmiKhpdeDkB~=BSnQ-O=siFi8{*k|Pff$&pbj1x|pgc-i6$ui3IzPjD7yB-lSKbvucr$7Hj zB6RlXyz=-ZoIF9qb7PE5?Cy((>-Jb5(|PQ4I+1(fdhpf8SgKdf4&BG1bC4o2VXNi-n-um=b<0NTS>Vl7Gs4oB2f>DogZfJqp=EIL z9T*BSx|1b02^vfFjd(l!<&~~s^iubOSr)E2DA#Qr!{_<|-TmsLB3sJi!(CP(=0@qY zkYdT$4GYy8jgqff;c;uKLF&Z8V=D& ztw`EK0?N=gpXHTlXOOxfVneeE(KzgAmTt-b%m+c4$RuXI-h5(dM6UB71E<#w7`#7K zpJ27!9l{!BYR_z4`#(nKrtEjjSo^b;LN4Lq;W!><&>bWI@K%l4C#!DHhY~LP;CR7X zueBrCd%$J_+hU~$g%OKT7=wvW^xCXf54uQedQuW*cUd7bNa&7z*A&E!M9T>Kh@^NUxwk)OW0-(x1dsL(KZ6URHM+8e=dKki9#VC7fcWG{v87KeHNss61-1nfH)9mSLd;9>B6n5#FyZ|PW z;kAH?fNJ+{@K2hDR*!>eOS`n|NNv~29w?Yqn{UkmJCnUomaSZ9?_R=rUS?f`82&`*y3c z7K)jAnsTJ(x*0~?JURRZ7Nh~n*cckp!slh3rC4SuXcw!7%2ATijb&wZop;N` z-96H;ZCRuj>JUP4Y$NiD9wxePrtukN$eL&7&OSf^_J{2J&JhPf)8__#4|{(c!buKj zEbdrqwPcW~$?z=fO)h+&RRAueV;Hj%@vv>-r&X12@G1G)Tdw!W3yoZOiH5tn&97y6@aBbP^UT;ss zD5QxImsQQduw z>v3d&1JAiw>2)GAdk2jnWh1}+Jo)s|$0CQjiH!ilI$eKZN)Lq21=#!H40YKg!Wa~T3P?voVWiVW>$!bCh8&bhmSb>E%~h~KqMQy!?hE^8LIivvNVQ@QvNM5z*bK$^;SE+s!~C5v|_&88MnL= zm`r@^B|qF=(L_tD_1$l5IjKTy@3H!+?CIm&QORSUUem4i%CZ;~jBEb&@#o{clEF(4 zJT^m%(Tc$)KIe{HKTXEOGRc+mX8sM|!Flzmxrjo$>8P>6+q7C;Om(^pj`MSRM^fHA zRqIMXsd5K6s`BJ9oII%TQtQi9iIMOz%E}HD6k|6tcOk{Mc3h=#y=ZxT;Z z-I;D%_q9Dw%|2Gvs}JbQTn~tO_DPkq=FZtQ7D}a+bp?E5yOjechyJvud{1ro#*L1& z%e`G351M@lR8bv0^p6V$9CZcg`hhJc+8=| zG?N8h+HvKx2Tk5eIXvci#a`{6|4!chLeX%nBO=q@x^;+9zPEI288+E_GnT^0 z&jo-ttFId)$-kpXGdwMZoYzA^>!$qQ!;k^t*P<$W*@G7uU%B>w76_i?@*7VjGLyX6 z4+=AM-86k@rsfv@7KhnVHrQr7J0I{OVB15dau8zN(OxhaZZMF$zby+mYc~%e3Eb~> z;_WztCcw;W_Ifsga4)Akm8n3d-uluZJ-5QHh87>cF61juU7rq@<|o?E!Sgs+k+2P@ zm{AcI#+%E*!4?XVzMkYA5Za%+wG^mx~A;|f9 zbvMdhrUl=AKY}pYDR?U&GA;m3^f`>kP0Nl|@e`9>n`7bf@l!cm)V5ze=fqy(XhSjA z|0gu&QG)A5DtD2@et1Fl9@yCVCIsiT_HNe4SsTd;;#mQP(yuejwG}psO@o>39Nj`t zjLa%4LvAlW?`t3?&F5U*t@**7xbRc*(t$;f$>Gzl_AQ20515B82b^-@2;s6Pk)!DqMM8bU*PwbtWp#5rP`&mob2c8`y)(RKNL}u`T;;J8p=1 zZ^(sn-ZI?7U#`A0wc#Mp`OTAWF52pGm5>+(FKj7s=sPO%72`CiFWs7$SK8Ym;vt|n+hvgIA z!SrL|g20KbwdaG(V+iMkS=w#mhR}>(_uEyMVhrYt9(Y|KM-;L;TfD~+*!C~n6OxRL%f~uJ1WXPTMadT3 zDf__o7VAEsJhI*F()jsi0muEJ4-L?GWA1$ zxajG_IH72q3ehSkuEsif`rg=ySoQ6Oz|v52Iu&QgR97yx>_UTi%SW628dM9;SXz*A zg1}%dJV#UQ(Fkm`W*7;x-n?xx0yZk@a^2GE2Y`yybU+W+bhdv`vrOBQZW?t|t1`Q? zZS$_6>*sIkmSF_=;0Ku*2z5b*4I%Y-TP)cT)t@)gmp;p!eheshjChK!kT?SyN}Sb- z_Q4kF_!rHNdm=~En05y-Svq;GbwIF(7x=CXF&(aF-dPoX?RGeAUT;_Y3g5VHEbWzB z_{m{#tfgn6btHup5(itu*0nniM`WSKOn3RARX6?3PaSga@UCAq$-z|3Jkv$$g$r0# z18{(10dxP+5l0EbD7^VPoMfGg)4ca;|*B)a+P&A1P(u$%^eqN94Ppq zI>TNFI?J}i{M=d~l_EHdV_p7ra>aZT)1(&L@)W7X^;3d896p`)XAl8TP;M;O!3y;i zt;EO5!-ZNCe_rK6chwJ&Ay6z#*Ii&C5yqeYmmU{-^BNh?Yz3{OTkf4)edaAwN&ZHT zkU#m4lYk8pq;a-cQVQ8%{d_ubfEaqD?;pW~8^&_=xp5EyQLDIH-C<5y^2e=Oas6&d zK|mnQ2-|JG1~rOa`5L9*hh)PVQEH4VV%lQ4(&$dFef>}o`s2|US!o)lz1UM-lp@)n zKB3?#RqJj}wy`h>eh(VFu2dAg`G6}dwe3DJOFF$JXksGD8+$x4`>(>yX~-J{Lw*oz zcwMr&;^&n1Cnb%66^uwSlRaP;tNJyopdU#vMyHfgh$6i=bk#o5K{N|1VBqir%!!w3 zW9h2|<{*gD6;zE)ov+js2eJKeRCsV<{#}e%1w&n^VG|G zEf~@vx*aNjIQQ#1^jCA(dmSZO1tc8_9kcxFpCICkx)vopuf6t<501?{PTs>cU5nMU zksna>WToJ~j#hSyGmL>6SBTRco3P3E`mM!%QBI6bvXA`}O?}VnH*ieIK!yn9u!~kR zB!>b^S&v;ED7K2|Tq>3j;Den#O6rwxSgvXBSnero5+)rQd{Bs!f6bu>8GPx-EPms# zY#;o|$pY(_nsXa2Pp9ntj8;R%)MreyH#o+k-Cuf)t5_KZ)-x!5*u8u4)GKokD(6=cDkYY$AQ@M@2gWZ)47e5W8Sr+n{yU`D35^LXF6X$gZ z`E=w$k9^h!exl2{bNGZbKwlr7>cxvB)_Bu>AXeV_p2=a3i9*j9Kr&pm(WLRzt2|3Dz_Zn4EerUJTg!z7E(R!YiUoB}i zwck|Gi}fB!+z{ZOyM4U|v-n!7RC#CyISKE_v&d*1lA5o7hUms=G0OGzFv43b>Z!Z+ z&4+m{CWl_gaSgXe@pf{9atMM`p$?amDV3brYEj+2H~#~|8NPt^!4y~tfpb-75WSaq zM+H|>TI38^2F$&90f^@96c7QaGMjMTqdmbpl2p=zi0(UnE-Ck?TXe?HnIcb;Ln8J# zbKO5SayP1z4c{QiSB69-#y#&9 z#rgl#SutHHqw`8?Bd9Z|OB+sQ%Ex!I ziA64z2xXfgQhFoyxSR^~GuvEaw~swV{_KHg|8facN*0Njey<^yW7rk1IJU7};6K7d z20*HAi6B$TG%SF2oK_Oz#V_*xGC=@>JFWdG`bU@bn~b7@hlnDx;UmB_R2wN_Q^YFk zh9^Ho>mp2E6c)a(V`J?qD`c|eUMc+_{MP#gtlU?QGoyAG%Aqs+X46M57LKC=!6?st z5@8J#0S3nW-*<66_n}Dhjo3p!;uU*F80*Ln(ew1<5dVW-0P^#9U;xn@{Q^Ie2>(YI zkK_!%^w<4C2+H?S-jgN(CCqQ??QWBT;5Hz83qSu!OutZQ@_8`mBnfg$BDBqHKIr*G z_+jtyl18FmM!HD}*{wyK{`4aSJ#ha8nspE$DhlzI7yC=+=JKbAMN??w$I0V-5Rl9mltaN)?flNoMNd{c7S^fe@iB3L~fF45sgSlQof9Czplk|=-?tkdSpW-mSs0Mfk{Qi6O zckn1YKvnPee&BDq#v}&7?Jv&M>-Z0H;sWbK1a$elfqH+_N{mARo%!@=h1P#1#P!q# zWc$&XopgWSTrB`7_TN+ipksycrLl6OeQ`{|V}HL$bG`>$k}e=G_ryT#l`X{I+1U}@ z_{jrk@e8U9m(^gVIR1Ei%T_2bhxQuvz+-{r2jccvP#69*pAZ4i9xycVRH{V5@f2f>xM?r57Jd>B zGKC0G27mDBVpZZ`G|Cuj!XLBqwI;-X7QUbZ`&8~v6Z~m8;aF~6+xDNn4OQ;ovn9>A z`}i_BSvkT?Ked5x*$HqxACNj#xIa28SJ(z(X-^dB2nvWC98#U~y*wo16HtQpDKz>Q z;eaq$=PqtPQqzSn8)fWsTR9Z8?yJ`Xxxr}E<1#_5Lgp1?0-t1)USIpE|7H#VfnY4u zdHZD24)%yc$CkTd=?y182*J`1WZ-dCp;lMsF88Ioo1APeH(c1ZcE<~3Yi!dWUnURF z6k?zuErXG;QZIMX8{}$BmOw({YFQyf-@8rU_i}+njN2J!O+2)2A1s?S{OS&g(qDDc zjt2q+g9s?D*S$Fr9V$Ai=uC zFI5hMV>MD~dOOu>s zCwe^KDJ_&mV^~bf6@UF*r$*=^>!uOwhV`KvSSCGuS5rbo^_b59~%<8>#8Zc7CEnN;|gbap~ z2wR^yMCYq5h#hBY<}euF?~T_7GZ>9`e%?B~?rl7Y%p+na@W-+)Q*#)K{pyn1RCf2` zrJ?!6#`-dgf&=gO<^$`oBL%5iH0rD#K6QvsHrBde)wQO09Dj{U&o;?gwwx$FyPzNG zZ->MpA+W$%gKW#r2X}uw@{lQ*o~EFnh#6|MK&yU-{0NlM9h(jRC9v*(mk|=slqEBo z=)2VD4`DQhr?R_TMMx8z^!5di`c66&Mzhd(M7CRO1I7lQr={K*!I2sT-y zqQJC4&|jq4ssTX7WWeASc7l3!C!?T1^pZF*WLDr277i?u_n5CX!z>Ko14L6cdlh=) zE$WR4m&Q@j^71)_J6l_OCw2!Sdbt=Q3*|cg0XANHi%#d0)$s%R$>vcgwbdpw{ppoE zLIY?+Iim4Y<51pS$fjRL(kq|kN{dnF90@MxRW6q=SM~3jhwNGRDENdplkduxnP=V? zdE28?DCIlZub58wNZZ@MPhcP4<9Ixf9!-7Ofj?S+Odd(nfiaq1B(skJ#Au!`^LX7@ z;%CtAzLPg~41j(}!OwbV0!Vji&GiV|b<-mKw#JbsH}zt4Yng^+-Ya2l#cLaI~qq z(5O*f8vdKRbbt-SpBwb(_ewnBCZFxsB)tkK@-^O)d81j*iBVoZ6{`!K9$6g^i|wfs z-Ptki*PUl%Xr%RC~EdJngj3MB3UpjmakijS4}dXF4f_%>5r%}q*f z0@>|Ihn4#_g$1J?EZv(SX2Zx%-NHt}@F_Q1h%nBp5B1wW1_(M)@UO=QN_*?>djf=FCjgkX)#MIR@|=RTHNmPO-_R=2DYPt{LDaUlgd)C zQNuoMb9fYBJ~7P@Z3nC?iW>C}X@2wcUpk~6=#ZS89P87y=IU8>>oKXlnQMlHd;i#r zC99pK3czkhC^E?JiNhv$$j0{~EHZm@O^|55X?0kb_){swfH-rwPdM8;jni%H%pyf2 z4vMZWSAR+Uv4GQ4S6_{qC8V?lpUaTGk8KZDO|)-t+>P#VOgkgTuU_79Zho4f8tW;t zxz?FXl~LTl8BLeizMy-z^**;vAdbfMXu#J~9hQSho&ih_4-#ilRDkqjXbtyO`|MIl z-JMF}!#FwMrGR7oI7_gh7cI_Iz9*Y25nuThzM^N$zB{x<^=i(5Iu%t?$lHysHQdk) zzxc$+O?Q?M{jNft=|iolE{gAa=)GC1>w($(rN(EdF>MU9M0w8T(eUlz(DG+pUl}HT=v!%tML5D zVX#;h<3}(UX!pOIR&)h85qhiNpMc*-OaM@SEXp>pXt@j@_NLsF1SbF}q3EPJ%iO$uoQd{gL;Iow>&0*QNR1#xojmc==qA4Hut z#{|t{E{|q3r)PY;1cb`N4c7xy&0|vS=cP}3Z}=Jg>^qMLA_)yr=Oq2$IW$i;bml`w zHU}%;?(6ho<2(16me^*pbru2eq3-sevh@Pia=jR9DvMnd_nVRTuB~}l`6C?9UVTy2 z24dymtsb|R%wO;7knONb*3Puh2jWys@hbHn@c_4qX$^;G`nx_~-k&oxt0^{=qP=TK z{#ZnSnlP?***f`BG2-Q@1kWT&hA2gax>NK+@I8znvND1+U|}@ zJ0F)fn$u4U+JUO5bWt92BDxz)ek=Gq?_L&}ZOt4$DC%Bvi9>FkK_pwZ-fu-}&6mV# zp6q>XJ1Lp_ko2YT8O$ll-l0w^xO0`jiEPF)AMjs4`WxPA?}$70Th3Jp+AEou_k zvia(St;(tV5ya~D>#yDKZu$Y7QkFOTfp*$5PyKpyFJdLK7GXxF0C}<}t1I}@QHd?c zVQU<9JYzNM*f;(ia=`g<<1s!$ID+6RuDWu*0l9 z3dt9THv7MBDX(sdXEdYWm}jMM2<~8Cr#;Q>+|3@5k8|AhCLe|AHK+;qs8sr6*%g&+ z^b`7F9#*MJriN`bYj|w&H(PMvw%TkDPWbPnEUf^f_rXU`Q-NeX55AKP(@xj%={z7J}3C=K*X(!6%SEX)eN@rK)QqBX@! zES|{}+|LJ*M<6b$U(XJNL3c^{5rltPBz`WRXS(h&8;S8f-5BGjdAwQ@><&2-bc=NF znwlwCgGdXIxWC}VbaI$uyS(9R|1!OA+9zbB-cM5E$)l3W+Q;&;AeM3gmJ`sk)BX|o z&d_@d3;R=r^0uZWVyPTUVQZa^J(0C=wb4c)5$omq!6V{y^4abL>v!4CV$TyJoQ29a zqIy&N@)g=$Ft@uKl6JRBJQyYg1%S;Fh!_lyC5VKSiNYMAK7>fPfhzKL3+_Is><9w1Z zR&lN2a@W89?UX-$w~wnN0>1S~0&w3V-qc($rHoEH6II}QBjJTKu4G|+2LOVbi?DwC z7<*{rI4!q7(bbDfBI4o;QK2WnD|^yi`|B%umog%>i%#=hy8CbZiTThJNb71HmcITJ zh!)QT_Ttqhr48H8vJ7jrtZE&oZarA&G48gSPrj{ z2?pMfK3=oS#RtMC1e4*2VQ+XgF6zt426+>sl4*SQW=)S|bhFvl-7D^QeJHm8!{;Jl zh4bk_HogbakFKfEkE^bOaUFUOz-RPE{9QO~Pa$e3D`iz0B&v5pVVAAXkL@qLY+*@< zcSMZb`bh4$@gN|6W5f|(UxM%w1goYYopT9PTt2vi@3<)dZs*mw+ z2sp|(>7EQ%^z^^#uxJ?*#5nN7wi|?Y7MHK(1Txj&NTa*kC`kZ;F-yJp$;%>j=PhXobxlFw(&#{=FTV zzC)B5)aT5-j;t{V_@NbfBgv79k09>Ynd@;oCx@vl2GmJOlHnEY+?D3@awRW(o(l(R@^5lCw_I4njRls?Zc32j0A4QoT|t- z(Y&ID7t#+VR-ZzWNwHbYIN#E-D=pL7ZHG2qd(IV4%4ZbFo3~Sr+=1Bx>=N}(9$oO1 zEtHT^g2$N6=EZXJYYEidrx;nV>~h^7S}eSfrr8*gbILxUp>?fj2M-;orqXz0)9;mM zJ~7_4A4Tx{;>>O-3n%a6&JY_`a{~FSn0k*N$QNYfn z-K-b^PkfZHndTm#UmbMqiO=c!phSTy(_wCc4}fWP%ytrqC+}|sj1z(q_#nm@VULr~ z0XA4#_HuvrQ$leA4~yB|yRWjLo?U1reIz#U*Q`KaDhe$HDjwIDA?&Hvm?mx?!;qep z-MAG&i}&`RxmKc%A2&a9*BcahWT~8ri@!Lp39Qh=cV(OJ4rC*Ds|NCCI+|uNMezrs zj8ilyACduK=l$Z@XqgNkqQC4j%xWL=(EK*SzN$2P7NnN$I35Nu!*(U>g~QNu-1D@O zFNIj~Vc=USYH)~|H#yabr822EhxWEE=R4_otkk(&BqvGrES;j^Ho@fs?r#IA@#^dP zdnAhholn++#Cf=%8YUxM2@xlFyK!Ntb~$$i!)_N3vJZ>E+^+HhU`M!Rp||yTvJPO6 zwa7}IUU3NnOYLvKHPfry@tfeO%7x_e0Aa{=uxiaCK)oufT{6@ z<)Mc4(Cb1-@M$YviXffAT|#vA4|bGNe52`(#!+mH zd&>9IIff?{JwG53!qUI>WM!$F)-g4C_G29cT{xOXqz_^GG9;g1-%9`qp5Wh8hp{@a ztuFyFV(NT}&#xt{Hd)b7sWFV4uE}QfV;k@jfD@gkwx{Cu=my-PUqA-!(fyt-9OaF$tM00et^!%U0hc;d#z6)iy$gW zsnH}9S7>KYUI9jwoG5saE5>`18^Pq$IA{VSe|m{tW?%<$MIhGn=##;%lYpqpv!JF1 z+&+J&FOU}*{$J%KNI}rAUJ^SI!1G`&FdD^xx=*~+-JBZOkmCY5A~e7NRDVreC;lba zUtZgOlmpCNoj}To2PhOplhGj^5L*9_$(HNd6%WM$7KJ`POj8mF2nc8qpdLW(0Q#Hw z;)_q5oeF>hvrjY*JpJBW{4Z2J(iug8HqMdlkszfsP0LW$2j}w(veb; z$&`vN(Ihtvx4b0UxrSeSPV1^+(Va?_O{c38Z4YN@xs6`lrpw~#3ya>LRBZyXD^wUS z=k*smp}GfLQvn}Auit~ed!xDDG0#yW&Gukk9MFFvPkwtzO69&Mp{9;^I^Wr|TEnzG z>eu>`=$t(Zh%7zd3ce(n;x;(H!OF#;XwTP`mD|ccBYCG-11pDKDzJnUsE=K(6XMBC zu@Yn~{jJ~hXV`TuUOFKD<%P}at?tc5%9R373gNe>I8||!sxOpJ> zc@@ZCPSU@A$g%Dl>}BwLEEF`E}EjHCRBRlIZmbK>Ra>$@mm8#*3P9{!vW`y=s+ zT(NjuJ4hSi_7*Tt5hSIe3X=}*16t=&JOc#cL!;LCjB32cWQsTzN2wwdnWQz+Dm8t* zw08SD2?%({V(23|AOsr`$TSFq5~}CMg|=_Fn11k9kdrIwsuBh~%H%efI>ms3s}M+) zJh7|Snx{U!{QN(&21jcxI$&0ts?sysqdX6v5u#Vy!_ES`_*c+!!9Ytvm?FvqkUkYj zjme1FzQ{fz=D-0Hj@Y0e9-d$R01@)uz1-oYA79c>UH9hrIr)B%)%%gS*gFJt-h%f; z)=Aox6fg6^Td)A1b!pek_mXUJ7D0JvnTk(zbV+a9On*C&8owC4Vtm6(b4(@iiFwIj z>LY)T*e;}9`9z;IcOBRabgSVkFsvBso(05^Q1xu9-r_39f{zQe@d^JDM-nGcV)`vD ztOk;lD#4a>4F91f5nS59FzXCa`r~!_KlT+G5a%XHRLTG0J+I#j0d1L-fF$~VU
zW|H!!-ULv~fBynse!1zjq5p;nRDg75F@K$D(tps35H2lnv$g=mA49-D50HA98LOe< z#a{y9pTEy93BaMZLPxS@3(XUHwS(!2mkNZ2rf!s# zMBIT=-t*g7)IHZosRM%E5cCSdDBF^j_V0EOMb5xA zGs>d)<1+WZewGF&5yJEh4tyCa|NN;W0e6cc>pA_~p}>bw{83{s+x1N&IP?3>69~dU zuq9-X_+uAVUew(h$r|*#-=&Lt z1yMlQPVjei6`-UdsCW(?7VS!1ANKN8bhx=Q*{(((0mtzwDAl$fLK#-z%WfxcK60#k z;!fnCtK$}yREStgApGwkRp7vT^rcdmEm~~%C;I~We};&BeJrxsidED^7=OBWR0KpJ zpHe1x!Kgd|h=F(6d1ndNa29@H;CoIy{4l!jPG6p2AAh_ClHBD@2Z3%j9OT=bY5M(o zblv%jy(@kXwYZ_f?vD_UOcqRlYDyFuC+8l@40q@CvR7_?dAW2q z+@Cbd`kA&Qva5gY5rfzpZagt-d3Z)&$YnLJm#$ecPoAx_^{f*}Hjf;1nMCsMt2anZ zqf#C2(zJODrCV}ktIs=KN180gJQ3mjs*Iu8fAC@Y(OdILmg zh2VED2HvY^BFQ*e2~O3P$K(5$uS{4?fo!(V?4%pX_(H!3{ix{=(meD*MfKhLS5@+1 zf;b*gP0#Iu+;go@*NtuIl4-FDn#8-q3aaptz!`CrUq&DhAPS%$jHng^%?jbt-LL9D zId7JeVv2Joy@w+Z!Yu?w2z?u8UXz-iDZAYEeFsND1qc~*()^tH@YI8&VSoO`lK`Gw z2?iDu`#29*oWJpQ4F$CK@#p^SFXH7U1JJV3EPRDytNSJ0I%G)orq0D`AaOeU_$UwA zSx5LYs#yE?4yex988w{KOkW1BG5j>v6Kty5MRx-!Gx}+$Sndh{>s-mcO(HX*|bF-QHUEO!w_lY_Sqrun?$7@PRqR? zMfuJ8Rn-y}aV=v zvLwVUKIv|2U87|d#kaVQP8WdCa+SMC3vz&DJ9Qo1WwJfWxLEw8>AEFIJ$buxBRo>? z?YpwPip}?;y&0kV)O67AbywRLXU9sLk*dzk3EG|?Ow=OI8w#JXZq}3yiW&88x8h-a z*F>+PB{}0)LQ$cfzUnWV%$P3?qH}Xjw7}_Qd%lsSdiuHkrf9p{Hh?g0*8r{fT@>E) zyqG}p*O)0rMwOBE+>~u9{X{msAXk7S&)qok_4yg>If$Hsy62M}pCvp31-X^Y(5S`( zl;kM)`?e!acJM*; z3&m=i7s)}}oQCG22Pw>(<=P;4wHYZogj)?vt@K6EWHGuhaH8_Di>vR%+>hD^DOr!tA_4<`}k zV6lpnYBUc%R+cPtsyEn{4;4CmGC8gu8M@bB2MNn?IFx8059(>U95L!O+f7HBFEvaL zc)wEe;=DBtc{rI_*&N|~9=~R~F|AsAn>kW8I~e+|a|cqOVinuP732yyqH;qksyRp6 zGCcZ<>fxCUyV01S-QCtxW!&ALcvM;3uzhIi>%KgGQ^tq!#nn7}8BnGyxh|WPoJcp7 zYQB(@7#C(KmKW@Hw32GRQrn@%o?Xs+R|mx6G|BddkmL|}s(t3-PTKy_bbHlky-wQ4 zkD|17KiDg%W21!^ai8ORUOj_@l8okApfJZ=#r0Wb)_%d15a5p4Fw{x!+^o-9o<@Y6 ztC^yG`(%oyt#o~nzq1KQDJ%2Jd*G%u6}y~m*Q9>jYA7{XKfghM&@-dewW&WjE{kOe z7#w|L<*^u;r=Os**=3L(HKnM^D5R;VNF1I--RPm|rjEGn{MNjzWfAbXq|^@$gc&~{ z=8!dSJxCi3CzuR3v08I7@aNmY^T(k~5B=52+}T~LN#wuud=fRVRbY??m-IB15S}ym z;8UvqmX0|w9DN;2sO)JkTB2w}`C zmc{Uw_^&t_aG1!SOIwcpaF;JHn0QW-$f?m|(07vXg_2c>-5J)-L3sXGVISP%i^}he zGj$R9d(tdLEOC7CACW04I(IjAkofz#x4=3j;X;_z; za~WBh*gVTx2*wSSAQyswMC+{_5rX+iDx3S`@~gZvGaEWMsZalrL#{@Z-_^S4cJYjc zgb}0leatWpDhMto{7J}A)C)x+`w@YqDDxP?s+d&BTSS|!1h@IhFPWD!PCLqER0kn6 z0IS(B2-nOwb>(>na?WPujVvQAl%~rNqwb_^xW9mD7ViqTcF!A=(>EO*VA#|BI+AQ% z!l)dIZrKVP@Ymgj@R<$^rrXo1l>wb|S3Sua-?5P!moi6TS%7 z%<7XgdGe~FA5C#Q2dL!rDcv}l1osvE^XlR4D*1xSP5y0ur&>ddHbo>RAsW^UvD zbVT#Tg%E|J6hm%DL3x*{g6EaFbL4k~!2mtI<95B=(S$P{1FWZT%iQr^*Lb^VO-8pf zmM3D63nk0up@I2wps?Z;=@HaU-8K9beNErS# z@a!&6ZdIzm&g)eLtnd9WOmeW|1kxRtWTR`Atznn^QL{;p*GGXGsNYf7`|wX}ZqSc# zP}A!VPCih#Jc#T*I-Ujg2n+j1WgOPI38}*th|i9?eIL0>wO=5YLl7u@o2Yda&hhm5 zBJK5k9=3-PdRc=P${OTxYiWwxvTuz@Dv?hCXS}A9IAYws3%<~*V=mii!h_qTIEIY& z@ycuT^laXX;|MoM`X%kf9L0gA@)g5|3UOuy>3tMlYG_?wVEKS?_@Shytl7?@>C9_5 zy|XEub@0?^63hA2lVyhjBkbID=?YpiA(ho34v<4nA29jVEg{S>3$}hRjRK|^Z(dCa zbF~quMwaT-ngd#%PCl;tsJdiHP_nSgYMWk-H~YrQR=IhSW| z9v6===QCPmgQM!In{6nWTDP&xi#RlpRW?+5({s(STX6jl4&a8{jXhGQyB=z_+oH}eDnu~lNemXI&}eBJ?gyF;czE0? z+b`K@x{w|3BKSoyFPjeF!te%gl2x1(;RQyFI40dpbqPtpA7IILZ1CD^VhK{3oW?z5#d*T6 zA98{`jD1bFUCs0W+wIhyp4he{!WTuYt*82U*{z3?Y*|r*z-gpYoVILBAbbk&knUtX zjy56?gpgK;EI|(#88#^*gLQxS8gRg5m_cDTOgi2*2$@UZX$oxB#BCt5T&!Cj?*>?m zu+Gm zlLv2uRBU3#eK&-jE;3V6fPQmWKk_;gf<9qJO=g@sSy3^5w9DK9p>>5xu?*MpTHOJD zc+IE?*UUUMf#3-^f}n4vdme6px#-by?3#!oFfYZishgh?1l8$cORb}~WLhb%2S;B! zuMU-$I0!3%b^MXzXBx~ld+9a;r1!|8lZ_pxLGr7{ST&RFg&L3vGi9I@5zaB3)~|=INdkFTD=8GA@pv+zTgq-9{Rqz@cWCI3T5=qInS1zN z>b6IdZY`HpZyNIi+{}_aRY6T7j^)I5k3(0MIl=vXFBz~cWVoSjUMF*M-IV1fW5o&Z zV&Iao*k%7HyW((9$=o}7R1?byoIg{uVpNOEEf?^u*P`$!np~`sQiyrQnzfzG?F+?I zn^e&O&1OiZ!NIq^wq^ezD{1Z^YI9dlRexf?BahRyE4f7{kQsl3z)tvjAph*!zJ`3% zQbq`)MZ4;wvYvdxA-_BpZN-oY2@YD6B_;0p6qf8@I$pTIly6p_j`0pk0M!?L?2fbx z28(vdMa%tR&a}7#-i~ly>c@H1&oQLi;2qNiXo20IM@aJPy%?hJSG|I%P{okTjt^)7 zXY5cxoZW98Vhy}kSC1jrG|K~)_TXUCMvbd|SYInH^_){&PrT1Y;A;J&9G1SRD{n=* zfWC)I!da~eUqMSnB(uCGgPfAFMg&$&TD=boQr!22t$&uMO|=w5jgv5&j#Z{3u}o{# zxh7`{!|Is8jN9Hr=_GZk99ZZk$Bq4p@P-GprC*q1YG}QxzS^xf*N)|0I*hbUhPMP? zjxp8S%xkrK6OOQm<<%`Ky{0`PitWfs&Kt_YGNH69b}KlmTT4KG+%D`}vtuqPc-jUY zfBkwMHTC-8+@l5l1Frk=qEp3F2IvxL0bIMWjh|46-2I-HXwlJs(EZ+xAuo+w-Tb5S z-2*-7KJFJQ_vAp^tM^LaFKZ#Luploif9;ad%S^T7(zz=lp=_KdrCzINc89m;!r8nf z3K7~`of$(lzzL!&10$TsDXo{ojn+T=@*sES&_KruYF3(ANN1B+K%L8g|Pvu)z45$c3zqIi66-GiV`)8-NTB)2E)?LA=o6(#G36lM84`^ZMy< zUyH`0>U8!g^$&}W-^vZhYBDQIfDk0QPPo_bFY8G8<+teE4HjUn?*Fyt4fCxcBKT`~ zytIDC>fv4Xz_W5~O#Ju9=^jMAaSKQJ?oE6U1)*)`A7<%}&S^FK{q@_!SRo*d7Dt+P zcV3t1Sy`1+{#Y)TJkiLc+}tNLF;%`vc6+8Cc)t&*)3lKyPo~y{_1ks>^ z$>OW1MkpkjFz$t|(H-^en972m^X-IvEZk9_*5KXtc-BGmzs(U%&b+5Ou!J{y<(pQ7 zWJt+PreCe6y~cCCgEQos<8xb`UM6^cz$z^*ov0)w9jR2-_Hf&C+s$e5y93i-G83JaDvk7CSI@=EyzYvg7rKF7ptEkm}zlWsr4fr>=vyi zO!=M)-Dv`{1pHLsK}3dFiOe;fXScA~>PUnpc@Oxhbm})(eh6ANvN?KjqRaTys8< z1VBCg=P^Ry zILya|$3Bm#l6qjASwRW1I1U^jiFSE+RO!?-feZbEH><3-tFzAo5?j3aJ)I486Rdl z#h>JGtp(Xo`HLODq4!{w6TGmYmVekYNJrmvxvEF6QocDXzg)PEzfV2u!SOI|5Yr%9 zx|UiWK%JRrJz>I3O1Qkb4^%l%HSXAUy)e>lFKs1u=eSA0edo^dz83;a;hOsm4{XCc z;)#wSlA)lYD35G|3i5nqzpI42d?Ke!QAvsLW+-kKKV6}kH^Mtt%hljrfWj!0pmh(< zVR_^a9Y#qhgtxkQHd4Qu<>SO6Rk+N0qiub_U}Grj{;L6}tXGG^n0sN6iQ=*|92F#F zyZv>?f4?2_JTE<5nC+rhC(|+}xi6ki%E}L02McCO$FFUOW9%0`*gG{M#3O|ezSdc3 zb28c}tqBHYxri+HN{EE+$E*93%h?9}kLw*~rH^Oyu$4S(LKEX&C`XnD%cj9*)k{`l z#>U3`mmNw<)!`nYn2OX?3tkt~tj92yM_Hn!G&o7HJn^WUMYuol$YcWXXskXa%CC`5 zFjY%5p)awVYE;87s%Hk}(J-XLxZK$C{9io>OB^M|hyi3B@02!lS! zS$2A~jGop_p)FJ!>IPEY14*~D3ZJmt%h#*~9d2NPtZ)495MSV z7~{i-w{?&$pOqb*q>fQHNn-%tmhDamM#ARXE}DJ}!rANZZm81BE!Mh+0T- z3pk*zY-taA7x@ON2Gj`5nGYVez02EOF|QqtaeijIX3antm6c|xC-~YNEaJIPOk4V& zXI~c$K;DLPoLRQJ7nO9>FtZ*usWvk;IN^Bc`V^Hl^`IeO25?}JmW1aMEbv}A#+)+o zI=~DC3$&Jf$>a6czFnf2wmCs^SW%BhvKMTlf|fQ|(b-9HQYrghTwo`V$C^PUcH5SP z#TGZi(Kk?o$D(VI2eYbT`Ynx#;al4{3-QAv0>?Y`g`%}&uq=j;i<$v@qBg~jcpH3EB-0&Lcx+xTO2eL2f|J*Fuf^&D(U;=5fb zw$`T)=OkUbpIDgF)tgrR7^i@}`VCJw44u@Oh&u zME$QZb;!jpH=6EGMwM0%WPs~jU*lo9r0Gf)KFfj^3S1af=ePvOQJ7F@;<4B6y53A8 zwI|&+>E(PVQWbP~2|}Tcf}aMnFfgiPcGTps_+=*r<#%0AH_-2I(`qP$tX8mXXCv{f zu#a%S_p|jmoWil$8H}ZYJq;$td(c=F8?mP;up2i6cRNfBFw0ncBr&sx;ytYQM=(49 zHjPKvwoI+;aU-eZlF0_)t-q#OjoqyH`>qzu2pkrzv&HAN1urfE&yslRZg)bD zyVCt{Ek0x2QB6-~C4_^k!~z>-->*GzpE|LDPj6}N_$kQtDBC~ay$FjAM7JnNSb`DNtt(NU$-i<=5#SM%Yysc z$sW^j+()U;w&K(kaD)?nnA5k81stu==BcKy%gIE!`e^@Pn|s%jd*s*)hD}zM(8?&y zv=Cil?uwS+8&2o`z$v37m)|k&HkAFbd`sD+K6f%O_Hm>8nR08(MsF)tVUk!&Z=T~Y zfYxqauDyJ|N%Pn47-75;TiG3>96Sf?x8k0ipRP94S9?pU&dITtk9Sva?3V?Zbn`r) zN}zpMk9}W@Qszux9x5oAWj>k`KyQKpdmgnqn4>y4N7LmblcJIZur=>b@Tvog&utx< zc&(Tv%_8(^mIv;o$$>zjJcf!|5 z&Y-zcDMb~X_AWYo4JyAg1bWGzd&|xD_{MOB|LWj+-vT$9N*Sd7jTXKJuDya_|NGJ$ zE|6G;+b{ad$x;XxxQ3CD@t4oD5H2RLK(FLZwfj#z3Fu~kYj034{za>S54zq!=rHA1 zO8isJ7hc47;M#XD?7uIWA_9%{)^7SQed1?C;2NCNDDQuG`sWBZ0L`1r7-sn!rUe78 zy@qlA7q$gHRB!_T8Rn$&UlP&?E-v627xzD~=1VELm;h{4-<##&Kh5at_fWvKwJ<^q&N)Ze|t?g`Bmqh7leLNCbgK$ z2SBk_OEqV%AjJvvS(X+8MK--byh&C?i8=_R19^##hW0^PCI1ObMF`WcSLvTF_2d`8 zU86QF5S>i4qguv~|KU3&!(q`L`BZFm<{FkzRl93)N7N6JJ0s`vB1 zai~oA%F5Wc05zv9n{upHQeu!a2X|=oDuLD}jOyD@8uo3qZ&NCfx7mNU7GK8nA(W50 zC(T*#nhS;P{!*dKbmI$1^1h9Q#j4*{d}=_gY&{DT+5fft*yBVt}Cd<3##P47%;%m2>i?2*kpS>NLrj<#Bl#(WG3|d{%S9Aib*yix1Ce# zjG>^oIGRJht_7G(_1uyuLjL2K05U`=0JWYNDsz*T&b-icEibBx_hNv1Y9*E!n|hh7 zw$rkWlxY7Yl4Kkqwk?BXbBAfNTk%Dy=co(e02tPL1x#fTN(O!=&$H{_N_aByzUsJ& z4#oAw98LF<19z!jFG${oqJA}$uw}-RPX0ZPhJ1AQ->4G8O@|UYb9mp6+C0^0kcjaL z54M=8v%Jj(I!u9e-ZJIjJn(e=K%^5@PF|i{@vSc*BBqT7XNng?y1DI@??2Ir>j0!g z?!aQb7#u8QYC`_K+zMQliP*lz8eaaF3jwql4A2uPt-^C$|Fpd40}&Uu2zSzo!xxv| ztgx4Oi8u!)9a15iCnCKUWc*K&&yrt3kU|)_udE$n{X>NSEO0Y$fiSvFj)D7kxc6EB za|a6O*3G~2g`V{1@2li@uNW_e9Sa$zi2uKk{~u{dBTOWahhz$Vpil4n$GgpItiJz( zsfra05d;D8XH2-^aB2ljuK;0eBJPT^!|%2{Cn`~H|?NPP8c`<4ime>OT$Dgg89$(lZUqo3!1?{hYoz&lX+Yt0mK zbE6qA5&NzFm4%^y_9#l$l&QSs_S8z!+6&|OrhA_^O_e{Okb-RzPV;Br^q-MSWN#_u z@ALn&f72MO+F7YWaAttgYTe<7Iw;`<{z)9oE~KL7T>X;;L+z+9o#=nI;S~Kdu^jhR zgKrGX)ldp@{yHXBKyga>)0!<^D930?ipdIqPB@9=pCs(ct7TYTrTa%)EVXCI(f?AV!Jr(M1P+-V|7TlcpeG5S z=zl+77Tbg#I71h^yL2! z-T#q}?|(aV;mkA_DN=ItCkKp_djm(ir@e0c?jKwVG)9H8nC$6;YUDEWGqrs^x9K_d z;Yzq%m>QRc;gw34=yTVc9hbXTtMgKp4RvjO8${IT*SpAnl6aJYN;QE&oAGX#+Np^J z3Tti&TV*|v?{feljZ}?zTdt5r2BA>FI*$NTnJ~o0%FfWE z@-<-DxrT^7OLNckQNuCEMQgD}$DUZbGNG`V^#1a{rHf(;z|Ds^aiNJPBhFOD&)A)e z9HOFPqRgliNu`4w`&u@DIKQYce!Y(1Er6~PPu7{kx`(K@6D`wiAO2pI@O0ox5&FWK zvT=XTRLIjUkA!V)TIb_!1!vL@-8f!D#t+yCGZNev2Vqn%dij1KhgLGpU3KrMvdZCd4-GB=<0K&KyG=c@hRu9qB=K;a zb1aK`X$VXebbk52e$J zsp`caZgOH2@vr#noHV{{9Qha-YQwN-FhwSW*wtHVBu)^Wdckgis>OI|hc zxOi2-rJJqwJaUK$8Zw5XYi_~jFMbqv6zz+=_cw$TL^$#(>Jkh%uMv=kK$fD>UMU``|9!= zkY&g5jO8M5t;(EpaQ`C2k1|HJM0SL>2@MA`iY@HeoLQ8!v3v$O={&3=mIhd)tP%*} zz&Q#W&y-(n7%n^Jcm#rLpbQNRgdFKHW2jj~hknZ0LbI+tGIjw&SII zR;k72Z#=F*R(lQbf0jpNwk)g}OO%WWa7(@oi9^PDQQ%iw0{FXiG+niNwR*^acTV|J zV(4mAE*8Mu9|0Frao%sgp%Vr`x*#C~Fpke|mw?1661!iUpLQ=DkJwpYj?meMFGG>l zQkMRQSC!bQ07ffFSf$7Y6R~{!*M~)l#n}t{i@UKaT9J`9#sc_H{l4tki$_dJRFx{> zzM3u4d23!hv{SjaYpU9rP10v%Ql*V6g(*8Jqj{RLSv^a>9=Mc8vD{HcryuC&odtEh zWt8lHc^U*IFaoDV=yEm*`fkXbrJi3IPUS*G>ZB_gF$B_$CIM+Xrq7)ylf|$&U^~W> zgi71VZXNE|Y42Vy1_YCh9I&$a{TowmQ-Mxrq|NUcCSEnl#0h6;vBLI_*DD`hjma*s zqegi9?#dxj;i>uYvGb?3PsP`$sXyKqzyoxIO*J!*Oe)nZOOB((F1qGEN5@&(U$8B9 zvmkB*+SXcsL`T%8;;RpO1q^0x-Q*MzdJ?>mTSfrm5y z6e{EXkf)53nexr45PGNKf^|*XxEQnjqm_@}?R-?5;PUFBAOh0*y|8sJ_iK1ZWLGFO z1jpkS%lfT5JfHoYd>-V@cr-D>y-vc6dKvYVQiq(BRW=h z@`RqFkqZ_B&oNCELcbh4MLiL+&)R8R4(+sm*(N{uwVZ>0f24*3ZV~;;j^A+yvwS4B zxLiB6i0Se`jwS?s{7G*$&^&!1cChF>RhRdowiIyZdO6*qoP4N3DRAtU?3&amW?E(% zmRg$iGjw5=AKpDcf11GX>G5UnGyMU2q2ZqHu7b)gh;|K3FCKHSb3NEtlz#0l)1>n& z(e-KNW=-q(I^A)PW1an`|9UM?(GgruY5U9D^!HZvE*EDy!m83UM=BrK-QIC2-N{}{ z_*Q95bn8~|_bEC{mL!KM)W%Rn>eKRxoD^GY*LauxCF!iCoX|OTjss(*wrm1_-m@s{ zNAJW8_LeLMXwU)gZ)`S%rqzDst8_8BXko`!+wJWZ+kN9S1F@XFgT~O-S~fI4u9SSY zWq>^V5S1aJ^CVymbdX1aCUP6N*?X)4lO-`Y!jZlHPkgDUxZ*`$p3nE6sM;j2NWi}d4$&5P+|;W}D#=Pl{7H{8v= zCju{I?ECzeK6>69bXVUKJ)i4Az8l}wM%9p;BwSUy0|IT3f_ApB_rK^pB9bHazW?Q)JCo*#mw$Sp>rbix*UeC%70}UexA_eJI%(u_G zRpcm@i<`pI>gVZw&!^B2m*08u7+kPRB?>ScA=^pD z)BS-hBFbrq%m*eg<*9qi9u@h~LZvGVl|b$lXXMprWJRg5Twc_w$#W-91{<|KCq*}m zChDM;!C0bPqvkofNfjRA_2;PCSDa|g6E%Cn!Gz^=}NX(VWz3PJ(p)h&>6#} z8OC?zH8iCC=6Gl2>(Xfi9s%BscL^kDRsxRW&$lnaizoe`MOaE`k&u51lyWbRqu#Jn z=!f))1n!kf?ptcL$dSp>m{6prJh~7z>I(feKKw0Gx5H)2bNBbzx^Y%dOWx-^81U?GVe~u!y)zSe0?Jyj<53G>s*{N>86we3^cDuxZVo^SCC|^4*YI<$$Wf zSTu!^%i`IH{~KNzBJs8&Q{60?|Lq_lq3yJZr={TxN}yS+|(wtp_HY9o+`CBp>65c%bMwTbhN_k}HB!aUu&D!g0 ze8Jn>N#$*osXaoe%wbDmNls)*M!u)y7c3Y2d%j;wPZ7bA=X*WtUhQ1igKq%n&+05y zdJ$j)Vw>HMFsVFn4=ZZMSpLsdW3Pb9R@rWaG(g*35gx`(Z$WFv8M91f=LcD)@$dGe zt%Ir)+O-*0LF2tVhk@{tux&H#294pes?JZ~j+2Oh#@*G^$6xbmztI@>9tXE+3x%G1 zrJXvTZUOsl)JAvzB_mz*bvsgm@LKAyDM2O&jOY05rq9=-+Buh?&k!`v+0Ls?%)%3@ z>wNV`MR_>cGF@N%QrKb9aCaUtpF0l&Hfu)$5)?j5^1!RXhImHr)HG%?L|i`yB=;@V z_w^6+O1#Cov9-YdBGB2oMuz54(7(IK;RPCAmND)88WBzc**v5IvaX zADnSKgu$XVLOrlqG2`ZS=UGgHpoiWuey-Q<(EP*YZ{wZxQ<4pW)!X7ej?LVOeJHBG1t&) z{OZ$NJ8R#$-$SzE-5aBC^b@$owmG?HhZwX zN~YdoUNG{N*(z9fqSbN4Y6eX_V^NSd&hE50j9;6Jr^_ka`bdI?^Qo~(^Vl%;hOpA} z3~AW}4pUW&$*C%&4c5q~4Vrwz{%?Cr<^*e4Wf_puu2FSPbTS|>Rr87n#t6aOKuj`=lcb$J;S@$m-+4)IuDJ`!q|mbG$8108eL99TYeF zaPgJTYWLC!m9mk%uk-)jx(a4j)`-r zV~~X>sVs@kvpE{BJ|%8ws4HP1=auViH}SI1&Z!(ovObTD;b6#@$%QUyu}^cNcbqDQ z&(Z^>6WR9iHbRe+lpW`Qr%*1dtE~{Gbu1!WiJb04wPq9aly1!a5+VjlE|O_+`;Hjn zvZMyM&IdlXTJ%NV*;!<*+nVY8V&DLX%K;H;dsF)N%^levE!SRHxg^{AI1t$HM(GKr(*Ef4_7J`2^)Yjj_P313+ z1bb4?rznGm$I(5Nmo_cv#TD1itz&{!#GI%#%tDN*m4BTmeTzxnCiTglL$X#x=b7mP zJLPpwWblvbY`#-zh#;isw4z&Po!>`yC~; zWKTfQS*K*rxyN48_`8zAA877Jn48hj?b*y5<e*Y*i(IMcEH501snE|-!^ z8TD$sB)hjk&*$UU?cC?gcbJDKABc9at)D*W^D~%4`Gm(*VYF`qA4xA-p zdGIhz1Jvc_)hLNxVOM?$00MJ1g80>!N?*hFp4O|${C+i=fYZe38sK`e0p4}US`%Hi zL&>TFH&(VGZ{q*w{<$$L-76{ZUK8vW2a}6Ak~|bNxwM9)$Yu-EdsY>p0sB~!gpWsq z{fGYFZaZ70ON&EmVPUY3cU@9vJKif_68Be+By~DE7*!ZzP?S~OnCq8;%lB(6LT786 zzc|T;%!$L~RIF=KKKQC+_7TDK$5iHK5o>b=VNW0JcL|R?5dLjLh5CVj^QVaTVC}h* z-ZW$NT|xUs_q|b7ky5B7XpLSg{jR0fu?|=Qq9V7tuxZXVu8!>*ENdedHEJ;0ee!D@ zrF__!6;++m_uKy3#T;Y^K^uwT|9EV9L9IwK*vp80u1rIY4*0!BS+rq^36TRmCZ_b7 zqV&-$ko2A#Jp8@$g6aDEN1;fzb!!mYYRm$67Gsb%w*9%|)+T~95ykSPL1mn_9R5^1 z^l!WJGX<*{@Nm8?275GgX3wk=)t}KU%k6!N>*Fx%z^)WopZF~eCyc%k;6G3+C1FIL z4Re87*LaT$gORIyg2&o$vdceKqafg(i%IfT()rA=o}M(JWDJxSai$OX5o|Xm)v3ab zKb(>RKRzs@Tke|ZpBOvDd8?>98RD)oGH;?jxQ#d3R~B>6uB5b-uA*(Ma=X$Q=H{l; zu-J0*_lyg^kySvFrHmky996yta^UIe+l1sxt#s4qR=f14J@z^56j{oxxb;OJEG{3H z!UH!Lq54Qc;@Ax8rGEDypoEEhoc*}~E-k%ZX+@*QcZ>0Wqm1)tMqm@b|{xfGK~ zQ-0Dv+~D;PuDrLdS|xC0yr>6NGQi9u^9>ru`4Q1|w)E|H^YioLc6T3B{yM$>c*E${ z+K)zy6#1MndeuIi+fyA;7i8c%ZrG=CNGQz2B-vwK zKc)7@B;S?EEhv1W75a>T=LsyR0w`eMGFGjCHoa-r4|(g9@oF>GcvAsEIwO|t z`(QLbAmq4HR4zg{cOWgNvG1_sC--B{M=2r?-<(N#RZ5;L63ol9h+zF<8oY^bg*EcQ zd6QYq%has?$yRrW`qmFxtIM1xu*^D8F?4IBsDTZvI+U-($i79~q5ho=G5k}*HWFV~ zf~}>hBFRSTZDIUsHWY{4nJt8_bw8)MIqqTZITK*x>DuhxMK6=#e}h2>@LEWwbE?%7 z*nrBG2j&{Wmc9y*>~G9mIX+J+rmjj+7zcx>$k2{q7^{@~;&Kt*mct#UFpMR0NS;Jr zk>xw7i5$y&rC{BCEO*t_fefDb`1t9&fU?t%SsM;V6la@@I#f%225nv?j1`QPEru#4 zH(kS|@cC>To4D}T(F!)HQEamj)1jI-$`{26;7LxqiM0VlDN&@X%`k2 zq5+Hcg$qqI6RHdZxD!EvckkXEuDGuZ9(vk1_&Y5)r#yBk6ay#fL|+qf5PwicGD`aL zMd;(v3retVTtSuc9t@SO<#D+%{`2Z%93+!lR~rE$iyj*2>t_10V@gb5sbO#G{`4`) zLNU;&S|q$Ee^||lUdSg$;jrrqSUVqnWY)Q(5hN;~R1-q)w;%q8yabl%1Ik8{Ax98x z@2roR!MX#7YhZ2g@QS(U${)&wr}Tp!atOg(?xzu{3W)5&!oKaPNoO+nXyQ9Ud|eK0 z*ON7Yo_IIzErk>wiu7N<-9VSWgUlFEWN7crYMqc6Yj0=bkOU8|T*LbejkU(oqENLq zq`uzmEGialz~R4kXl430GF+~m1AJR{SV`zdosfcu`@QNY`D}6QQF2^4Fjjfg;PBQ9wlMRducPN)RfVKEd7dSRQS+KDU8eJ)(t+hUjT z@VG92U7c@NDlFS*S$CWQus-Hdiu7$RL`fbS4jYNFHGDuGFCIkdNGj5 z80gp4Yc~-{0TG$(FlEY>9~p1Mi8fR#{I<`9cETy>3m&Ey*{ZwQC$XZVza8~?kyTzU zrCH>T-yfxOxv`8;@@Db`g-}HXiP{mGuNXLq^7rQER_SqhxIxLGW-30;b>wJma6PuZ zYYx0_0uQWfh9&;TqXuH{AV*0vbb{bk!FgkG^l}Kz*D0fV7#ssOPyvHydqJN5bEFQ| zjl9|0G8Ye}5C4%pJOjzLfQO~+yPD)U^7CXNa47;Od*rAELNs974uG?j$utNsfL%1Ij0V#sqVHRgJ32NJUBg;{kO13@j=A z>l;z8s;P$H3RxUk^f}1U^=>p&Q9Kr`a44)>8@Q`hPCf+fr^sx2GM1u4f#Y=A#5Z-7 zsQPNv94bJWU_-7iRNS?HIpH`GeZkX>1-q-dF5rR+9CoVl>0vq{kX&{{ArX0XOw(?< z@cma7IMU+!d_VpXr#u7gCS1t!?On>dD9oK6asW6)^WOt~xl;!r>FnHuq2IuM&RzN+)(Ld`RyoFy>xinY*zjkY z)i}<~dP$gIrA5i`^{M-8u)T|w`?vlb#cLolx%DX#sb6?{d1En#nZC#o+lY^M!#1S2 z3K)bfP`<-sU|lj$OoY3H6GS=f5uI*Z&>vfL8Y@T^mExMA52K25#AHFT2VWWn7d{gN zlU-yoj)h64Fe#xJ7;PHsvYRabdM__kX8F8;QW~r)oB4;D>QFB84OFq#^ReTwZXv_a zH&vs|>AJTs)Zj3Gd!k|k`>uKW;FjQS!jA>v@`9;#K&w%x}i+{ z>U5xGb>XYvyZY|O^5ixn6a^}B>yhfFnL_b!EQDH1-F?>hDfg92r5@*aLzoBqR?@@G zDY}363KUBrGy8FtdMcl(I2nan^tO44puUDvNIsRIKXKuTCM1h+fX=|2${1!Yx6az{ zi_~9K*I0QG2!RmT%_CKTMB}kKJ$CP{{=s744~YE`$l!9Nd30cJ)@^^E_`A{*ox4NJXXB^n^Q(c6W+Qb z6iGvbyD{Y1qo)~Z_X|UHWgcwL;^>+fXmGGu{V9leLtH*SH2nJJaEYk{BP-vH?`tXp zbZ@i@=Z>N>wKEWM2bf&AR?JL<&PP)@#9lCku#Z>?)IiJ`nQf{tHpXnblJ+>=6g)PI zQOlETxUqS4r?|Wx0Ky3^?7bDEZ;qn-_sh2Jbd5nO_z)-W{8IIk#xGF$ku}GLPn%(g zqzpdMU?9>W_c)AGXUM4y>5U#$N|IbLc4DsY7Xs8etOhs!6x|4Gv_$B5WT*0pCZynO zA}05RGS?L>B|2_RIFx7N`;u!RDoH3>hhxj$Ozxl2D&y&#)mp!?61tnDPUXM=k_JuLN7tnZsQ@|mrM>t~&DNfLdHGS&{bs$Ee0NsyLoMHYL8ALYei7-cnxCd*l zC=Ssdi@8ed86x3C{fD(%+oiJ(WQKcy9cfBz4eg9Z!w;pl`SqfAt9RoMGIV` zuaWb53Y$toASsZ8LYflK(S1dsydi&f+CH&YzOc}{p7}9Z%#*RG09+Z_NJZ(Yg2tiO zL23J(sa>|M#g&+#lx_+%^Yp{#_P5T2Z!K&fHeRxp=wi$x#b0VGivA zS>ANf4TDVl_o8}1N1yT4R*s$q$o#U3eXr8*sul~jV*byR1_^7);uw+oVtLw{Lzi5h z1yfCBr3H8iZ*l6Ep=lgzTZdD^k|M193oZRulaXh!xEzvyv8b)sc zoc&7rFD~TJ!maDNWVFVxnBJamLR~%g<*Vr}mh=0_Z_1JXjM8%6Z5xd?CfzjHYG=H~ zuKZ41<4d?!b9g{`UcULz>arsHQY}u>?vVAW87as~-S>MlZs*&owOHk{n`t?LI*Bi% zI(`79I({>V%tn&@vfEHOvoWGX26Z*XH~7PG=aGc&dPcI}!R&;U zg}5V!%q&{Aq0xh?sIHo)5bFBgYgGJ95>{e9Uin2t=p=w^AgbC)5D4ZH)zMiE*LB4~ zo`LndjvMjrr5IICV9As`>F5h1(axg7&A8rE)*tMLzaFW|LCdAi6cX85vqnUr5y`vp z-Xr(!d?2;i_iqVCJg>3-g}cFf*zBPDyYjj|(>(%R?MwxEZnKry(_Lc<55(h&R^ObA zB8syH)g0QHhvoQv>IWhDrIs@{VjO5%cj&C)%{z`s6l2*_vx%s{T34bW598uTEw7%%3c{A|BAiE!(l0t_Wt2(IXau5Xa91AY*BX~6) z-c8CI)}J~48bEKMtJReJG2o8HG9_GO~Ln&523_$VYuSJ~}CGP2P%y<=WLl76Nk2RNv!6I_{ba z651?qKj2qh^mp?VG*f*SMVM#Dd5M#P=`Fn`Rdyd48SPp>eyRxBU!PKVC21SD*1WV( zv2%kd=uic!El24olP=qvPb8zm9z{~ZsJZ8u;vr9#t>KxPr>K8D#l7sQmOk##E9Lgw z2-DOK8h>JZ|J87v5qz?ZL4qs5+Ex$`+R*F)3?jdqL^31_~PC)npd%W;-@XPAFUTwY{7#616otf zr>a-ie%S}4-diO{OP+fZC<&{KIlIA@11i;4QGnmulQ3+QR9N? z1UYPtZZZqiBYu^35*)SXSSBI`0=DwmK6R3T?zP3xn(QD&J%wZNZ*T{Pmk$N7NA2yd zJEO)s7H=;Zd4BH*{v~WK8uweJBaGjhCZx6<*kuf3(TLcR9iWw3id&3E0Xc{|Is^bN zoau=NlIK_4F^vBBmZ0^erY;}Fkg&FbA%~AsUvi?h^T?7MDp8!2FM_{XvKjkl3GOIZ zyF7QNNZ_RJ7LsR*oyB|*T0LNENKoKQoarMOZ4{%j5cU^JcsfFn>zX1{o4HK4Dl;J% zKR9nfQieuD?l^$9S~;Dog^b(`O8V7ki=|SfQ9G^(C;55b;@kX-^^WTlbpiaLmuISM zD)W!&)bC)<+(!~F4R1Hg=L}uzWn3ijtL?C(hG>I?`Fy(&8PMLKFHY<{Es-JxF<7nL zUWWJY?wy|WF%t|=+)}13+A(V;-!h^Nc2=|)gQHovpI@6{61nNKL7*FVlOB)Q@!Uyj zzJP`5*CW?p{98ndBR_415vn}tY<>93lom2)C+al)J4oB0s*ucW?R%)~H=Vg7yF||T zx67i65({v!;Z>XDjh4GYUpr1)q9d;GsoEC}7RxMH+J*IKE2nd0^f*WBz*?Kce zt79;YXAx0A^yI>=4*_5ea{q8OIy62W4t)?y3eSt*u`Z9}T7tu4mnJ@6@COE_G|Ql~ zvvp0U3-k(#t6O(h9*XVN7MqM#-+OiVtdAk6My-W3jBUDX`cq^iA|Z6Q-HC>$k*%G4 z$&vElL`OJ1ujT!caKXBetEO)L^!u*7>04O&3I`N71Dwx(*m|I3)n2NF;gzwL-I#H> zPd^ss>#HacZ!$&+$MHMBQ%F}k=%!Jb3?n-v+=!s2~G%@QDHtyd0^*U}V$-*8+kM2SiG7ZkiEa%E|#18$d-x(rq}{5)!!NV5$d5<$(e&FE)SyeNPBZK^uU)x z^7&HNcb0JvIa<;OXLvp8FGEMNU|iFX632{$wGN*k3#nXbykRtz5PqZX)96HElRtkU?G;aPn+kC>P`q6^2Vah(T-?&?5!O=`B%p{m4)#89Uvy6S~opNjMSv^_DcP zv7XoL1Lr9>zkU%{5^Z~iATkjD7_AClIP#^cTSx@tUcjBh(e5nUdGr{micmURXM`-- zx(Q!;7j*t3{a@<`)amNZtv16`OU&c;JM3fCctYH;rNoEG!R?Fd+b9NYZ#Lh^Yrv0+ MqUOC)c`M}q0?L$ym;e9( diff --git a/docs/releasing.md b/docs/releasing.md index fbac456902..5b0fc7780a 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -1,41 +1,58 @@ # Releasing -1. Tag a commit to release from using semantic versioning (e.g. v1.0.0-rc1) +1. Ensure that the `release branch` already exist. -1. Visit the [Release GitHub Action](https://github.com/argoproj/argo-rollouts/actions/workflows/release.yaml) - and enter the tag. +1. Checkout the release branch. Example: `git fetch upstream && git + checkout release-1.5` -1. To automatically update the stable tag, select `Update stable tag`. (false by default) +1. Run the script found at `hack/trigger-release.sh` as follows: -[![GitHub Release Action](release-action.png)](release-action.png) +```shell +./hack/trigger-release.sh +``` + +Example: +```shell +./hack/trigger-release.sh v1.6.0-rc1 upstream +``` + +!!! tip +The tag must be in one of the following formats to trigger the GH workflow:
+* GA: `v..`
+* Pre-release: `v..-rc` + +Once the script is executed successfully, a GitHub workflow will start +execution. You can follow its progress under the [Actions](https://github.com/argoproj/argo-rollouts/actions/workflows/release.yaml) tab, the name of the action is `Release`. 1. When the action completes, visit the generated draft [Github releases](https://github.com/argoproj/argo-rollouts/releases) and enter the details about the release: - * Getting started (copy from previous release and new version) - * Changelog + * Getting started (copy from previous release and new version) + * Changelog + +### Update Brew formula 1. Update Brew formula: - * Fork the repo https://github.com/argoproj/homebrew-tap - * Run the following commands to update the brew formula: + * Fork the repo https://github.com/argoproj/homebrew-tap + * Run the following commands to update the brew formula: ```bash cd homebrew-tap ./update.sh kubectl-argo-rollouts $VERSION ``` - * If there is a new minor version we want to update the versioned formula as well: - * Run the following commands to update the versioned brew formula: - ```bash - ./update.sh kubectl-argo-rollouts $VERSION @ - ``` - * Example: If the new version is `v1.3.2`, we want to update the formula for `v1.3` as well. + * If there is a new minor version we want to update the versioned formula as well: + * Run the following commands to update the versioned brew formula: ```bash - ./update.sh kubectl-argo-rollouts v1.3.2 @1.3 + ./update.sh kubectl-argo-rollouts $VERSION @ ``` - * Commit and push the changes to your fork - ```bash - git commit -am "Update kubectl-argo-rollouts to $VERSION" - ``` - * Create a PR with the modified files pointing to upstream/master - * Once the PR is approved by a maintainer, it can be merged. + * Example: If the new version is `v1.3.2`, we want to update the formula for `v1.3` as well. + ```bash + ./update.sh kubectl-argo-rollouts v1.3.2 @1.3 + ``` + * Commit and push the changes to your fork + ```bash + git commit -am "Update kubectl-argo-rollouts to $VERSION" + ``` + * Create a PR with the modified files pointing to upstream/master + * Once the PR is approved by a maintainer, it can be merged. ### Verify @@ -50,4 +67,4 @@ ```bash brew upgrade kubectl-argo-rollouts kubectl argo rollouts version - ``` + ``` \ No newline at end of file diff --git a/docs/security.md b/docs/security/security.md similarity index 100% rename from docs/security.md rename to docs/security/security.md diff --git a/docs/security/signed-release-assets.md b/docs/security/signed-release-assets.md new file mode 100644 index 0000000000..7f6bf3bbfd --- /dev/null +++ b/docs/security/signed-release-assets.md @@ -0,0 +1,116 @@ +# Verification of Argo Rollouts Artifacts + +## Prerequisites +- cosign `v2.0.0` or higher [installation instructions](https://docs.sigstore.dev/cosign/installation) +- slsa-verifier [installation instructions](https://github.com/slsa-framework/slsa-verifier#installation) + +*** +## Release Assets +| Asset | Description | +|-------------------------------------|--------------------------------------------------| +| argo-rollouts-checksums.txt | Checksums of binaries | +| argo-rollouts-cli.intoto.jsonl | Attestation of CLI binaries & manifiest | +| dashboard-install.yaml | Dashboard install | +| install.yaml | Standard installation method | +| kubectl-argo-rollouts-darwin-amd64 | CLI Binary | +| kubectl-argo-rollouts-darwin-arm64 | CLI Binary | +| kubectl-argo-rollouts-linux-amd64 | CLI Binary | +| kubectl-argo-rollouts-linux-arm64 | CLI Binary | +| kubectl-argo-rollouts-windows-amd64 | CLI Binary | +| namespace-install.yaml | Namespace installation | +| notifications-install.yaml | Notification installation | +| rollout_cr_schema.json | Schema | +| sbom.tar.gz | Sbom | +| sbom.tar.gz.pem | Certificate used to sign sbom | +| sbom.tar.gz.sig | Signature of sbom | + +*** +## Verification of container images + +Argo Rollouts container images are signed by [cosign](https://github.com/sigstore/cosign) using identity-based ("keyless") signing and transparency. Executing the following command can be used to verify the signature of a container image: + +```bash +cosign verify \ +--certificate-identity-regexp https://github.com/argoproj/argo-rollouts/.github/workflows/image-reuse.yaml@refs/tags/v \ +--certificate-oidc-issuer https://token.actions.githubusercontent.com \ +quay.io/argoproj/argo-rollouts:v1.5.0 | jq +``` +The command should output the following if the container image was correctly verified: +```bash +The following checks were performed on each of these signatures: + - The cosign claims were validated + - Existence of the claims in the transparency log was verified offline + - The code-signing certificate was verified using trusted certificate authority certificates +[ + { + "critical": { + "identity": { + "docker-reference": "quay.io/argoproj/argo-rollouts" + }, + "image": { + "docker-manifest-digest": "sha256:519522f8c66c7b4c468f360ebe6c8ba07b8d64f5f948e71ae52c01b9953e1eb9" + }, + "type": "cosign container image signature" + }, + "optional": { + "1.3.6.1.4.1.57264.1.1": "https://token.actions.githubusercontent.com", + "1.3.6.1.4.1.57264.1.2": "push", + "1.3.6.1.4.1.57264.1.3": "aa1afcb418fcebcc68b063377c48225f5a9d1511", + "1.3.6.1.4.1.57264.1.4": "Release", + "1.3.6.1.4.1.57264.1.5": "argoproj/argo-rollouts", + "1.3.6.1.4.1.57264.1.6": "refs/tags/v1.5.0", + ... +``` + +*** +## Verification of container image attestations + +A [SLSA](https://slsa.dev/) Level 3 provenance is generated using [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator). + +The following command will verify the signature of an attestation and how it was issued. It will contain the payloadType, payload, and signature. +```bash +cosign verify-attestation --type slsaprovenance \ +--certificate-identity-regexp https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v \ +--certificate-oidc-issuer https://token.actions.githubusercontent.com \ +quay.io/argoproj/argo-rollouts:v1.5.0 | jq +``` +The payload is a non-falsifiable provenance which is base64 encoded and can be viewed by using the command below: +```bash +cosign verify-attestation --type slsaprovenance \ +--certificate-identity-regexp https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v \ +--certificate-oidc-issuer https://token.actions.githubusercontent.com \ +quay.io/argoproj/argo-rollouts:v1.5.0 | jq -r .payload | base64 -d | jq +``` +!!! tip + `cosign` or `slsa-verifier` can both be used to verify image attestations. + Check the documentation of each binary for detailed instructions. + +*** +## Verification of CLI artifacts with attestations + +A single attestation (`argo-rollouts.intoto.jsonl`) from each release is provided. This can be used with [slsa-verifier](https://github.com/slsa-framework/slsa-verifier#verification-for-github-builders) to verify that a CLI binary or manifest was generated using Argo Rollouts workflows on GitHub and ensures it was cryptographically signed. +```bash +slsa-verifier verify-artifact kubectl-argo-rollouts-linux-amd64 --provenance-path kubectl-argo-rollouts.intoto.jsonl --source-uri github.com/argoproj/argo-rollouts +``` +## Verifying an artifact and output the provenance + +```bash +slsa-verifier verify-artifact kubectl-argo-rollouts-linux-amd64 --provenance-path kubectl-argo-rollouts.intoto.jsonl --source-uri github.com/argoproj/argo-rollouts --print-provenance | jq +``` +## Verification of Sbom + +```bash +cosign verify-blob --signature sbom.tar.gz.sig --certificate sbom.tar.gz.pem \ +--certificate-identity-regexp ^https://github.com/argoproj/argo-rollouts/.github/workflows/release.yaml@refs/tags/v \ +--certificate-oidc-issuer https://token.actions.githubusercontent.com \ + ~/Downloads/sbom.tar.gz | jq +``` + +*** +## Verification on Kubernetes + +### Policy controllers +!!! note + We encourage all users to verify signatures and provenances with your admission/policy controller of choice. Doing so will verify that an image was built by us before it's deployed on your Kubernetes cluster. + +Cosign signatures and SLSA provenances are compatible with several types of admission controllers. Please see the [cosign documentation](https://docs.sigstore.dev/cosign/overview/#kubernetes-integrations) and [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#verification) for supported controllers. diff --git a/hack/trigger-release.sh b/hack/trigger-release.sh new file mode 100755 index 0000000000..b7f843fad7 --- /dev/null +++ b/hack/trigger-release.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +# This script requires bash shell - sorry. + +NEW_TAG="${1}" +GIT_REMOTE="${2}" + +set -ue + +if test "${NEW_TAG}" = "" -o "${GIT_REMOTE}" = ""; then + echo "!! Usage: $0 " >&2 + exit 1 +fi + +# Target (version) tag must match version scheme vMAJOR.MINOR.PATCH with an +# optional pre-release tag. +if ! echo "${NEW_TAG}" | egrep -q '^v[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)*$'; then + echo "!! Malformed version tag: '${NEW_TAG}', must match 'vMAJOR.MINOR.PATCH(-rcX)'" >&2 + exit 1 +fi + +# Check whether we are in correct branch of local repository +RELEASE_BRANCH="${NEW_TAG%\.[0-9]*}" +RELEASE_BRANCH="release-${RELEASE_BRANCH#*v}" + +currentBranch=$(git branch --show-current) +if test "$currentBranch" != "${RELEASE_BRANCH}"; then + echo "!! Please checkout branch '${RELEASE_BRANCH}' (currently in branch: '${currentBranch}')" >&2 + exit 1 +fi + +echo ">> Working in release branch '${RELEASE_BRANCH}'" + +echo ">> Ensuring release branch is up to date." +# make sure release branch is up to date +git pull ${GIT_REMOTE} ${RELEASE_BRANCH} + +# Check for target (version) tag in local repo +if git tag -l | grep -q -E "^${NEW_TAG}$"; then + echo "!! Target version tag '${NEW_TAG}' already exists in local repository" >&2 + exit 1 +fi + +# Check for target (version) tag in remote repo +if git ls-remote ${GIT_REMOTE} refs/tags/${NEW_TAG} | grep -q -E "${NEW_TAG}$"; then + echo "!! Target version tag '${NEW_TAG}' already exists in remote '${GIT_REMOTE}'" >&2 + exit 1 +fi + +echo ">> Creating new release '${NEW_TAG}' by pushing '${NEW_TAG}' to '${GIT_REMOTE}'" + +# Create new tag in local repository +git tag ${NEW_TAG} + +# Push the new tag to remote repository +git push ${GIT_REMOTE} ${NEW_TAG} diff --git a/mkdocs.yml b/mkdocs.yml index c7cdabc426..d608710305 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -129,7 +129,9 @@ nav: - Best Practices: best-practices.md - Migrating: migrating.md - FAQ: FAQ.md -- Security: security.md +- Security: + - Security Policy: security/security.md + - Verify Release Artifacts: security/signed-release-assets.md - Roadmap/Release Schedule: roadmap.md - Contributing: - Contribution Guide: CONTRIBUTING.md From 365a51cdd1b05d1b3005b6d6d4df5cc108959847 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Wed, 19 Jul 2023 12:00:28 +0300 Subject: [PATCH 52/90] release 1.5 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 88c5fb891d..bc80560fad 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.0 +1.5.0 From 3c5b69ade644ae45bfab81ad916f107810465a29 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Wed, 19 Jul 2023 13:20:04 +0300 Subject: [PATCH 53/90] remove spdx --- .github/workflows/release.yaml | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b8cfe98c30..2d050379fd 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -134,37 +134,6 @@ jobs: make release-plugins make manifests IMAGE_TAG=${{ github.event.inputs.tag }} - - name: Generate SBOM (spdx) - id: spdx-builder - env: - # defines the spdx/spdx-sbom-generator version to use. - SPDX_GEN_VERSION: v0.0.13 - # defines the sigs.k8s.io/bom version to use. - SIGS_BOM_VERSION: v0.2.1 - # comma delimited list of project relative folders to inspect for package - # managers (gomod, yarn, npm). - PROJECT_FOLDERS: ".,./ui" - # full qualified name of the docker image to be inspected - DOCKER_IMAGE: quay.io/codefresh/argo-rollouts:${{ github.event.inputs.tag }} - - run: | - yarn install --cwd ./ui - go install github.com/spdx/spdx-sbom-generator/cmd/generator@$SPDX_GEN_VERSION - go install sigs.k8s.io/bom/cmd/bom@$SIGS_BOM_VERSION - - # Generate SPDX for project dependencies analyzing package managers - for folder in $(echo $PROJECT_FOLDERS | sed "s/,/ /g") - do - generator -p $folder -o /tmp - done - - # Generate SPDX for binaries analyzing the docker image - if [[ ! -z $DOCKER_IMAGE ]]; then - bom generate -o /tmp/bom-docker-image.spdx -i $DOCKER_IMAGE - fi - - cd /tmp && tar -zcf sbom.tar.gz *.spdx - - name: Draft release uses: softprops/action-gh-release@v1 with: From 744c0348f01a09e0dfb635f9846b93c19f6b767d Mon Sep 17 00:00:00 2001 From: Bart Smykla Date: Tue, 22 Aug 2023 08:03:25 +0200 Subject: [PATCH 54/90] fix(controller): typo fix ("Secrete" -> "Secret") in secret informer (#2965) fix: typo fix ("Secrete" -> "Secret") in secret informer Signed-off-by: Bart Smykla --- cmd/rollouts-controller/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index 2b603ec8b6..ad7190c585 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -165,7 +165,7 @@ func newCommand() *cobra.Command { resyncDuration, kubeinformers.WithNamespace(notificationConfigNamespace), kubeinformers.WithTweakListOptions(func(options *metav1.ListOptions) { - options.Kind = "Secrete" + options.Kind = "Secret" options.FieldSelector = fmt.Sprintf("metadata.name=%s", record.NotificationSecret) }), ) From 5804a34fa62a2b352e11663aa9c268fc90de8167 Mon Sep 17 00:00:00 2001 From: Andy Chen Date: Thu, 31 Aug 2023 14:16:35 -0700 Subject: [PATCH 55/90] fix(controller): rollback should skip all steps to active rs within RollbackWindow (#2953) * fix(canary): skip steps when in rollback window and rs is still active Resolve #2939 Signed-off-by: Andy Chen * test(canary): add case where rollback when in window and rs is still active Signed-off-by: Andy Chen * test(replicaset): add test case for IsActive function Signed-off-by: Andy Chen --------- Signed-off-by: Andy Chen Co-authored-by: Yohan Belval Co-authored-by: zachaller --- rollout/canary.go | 11 +++++-- rollout/canary_test.go | 49 +++++++++++++++++++++++++++++ utils/replicaset/replicaset.go | 9 ++++++ utils/replicaset/replicaset_test.go | 12 +++++++ utils/time/now.go | 5 +++ 5 files changed, 83 insertions(+), 3 deletions(-) diff --git a/rollout/canary.go b/rollout/canary.go index 7c31506a82..dff4b52d50 100644 --- a/rollout/canary.go +++ b/rollout/canary.go @@ -359,13 +359,18 @@ func (c *rolloutContext) syncRolloutStatusCanary() error { if replicasetutil.PodTemplateOrStepsChanged(c.rollout, c.newRS) { c.resetRolloutStatus(&newStatus) - if c.newRS != nil && c.rollout.Status.StableRS == replicasetutil.GetPodTemplateHash(c.newRS) { - if stepCount > 0 { + if c.newRS != nil && stepCount > 0 { + if c.rollout.Status.StableRS == replicasetutil.GetPodTemplateHash(c.newRS) { // If we get here, we detected that we've moved back to the stable ReplicaSet - c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: "SkipSteps"}, "Rollback to stable") + c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: "SkipSteps"}, "Rollback to stable ReplicaSets") + newStatus.CurrentStepIndex = &stepCount + } else if c.isRollbackWithinWindow() && replicasetutil.IsActive(c.newRS) { + // Else if we get here we detected that we are within the rollback window we can skip steps and move back to the active ReplicaSet + c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: "SkipSteps"}, "Rollback to active ReplicaSets within RollbackWindow") newStatus.CurrentStepIndex = &stepCount } } + newStatus = c.calculateRolloutConditions(newStatus) return c.persistRolloutStatus(&newStatus) } diff --git a/rollout/canary_test.go b/rollout/canary_test.go index 1811f6a4c4..9f66cf1078 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -846,6 +846,55 @@ func TestRollBackToStable(t *testing.T) { assert.Equal(t, calculatePatch(r2, expectedPatch), patch) } +func TestRollBackToActiveReplicaSetWithinWindow(t *testing.T) { + f := newFixture(t) + defer f.Close() + + steps := []v1alpha1.CanaryStep{{ + SetWeight: int32Ptr(10), + }} + + r1 := newCanaryRollout("foo", 1, nil, steps, int32Ptr(0), intstr.FromInt(1), intstr.FromInt(0)) + r2 := bumpVersion(r1) + + // For the fast rollback to work, we need to: + // 1. Have the previous revision be active (i.e. not scaled down) + // 2. Be in rollback window (within window revisions and previous creation timestamp) + rs1 := newReplicaSetWithStatus(r1, 1, 1) + rs2 := newReplicaSetWithStatus(r2, 1, 1) + r2.Spec.RollbackWindow = &v1alpha1.RollbackWindowSpec{Revisions: 1} + rs1.CreationTimestamp = timeutil.MetaTime(time.Now().Add(-1 * time.Hour)) + rs2.CreationTimestamp = timeutil.MetaNow() + + f.kubeobjects = append(f.kubeobjects, rs1, rs2) + f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) + f.serviceLister = append(f.serviceLister) + + // Switch back to version 1 + r2.Spec.Template = r1.Spec.Template + + rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + + // Since old replicaset is still active, expect twice the number of replicas + r2 = updateCanaryRolloutStatus(r2, rs2PodHash, 2, 2, 2, false) + + f.rolloutLister = append(f.rolloutLister, r2) + f.objects = append(f.objects, r2) + + f.expectUpdateReplicaSetAction(rs1) + f.expectUpdateReplicaSetAction(rs1) + rolloutPatchIndex := f.expectPatchRolloutAction(r2) + f.run(getKey(r2, t)) + + expectedStepIndex := len(steps) + patch := f.getPatchedRolloutWithoutConditions(rolloutPatchIndex) + + // Assert current pod hash is the old replicaset and steps were skipped + assert.Regexp(t, fmt.Sprintf(`"currentPodHash":"%s"`, rs1PodHash), patch) + assert.Regexp(t, fmt.Sprintf(`"currentStepIndex":%d`, expectedStepIndex), patch) +} + func TestGradualShiftToNewStable(t *testing.T) { f := newFixture(t) defer f.Close() diff --git a/utils/replicaset/replicaset.go b/utils/replicaset/replicaset.go index 8554cdf94b..9aec161b66 100644 --- a/utils/replicaset/replicaset.go +++ b/utils/replicaset/replicaset.go @@ -341,6 +341,15 @@ func FindActiveOrLatest(newRS *appsv1.ReplicaSet, oldRSs []*appsv1.ReplicaSet) * } } +// IsActive returns if replica set is active (has, or at least ought to have pods). +func IsActive(rs *appsv1.ReplicaSet) bool { + if rs == nil { + return false + } + + return len(controller.FilterActiveReplicaSets([]*appsv1.ReplicaSet{rs})) > 0 +} + // GetReplicaCountForReplicaSets returns the sum of Replicas of the given replica sets. func GetReplicaCountForReplicaSets(replicaSets []*appsv1.ReplicaSet) int32 { totalReplicas := int32(0) diff --git a/utils/replicaset/replicaset_test.go b/utils/replicaset/replicaset_test.go index 40c7d1ae2c..23bf320955 100644 --- a/utils/replicaset/replicaset_test.go +++ b/utils/replicaset/replicaset_test.go @@ -153,6 +153,18 @@ func TestFindOldReplicaSets(t *testing.T) { } } +func TestIsActive(t *testing.T) { + rs1 := generateRS(generateRollout("foo")) + *(rs1.Spec.Replicas) = 1 + + rs2 := generateRS(generateRollout("foo")) + *(rs2.Spec.Replicas) = 0 + + assert.False(t, IsActive(nil)) + assert.True(t, IsActive(&rs1)) + assert.False(t, IsActive(&rs2)) +} + func TestGetReplicaCountForReplicaSets(t *testing.T) { rs1 := generateRS(generateRollout("foo")) *(rs1.Spec.Replicas) = 1 diff --git a/utils/time/now.go b/utils/time/now.go index 4103857811..1b51cb3cc0 100644 --- a/utils/time/now.go +++ b/utils/time/now.go @@ -13,3 +13,8 @@ var Now = time.Now var MetaNow = func() metav1.Time { return metav1.Time{Time: Now()} } + +// MetaTime is a wrapper around metav1.Time and used to override behavior in tests. +var MetaTime = func(time time.Time) metav1.Time { + return metav1.Time{Time: time} +} From 7eae71ed89f1a3769864435bddebe3ca05384df3 Mon Sep 17 00:00:00 2001 From: pasha-codefresh Date: Tue, 5 Sep 2023 19:03:51 +0300 Subject: [PATCH 56/90] fix: analysis step should be ignored after promote (#3016) * fix: analysis step should be ignored after promote in case if result was inconclusive Signed-off-by: pashakostohrys * fix: analysis step should be ignored after promote in case if result was inconclusive Signed-off-by: pashakostohrys --------- Signed-off-by: pashakostohrys --- .../cmd/promote/promote.go | 18 ++++- .../cmd/promote/promote_test.go | 66 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/pkg/kubectl-argo-rollouts/cmd/promote/promote.go b/pkg/kubectl-argo-rollouts/cmd/promote/promote.go index d71d68573f..166f24c934 100644 --- a/pkg/kubectl-argo-rollouts/cmd/promote/promote.go +++ b/pkg/kubectl-argo-rollouts/cmd/promote/promote.go @@ -34,6 +34,7 @@ const ( setCurrentStepIndex = `{"status":{"currentStepIndex":%d}}` unpausePatch = `{"spec":{"paused":false}}` clearPauseConditionsPatch = `{"status":{"pauseConditions":null}}` + clearPauseConditionsAndControllerPausePatch = `{"status":{"pauseConditions":null, "controllerPause":false, "currentStepIndex":%d}}` unpauseAndClearPauseConditionsPatch = `{"spec":{"paused":false},"status":{"pauseConditions":null}}` promoteFullPatch = `{"status":{"promoteFull":true}}` clearPauseConditionsPatchWithStep = `{"status":{"pauseConditions":null, "currentStepIndex":%d}}` @@ -133,6 +134,10 @@ func PromoteRollout(rolloutIf clientset.RolloutInterface, name string, skipCurre return ro, nil } +func isInconclusive(rollout *v1alpha1.Rollout) bool { + return rollout.Spec.Strategy.Canary != nil && rollout.Status.Canary.CurrentStepAnalysisRunStatus != nil && rollout.Status.Canary.CurrentStepAnalysisRunStatus.Status == v1alpha1.AnalysisPhaseInconclusive +} + func getPatches(rollout *v1alpha1.Rollout, skipCurrentStep, skipAllStep, full bool) ([]byte, []byte, []byte) { var specPatch, statusPatch, unifiedPatch []byte switch { @@ -160,7 +165,18 @@ func getPatches(rollout *v1alpha1.Rollout, skipCurrentStep, skipAllStep, full bo if rollout.Spec.Paused { specPatch = []byte(unpausePatch) } - if len(rollout.Status.PauseConditions) > 0 { + // in case if canary rollout in inconclusive state, we want to unset controller pause , clean pause conditions and increment step index + // so that rollout can proceed to next step + // without such patch, rollout will be stuck in inconclusive state in case if next step is pause step + if isInconclusive(rollout) && len(rollout.Status.PauseConditions) > 0 && rollout.Status.ControllerPause { + _, index := replicasetutil.GetCurrentCanaryStep(rollout) + if index != nil { + if *index < int32(len(rollout.Spec.Strategy.Canary.Steps)) { + *index++ + } + statusPatch = []byte(fmt.Sprintf(clearPauseConditionsAndControllerPausePatch, *index)) + } + } else if len(rollout.Status.PauseConditions) > 0 { statusPatch = []byte(clearPauseConditionsPatch) } else if rollout.Spec.Strategy.Canary != nil { // we only want to clear pause conditions, or increment step index (never both) diff --git a/pkg/kubectl-argo-rollouts/cmd/promote/promote_test.go b/pkg/kubectl-argo-rollouts/cmd/promote/promote_test.go index 25c2b9929d..4a31c0a255 100644 --- a/pkg/kubectl-argo-rollouts/cmd/promote/promote_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/promote/promote_test.go @@ -490,3 +490,69 @@ func TestPromoteCmdAlreadyFullyPromoted(t *testing.T) { assert.Equal(t, stdout, "rollout 'guestbook' fully promoted\n") assert.Empty(t, stderr) } + +func TestPromoteInconclusiveStep(t *testing.T) { + ro := v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.RolloutSpec{ + Paused: true, + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + Steps: []v1alpha1.CanaryStep{ + { + SetWeight: pointer.Int32Ptr(1), + }, + { + SetWeight: pointer.Int32Ptr(2), + }, + }, + }, + }, + }, + Status: v1alpha1.RolloutStatus{ + PauseConditions: []v1alpha1.PauseCondition{{ + Reason: v1alpha1.PauseReasonCanaryPauseStep, + }}, + ControllerPause: true, + Canary: v1alpha1.CanaryStatus{ + CurrentStepAnalysisRunStatus: &v1alpha1.RolloutAnalysisRunStatus{ + Status: v1alpha1.AnalysisPhaseInconclusive, + }, + }, + }, + } + + tf, o := options.NewFakeArgoRolloutsOptions(&ro) + defer tf.Cleanup() + fakeClient := o.RolloutsClient.(*fakeroclient.Clientset) + fakeClient.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + if patchAction, ok := action.(kubetesting.PatchAction); ok { + patchRo := v1alpha1.Rollout{} + err := json.Unmarshal(patchAction.GetPatch(), &patchRo) + if err != nil { + panic(err) + } + ro.Status.CurrentStepIndex = patchRo.Status.CurrentStepIndex + ro.Status.ControllerPause = patchRo.Status.ControllerPause + ro.Status.PauseConditions = patchRo.Status.PauseConditions + } + return true, &ro, nil + }) + + cmd := NewCmdPromote(o) + cmd.PersistentPreRunE = o.PersistentPreRunE + cmd.SetArgs([]string{"guestbook"}) + + err := cmd.Execute() + assert.Nil(t, err) + assert.Equal(t, false, ro.Status.ControllerPause) + assert.Empty(t, ro.Status.PauseConditions) + + stdout := o.Out.(*bytes.Buffer).String() + stderr := o.ErrOut.(*bytes.Buffer).String() + assert.Equal(t, stdout, "rollout 'guestbook' promoted\n") + assert.Empty(t, stderr) +} From 9456150b7c68dda834066b40a3f5440cf2c8ab52 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 30 Aug 2023 09:24:31 -0600 Subject: [PATCH 57/90] chore: change file name for readthedocs compatibility (#2999) change file name for readthedoc compat Signed-off-by: zachaller --- .readthedocs.yml => .readthedocs.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .readthedocs.yml => .readthedocs.yaml (100%) diff --git a/.readthedocs.yml b/.readthedocs.yaml similarity index 100% rename from .readthedocs.yml rename to .readthedocs.yaml From 8d7d655e51f36ad7ea8de76b2cabe9964aa0f5e2 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 5 Oct 2023 10:30:50 -0600 Subject: [PATCH 58/90] fix: missing notification on error (#3076) * fix: missing notification on error Signed-off-by: zachaller * fix tests Signed-off-by: zachaller * aggregate errors Signed-off-by: zachaller * fix bad stat counts Signed-off-by: zachaller * return errors Signed-off-by: zachaller * fix tests on return of errors Signed-off-by: zachaller * change case on logs Signed-off-by: zachaller * missed a case Signed-off-by: zachaller --------- Signed-off-by: zachaller --- utils/record/record.go | 40 ++++++++++++++++++++++++------------- utils/record/record_test.go | 14 ++++++------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/utils/record/record.go b/utils/record/record.go index 87d83092f7..ef0cf23b17 100644 --- a/utils/record/record.go +++ b/utils/record/record.go @@ -218,9 +218,7 @@ func (e *EventRecorderAdapter) defaultEventf(object runtime.Object, warn bool, o err := e.sendNotifications(api, object, opts) if err != nil { logCtx.Errorf("Notifications failed to send for eventReason %s with error: %s", opts.EventReason, err) - e.NotificationFailedCounter.WithLabelValues(namespace, name, opts.EventType, opts.EventReason).Inc() } - e.NotificationSuccessCounter.WithLabelValues(namespace, name, opts.EventType, opts.EventReason).Inc() } } @@ -248,7 +246,7 @@ func NewAPIFactorySettings() api.Settings { } // Send notifications for triggered event if user is subscribed -func (e *EventRecorderAdapter) sendNotifications(notificationsAPI api.API, object runtime.Object, opts EventOptions) error { +func (e *EventRecorderAdapter) sendNotifications(notificationsAPI api.API, object runtime.Object, opts EventOptions) []error { logCtx := logutil.WithObject(object) _, namespace, name := logutil.KindNamespaceName(logCtx) startTime := timeutil.Now() @@ -259,7 +257,7 @@ func (e *EventRecorderAdapter) sendNotifications(notificationsAPI api.API, objec }() if notificationsAPI == nil { - return fmt.Errorf("notificationsAPI is nil") + return []error{fmt.Errorf("NotificationsAPI is nil")} } cfg := notificationsAPI.GetConfig() @@ -274,39 +272,53 @@ func (e *EventRecorderAdapter) sendNotifications(notificationsAPI api.API, objec objMap, err := toObjectMap(object) if err != nil { - return err + return []error{err} } emptyCondition := hash("") + // We should not return in these loops because we want other configured notifications to still send if they can. + errors := []error{} for _, destination := range destinations { res, err := notificationsAPI.RunTrigger(trigger, objMap) if err != nil { - log.Errorf("Failed to execute condition of trigger %s: %v", trigger, err) - return err + log.Errorf("Failed to run trigger, trigger: %s, destination: %s, namespace config: %s : %v", + trigger, destination, notificationsAPI.GetConfig().Namespace, err) + errors = append(errors, err) + continue } log.Infof("Trigger %s result: %v", trigger, res) for _, c := range res { - log.Infof("Res When Condition hash: %s, Templates: %s", c.Key, c.Templates) + log.Infof("Result when condition hash: %s, templates: %s", c.Key, c.Templates) s := strings.Split(c.Key, ".")[1] if s != emptyCondition && c.Triggered == true { err = notificationsAPI.Send(objMap, c.Templates, destination) if err != nil { - log.Errorf("notification error: %s", err.Error()) - return err + log.Errorf("Failed to execute the sending of notification on not empty condition, trigger: %s, destination: %s, namespace config: %s : %v", + trigger, destination, notificationsAPI.GetConfig().Namespace, err) + e.NotificationFailedCounter.WithLabelValues(namespace, name, opts.EventType, opts.EventReason).Inc() + errors = append(errors, err) + continue } + e.NotificationSuccessCounter.WithLabelValues(namespace, name, opts.EventType, opts.EventReason).Inc() } else if s == emptyCondition { err = notificationsAPI.Send(objMap, c.Templates, destination) if err != nil { - log.Errorf("notification error: %s", err.Error()) - return err + log.Errorf("Failed to execute the sending of notification on empty condition, trigger: %s, destination: %s, namespace config: %s : %v", + trigger, destination, notificationsAPI.GetConfig().Namespace, err) + e.NotificationFailedCounter.WithLabelValues(namespace, name, opts.EventType, opts.EventReason).Inc() + errors = append(errors, err) + continue } + e.NotificationSuccessCounter.WithLabelValues(namespace, name, opts.EventType, opts.EventReason).Inc() } } } - - return nil + if len(errors) == 0 { + return nil + } + return errors } // This function is copied over from notification engine to make sure we honour emptyCondition diff --git a/utils/record/record_test.go b/utils/record/record_test.go index d7e64af1fa..97650bae46 100644 --- a/utils/record/record_test.go +++ b/utils/record/record_test.go @@ -113,7 +113,7 @@ func TestSendNotifications(t *testing.T) { rec.EventRecorderAdapter.apiFactory = apiFactory //ch := make(chan prometheus.HistogramVec, 1) err := rec.sendNotifications(mockAPI, &r, EventOptions{EventReason: "FooReason"}) - assert.NoError(t, err) + assert.Nil(t, err) } func TestSendNotificationsWhenCondition(t *testing.T) { @@ -140,7 +140,7 @@ func TestSendNotificationsWhenCondition(t *testing.T) { rec.EventRecorderAdapter.apiFactory = apiFactory //ch := make(chan prometheus.HistogramVec, 1) err := rec.sendNotifications(mockAPI, &r, EventOptions{EventReason: "FooReason"}) - assert.NoError(t, err) + assert.Nil(t, err) } func TestSendNotificationsWhenConditionTime(t *testing.T) { @@ -340,7 +340,7 @@ func TestSendNotificationsFails(t *testing.T) { rec.EventRecorderAdapter.apiFactory = apiFactory err := rec.sendNotifications(mockAPI, &r, EventOptions{EventReason: "FooReason"}) - assert.Error(t, err) + assert.Len(t, err, 1) }) t.Run("GetAPIError", func(t *testing.T) { @@ -349,7 +349,7 @@ func TestSendNotificationsFails(t *testing.T) { rec.EventRecorderAdapter.apiFactory = apiFactory err := rec.sendNotifications(nil, &r, EventOptions{EventReason: "FooReason"}) - assert.Error(t, err) + assert.NotNil(t, err) }) } @@ -380,7 +380,7 @@ func TestSendNotificationsFailsWithRunTriggerError(t *testing.T) { rec.EventRecorderAdapter.apiFactory = apiFactory err := rec.sendNotifications(mockAPI, &r, EventOptions{EventReason: "FooReason"}) - assert.Error(t, err) + assert.Len(t, err, 1) }) t.Run("GetAPIError", func(t *testing.T) { @@ -389,7 +389,7 @@ func TestSendNotificationsFailsWithRunTriggerError(t *testing.T) { rec.EventRecorderAdapter.apiFactory = apiFactory err := rec.sendNotifications(nil, &r, EventOptions{EventReason: "FooReason"}) - assert.Error(t, err) + assert.NotNil(t, err) }) } @@ -419,7 +419,7 @@ func TestSendNotificationsNoTrigger(t *testing.T) { rec.EventRecorderAdapter.apiFactory = apiFactory err := rec.sendNotifications(mockAPI, &r, EventOptions{EventReason: "MissingReason"}) - assert.Error(t, err) + assert.Len(t, err, 1) } func TestNewAPIFactorySettings(t *testing.T) { From 725dd4d30ee0995c27b1919729d2ca605774b784 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 5 Oct 2023 08:14:05 -0600 Subject: [PATCH 59/90] fix: sync notification controller configmaps/secrets first (#3075) sync notification controller configmaps/secrets first before starting other informers Signed-off-by: zachaller --- controller/controller.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index 5429cfe743..afe4bc769b 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -463,6 +463,12 @@ func (c *Manager) startLeading(ctx context.Context, rolloutThreadiness, serviceT // Start the informer factories to begin populating the informer caches log.Info("Starting Controllers") + c.notificationConfigMapInformerFactory.Start(ctx.Done()) + c.notificationSecretInformerFactory.Start(ctx.Done()) + if ok := cache.WaitForCacheSync(ctx.Done(), c.configMapSynced, c.secretSynced); !ok { + log.Fatalf("failed to wait for configmap/secret caches to sync, exiting") + } + // notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(stopCh) // Start method is non-blocking and runs all registered informers in a dedicated goroutine. c.dynamicInformerFactory.Start(ctx.Done()) @@ -471,9 +477,6 @@ func (c *Manager) startLeading(ctx context.Context, rolloutThreadiness, serviceT } c.kubeInformerFactory.Start(ctx.Done()) - c.notificationConfigMapInformerFactory.Start(ctx.Done()) - c.notificationSecretInformerFactory.Start(ctx.Done()) - c.jobInformerFactory.Start(ctx.Done()) // Check if Istio installed on cluster before starting dynamicInformerFactory From 0d9983ef82718f2c8c20ab2b6c4423afe3b14410 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 11 Oct 2023 14:38:45 -0600 Subject: [PATCH 60/90] fix: bump notification-engine to fix double send on self server notifications (#3095) * bump notification-engine to fix double send on self server notifications Signed-off-by: zachaller * codegen Signed-off-by: zachaller --------- Signed-off-by: zachaller --- .../generated/notification-services/awssqs.md | 106 ++++++++++++++++ .../generated/notification-services/github.md | 11 +- .../notification-services/googlechat.md | 19 +-- .../notification-services/grafana.md | 6 + .../notification-services/overview.md | 1 + docs/generated/notification-services/slack.md | 82 ++++++------ go.mod | 56 ++++---- go.sum | 120 ++++++++++++------ mkdocs.yml | 1 + 9 files changed, 291 insertions(+), 111 deletions(-) create mode 100755 docs/generated/notification-services/awssqs.md diff --git a/docs/generated/notification-services/awssqs.md b/docs/generated/notification-services/awssqs.md new file mode 100755 index 0000000000..6bbc47cbbc --- /dev/null +++ b/docs/generated/notification-services/awssqs.md @@ -0,0 +1,106 @@ +# AWS SQS + +## Parameters + +This notification service is capable of sending simple messages to AWS SQS queue. + +* `queue` - name of the queue you are intending to send messages to. Can be overwriten with target destination annotation. +* `region` - region of the sqs queue can be provided via env variable AWS_DEFAULT_REGION +* `key` - optional, aws access key must be either referenced from a secret via variable or via env variable AWS_ACCESS_KEY_ID +* `secret` - optional, aws access secret must be either referenced from a secret via variableor via env variable AWS_SECRET_ACCESS_KEY +* `account` optional, external accountId of the queue +* `endpointUrl` optional, useful for development with localstack + +## Example + +### Using Secret for credential retrieval: + +Resource Annotation: +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + annotations: + notifications.argoproj.io/subscribe.on-deployment-ready.awssqs: "overwrite-myqueue" +``` + +* ConfigMap +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: +data: + service.awssqs: | + region: "us-east-2" + queue: "myqueue" + account: "1234567" + key: "$awsaccess_key" + secret: "$awsaccess_secret" + + template.deployment-ready: | + message: | + Deployment {{.obj.metadata.name}} is ready! + + trigger.on-deployment-ready: | + - when: any(obj.status.conditions, {.type == 'Available' && .status == 'True'}) + send: [deployment-ready] + - oncePer: obj.metadata.annotations["generation"] + +``` + Secret +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: +stringData: + awsaccess_key: test + awsaccess_secret: test +``` + + +### Minimal configuration using AWS Env variables + +Ensure following list of enviromental variable is injected via OIDC, or other method. And assuming SQS is local to the account. +You may skip usage of secret for sensitive data and omit other parameters. (Setting parameters via ConfigMap takes precedent.) + +Variables: + +```bash +export AWS_ACCESS_KEY_ID="test" +export AWS_SECRET_ACCESS_KEY="test" +export AWS_DEFAULT_REGION="us-east-1" +``` + +Resource Annotation: +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + annotations: + notifications.argoproj.io/subscribe.on-deployment-ready.awssqs: "" +``` + +* ConfigMap +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: +data: + service.awssqs: | + queue: "myqueue" + + template.deployment-ready: | + message: | + Deployment {{.obj.metadata.name}} is ready! + + trigger.on-deployment-ready: | + - when: any(obj.status.conditions, {.type == 'Available' && .status == 'True'}) + send: [deployment-ready] + - oncePer: obj.metadata.annotations["generation"] + +``` diff --git a/docs/generated/notification-services/github.md b/docs/generated/notification-services/github.md index c24ea00f43..913efef6ec 100755 --- a/docs/generated/notification-services/github.md +++ b/docs/generated/notification-services/github.md @@ -12,7 +12,7 @@ The GitHub notification service changes commit status using [GitHub Apps](https: ## Configuration 1. Create a GitHub Apps using https://github.com/settings/apps/new -2. Change repository permissions to enable write commit statuses and/or deployments +2. Change repository permissions to enable write commit statuses and/or deployments and/or pull requests comments ![2](https://user-images.githubusercontent.com/18019529/108397381-3ca57980-725b-11eb-8d17-5b8992dc009e.png) 3. Generate a private key, and download it automatically ![3](https://user-images.githubusercontent.com/18019529/108397926-d4a36300-725b-11eb-83fe-74795c8c3e03.png) @@ -75,8 +75,17 @@ template.app-deployed: | environmentURL: "https://{{.app.metadata.name}}.example.com" logURL: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" requiredContexts: [] + autoMerge: true + pullRequestComment: + content: | + Application {{.app.metadata.name}} is now running new version of deployments manifests. + See more here: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true ``` **Notes**: - If the message is set to 140 characters or more, it will be truncated. - If `github.repoURLPath` and `github.revisionPath` are same as above, they can be omitted. +- Automerge is optional and `true` by default for github deployments to ensure the requested ref is up to date with the default branch. + Setting this option to `false` is required if you would like to deploy older refs in your default branch. + For more information see the [Github Deployment API Docs](https://docs.github.com/en/rest/deployments/deployments?apiVersion=2022-11-28#create-a-deployment). +- If `github.pullRequestComment.content` is set to 65536 characters or more, it will be truncated. diff --git a/docs/generated/notification-services/googlechat.md b/docs/generated/notification-services/googlechat.md index 041ea6e022..fa3bdce8da 100755 --- a/docs/generated/notification-services/googlechat.md +++ b/docs/generated/notification-services/googlechat.md @@ -59,24 +59,27 @@ A card message can be defined as follows: ```yaml template.app-sync-succeeded: | googlechat: - cards: | + cardsV2: | - header: title: ArgoCD Bot Notification sections: - widgets: - - textParagraph: + - decoratedText: text: The app {{ .app.metadata.name }} has successfully synced! - widgets: - - keyValue: + - decoratedText: topLabel: Repository - content: {{ call .repo.RepoURLToHTTPS .app.spec.source.repoURL }} - - keyValue: + text: {{ call .repo.RepoURLToHTTPS .app.spec.source.repoURL }} + - decoratedText: topLabel: Revision - content: {{ .app.spec.source.targetRevision }} - - keyValue: + text: {{ .app.spec.source.targetRevision }} + - decoratedText: topLabel: Author - content: {{ (call .repo.GetCommitMetadata .app.status.sync.revision).Author }} + text: {{ (call .repo.GetCommitMetadata .app.status.sync.revision).Author }} ``` +All [Card fields](https://developers.google.com/chat/api/reference/rest/v1/cards#Card_1) are supported and can be used +in notifications. It is also possible to use the previous (now deprecated) `cards` key to use the legacy card fields, +but this is not recommended as Google has deprecated this field and recommends using the newer `cardsV2`. The card message can be written in JSON too. diff --git a/docs/generated/notification-services/grafana.md b/docs/generated/notification-services/grafana.md index ff567b71c1..a36672d0fa 100755 --- a/docs/generated/notification-services/grafana.md +++ b/docs/generated/notification-services/grafana.md @@ -4,6 +4,12 @@ To be able to create Grafana annotation with argocd-notifications you have to cr ![sample](https://user-images.githubusercontent.com/18019529/112024976-0f106080-8b78-11eb-9658-7663305899be.png) +Available parameters : + +* `apiURL` - the server url, e.g. https://grafana.example.com +* `apiKey` - the API key for the serviceaccount +* `insecureSkipVerify` - optional bool, true or false + 1. Login to your Grafana instance as `admin` 2. On the left menu, go to Configuration / API Keys 3. Click "Add API Key" diff --git a/docs/generated/notification-services/overview.md b/docs/generated/notification-services/overview.md index 15e674f654..265e575755 100755 --- a/docs/generated/notification-services/overview.md +++ b/docs/generated/notification-services/overview.md @@ -38,6 +38,7 @@ metadata: ## Service Types +* [AwsSqs](./awssqs.md) * [Email](./email.md) * [GitHub](./github.md) * [Slack](./slack.md) diff --git a/docs/generated/notification-services/slack.md b/docs/generated/notification-services/slack.md index 876445bfec..15937597c1 100755 --- a/docs/generated/notification-services/slack.md +++ b/docs/generated/notification-services/slack.md @@ -29,56 +29,56 @@ The Slack notification service configuration includes following settings: 1. Invite your slack bot to this channel **otherwise slack bot won't be able to deliver notifications to this channel** 1. Store Oauth access token in `argocd-notifications-secret` secret -```yaml - apiVersion: v1 - kind: Secret - metadata: - name: - stringData: - slack-token: -``` + ```yaml + apiVersion: v1 + kind: Secret + metadata: + name: + stringData: + slack-token: + ``` 1. Define service type slack in data section of `argocd-notifications-cm` configmap: -```yaml - apiVersion: v1 - kind: ConfigMap - metadata: - name: - data: - service.slack: | - token: $slack-token -``` + ```yaml + apiVersion: v1 + kind: ConfigMap + metadata: + name: + data: + service.slack: | + token: $slack-token + ``` 1. Add annotation in application yaml file to enable notifications for specific argocd app. The following example uses the [on-sync-succeeded trigger](../catalog.md#triggers): -```yaml - apiVersion: argoproj.io/v1alpha1 - kind: Application - metadata: - annotations: - notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my_channel -``` + ```yaml + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + annotations: + notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my_channel + ``` 1. Annotation with more than one [trigger](../catalog.md#triggers), with multiple destinations and recipients -```yaml - apiVersion: argoproj.io/v1alpha1 - kind: Application - metadata: - annotations: - notifications.argoproj.io/subscriptions: | - - trigger: [on-scaling-replica-set, on-rollout-updated, on-rollout-step-completed] - destinations: - - service: slack - recipients: [my-channel-1, my-channel-2] - - service: email - recipients: [recipient-1, recipient-2, recipient-3 ] - - trigger: [on-rollout-aborted, on-analysis-run-failed, on-analysis-run-error] - destinations: - - service: slack - recipients: [my-channel-21, my-channel-22] -``` + ```yaml + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + annotations: + notifications.argoproj.io/subscriptions: | + - trigger: [on-scaling-replica-set, on-rollout-updated, on-rollout-step-completed] + destinations: + - service: slack + recipients: [my-channel-1, my-channel-2] + - service: email + recipients: [recipient-1, recipient-2, recipient-3 ] + - trigger: [on-rollout-aborted, on-analysis-run-failed, on-analysis-run-error] + destinations: + - service: slack + recipients: [my-channel-21, my-channel-22] + ``` ## Templates diff --git a/go.mod b/go.mod index e5ed90b004..955e644fff 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module github.com/argoproj/argo-rollouts go 1.20 require ( - github.com/antonmedv/expr v1.13.0 - github.com/argoproj/notifications-engine v0.4.1-0.20230712163936-39dfcb66f902 + github.com/antonmedv/expr v1.15.3 + github.com/argoproj/notifications-engine v0.4.1-0.20231011160156-2d2d1a75dbee github.com/argoproj/pkg v0.13.6 - github.com/aws/aws-sdk-go-v2 v1.20.1 + github.com/aws/aws-sdk-go-v2 v1.21.1 github.com/aws/aws-sdk-go-v2/config v1.18.33 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.27.2 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.21.0 @@ -36,7 +36,7 @@ require ( github.com/stretchr/testify v1.8.4 github.com/tj/assert v0.0.3 github.com/valyala/fasttemplate v1.2.2 - google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 + google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 @@ -57,7 +57,7 @@ require ( ) require ( - cloud.google.com/go/compute v1.19.1 // indirect + cloud.google.com/go/compute v1.20.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.27 // indirect @@ -82,16 +82,17 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20220708192748-b73dcb041214 // indirect github.com/aws/aws-sdk-go v1.44.116 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.32 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 // indirect - github.com/aws/smithy-go v1.14.1 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.41 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.42 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.36 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect + github.com/aws/aws-sdk-go-v2/service/sqs v1.20.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.15.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.23.0 // indirect + github.com/aws/smithy-go v1.15.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -120,10 +121,13 @@ require ( github.com/google/go-github/v53 v53.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/s2a-go v0.1.4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/gregdel/pushover v1.1.0 // indirect + github.com/gregdel/pushover v1.2.1 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v0.14.1 // indirect @@ -162,7 +166,7 @@ require ( github.com/prometheus/procfs v0.10.1 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/slack-go/slack v0.12.2 // indirect - github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cast v1.5.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect @@ -170,21 +174,23 @@ require ( github.com/valyala/fastjson v1.6.3 // indirect github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 // indirect github.com/xlab/treeprint v1.1.0 // indirect + go.opencensus.io v0.24.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect - golang.org/x/crypto v0.7.0 // indirect + golang.org/x/crypto v0.11.0 // indirect golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect gomodules.xyz/notify v0.1.1 // indirect + google.golang.org/api v0.132.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect + google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // 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 604f38b70a..6265f6e972 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,8 @@ 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.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= 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= @@ -91,11 +91,11 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antonmedv/expr v1.13.0 h1:8YrTtlCzlOtXw+hpeCLDLL2uo0C0k6jmYpYTGws5c5w= -github.com/antonmedv/expr v1.13.0/go.mod h1:FPC8iWArxls7axbVLsW+kpg1mz29A1b2M6jt+hZfDkU= +github.com/antonmedv/expr v1.15.3 h1:q3hOJZNvLvhqE8OHBs1cFRdbXFNKuA+bHmRaI+AmRmI= +github.com/antonmedv/expr v1.15.3/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4JUv1ihsE= github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE= -github.com/argoproj/notifications-engine v0.4.1-0.20230712163936-39dfcb66f902 h1:JnW6RNwSxFwf4qQf3d6n+LhTODzmrLpDx2mQMPYzKf8= -github.com/argoproj/notifications-engine v0.4.1-0.20230712163936-39dfcb66f902/go.mod h1:W//xreL6/AGmJdh6SyvmJhOZ1VweW6DBm8qSBx7NO1M= +github.com/argoproj/notifications-engine v0.4.1-0.20231011160156-2d2d1a75dbee h1:ZYILioq4v6OIsr7uh0Pcx7JY4KpJ9qs8qbjRqM6HWMY= +github.com/argoproj/notifications-engine v0.4.1-0.20231011160156-2d2d1a75dbee/go.mod h1:VG9FXG0ddIVGc7NcSTRapaUjCPCYqOji//z6mmBYwCE= github.com/argoproj/pkg v0.13.6 h1:36WPD9MNYECHcO1/R1pj6teYspiK7uMQLCgLGft2abM= github.com/argoproj/pkg v0.13.6/go.mod h1:I698DoJBKuvNFaixh4vFl2C88cNIT1WS7KCbz5ewyF8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -103,34 +103,55 @@ 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.20.1 h1:rZBf5DWr7YGrnlTK4kgDQGn1ltqOg5orCYb/UhOFZkg= +github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac= +github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= +github.com/aws/aws-sdk-go-v2 v1.21.1 h1:wjHYshtPpYOZm+/mu3NhVgRRc0baM6LJZOmxPZ5Cwzs= +github.com/aws/aws-sdk-go-v2 v1.21.1/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= github.com/aws/aws-sdk-go-v2/config v1.18.33 h1:JKcw5SFxFW/rpM4mOPjv0VQ11E2kxW13F3exWOy7VZU= github.com/aws/aws-sdk-go-v2/config v1.18.33/go.mod h1:hXO/l9pgY3K5oZJldamP0pbZHdPqqk+4/maa7DSD3cA= -github.com/aws/aws-sdk-go-v2/credentials v1.13.32 h1:lIH1eKPcCY1ylR4B6PkBGRWMHO3aVenOKJHWiS4/G2w= github.com/aws/aws-sdk-go-v2/credentials v1.13.32/go.mod h1:lL8U3v/Y79YRG69WlAho0OHIKUXCyFvSXaIvfo81sls= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 h1:DK/9C+UN/X+1+Wm8pqaDksQr2tSLzq+8X1/rI/ZxKEQ= +github.com/aws/aws-sdk-go-v2/credentials v1.13.41 h1:dgbKq1tamtboYAKSXWbqL0lKO9rmEzEhbZFh9JQW/Bg= +github.com/aws/aws-sdk-go-v2/credentials v1.13.41/go.mod h1:cc3Fn7DkKbJalPtQnudHGZZ8ml9+hwtbc1CJONsYYqk= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8/go.mod h1:ce7BgLQfYr5hQFdy67oX2svto3ufGtm6oBvmsHScI1Q= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 h1:c8ed/T9T2K5I+h/JzmF5tpI46+OODQ74dzmdo+QnaMg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38/go.mod h1:qggunOChCMu9ZF/UkAfhTz25+U2rLVb3ya0Ua6TTfCA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 h1:hNeAAymUY5gu11WrrmFb3CVIp9Dar9hbo44yzzcQpzA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.42 h1:817VqVe6wvwE46xXy6YF5RywvjOX6U2zRQQ6IbQFK0s= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.42/go.mod h1:oDfgXoBBmj+kXnqxDDnIDnC56QBosglKp8ftRCTxR+0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32/go.mod h1:0ZXSqrty4FtQ7p8TEuRde/SZm9X05KT18LAUlR40Ln0= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 h1:fc0ukRAiP1syoSGZYu+DaE+FulSYhTiJ8WpVu5jElU4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.36 h1:7ZApaXzWbo8slc+W5TynuUlB4z66g44h7uqa3/d/BsY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.36/go.mod h1:rwr4WnmFi3RJO0M4dxbJtgi9BPLMpVBMX1nUte5ha9U= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39/go.mod h1:WLAW8PT7+JhjZfLSWe7WEJaJu0GNo0cKc2Zyo003RBs= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 h1:g+qlObJH4Kn4n21g69DjspU0hKTjWtq7naZ9OLCv0ew= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.27.2 h1:HbEoy5QzXicnGgGWF4moCgsbio2xytgVQcs70xD3j3w= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.27.2/go.mod h1:Fc5ZJyxghsjGp1KqbLb2HTJjsJjSv6AXUikHUJYmCHM= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.21.0 h1:lSCNS+ZMztgQWoLz/I27HdYjKlUaKEMWApM0dVOR/y8= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.21.0/go.mod h1:AZv/T0/2rhNBLiY2k109TT6HJ7Z0P8Z+SYvs0jqVkXE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 h1:dGAseBFEYxth10V23b5e2mAS+tX7oVbfYHD6dnDdAsg= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32/go.mod h1:4jwAWKEkCR0anWk5+1RbfSg1R5Gzld7NLiuaq5bTR/Y= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 h1:A2RlEMo4SJSwbNoUUgkxTAEMduAy/8wG3eB2b2lP4gY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= +github.com/aws/aws-sdk-go-v2/service/sqs v1.20.0 h1:tQoMg8i4nFAB70cJ4wiAYEiZRYo2P6uDmU2D6ys/igo= +github.com/aws/aws-sdk-go-v2/service/sqs v1.20.0/go.mod h1:jQhN5f4p3PALMNlUtfb/0wGIFlV7vGtJlPDVfxfNfPY= github.com/aws/aws-sdk-go-v2/service/sso v1.13.2/go.mod h1:ju+nNXUunfIFamXUIZQiICjnO/TPlOmWcYhZcSy7xaE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 h1:OJELEgyaT2kmaBGZ+myyZbTTLobfe3ox3FSh5eYK9Qs= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.0 h1:vuGK1vHNP9zx0PfOrtPumbwR2af0ATQ1Z2H6p75AgRQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.0/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2/go.mod h1:ubDBBaDFs1GHijSOTi8ljppML15GLG0HxhILtbjNNYQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 h1:ympg1+Lnq33XLhcK/xTG4yZHPs1Oyxu+6DEWbl7qOzA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 h1:8lKOidPkmSmfUtiTgtdXWgaKItCZ/g75/jEk6Ql6GsA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= github.com/aws/aws-sdk-go-v2/service/sts v1.21.2/go.mod h1:FQ/DQcOfESELfJi5ED+IPPAjI5xC6nxtSolVVB773jM= -github.com/aws/smithy-go v1.14.1 h1:EFKMUmH/iHMqLiwoEDx2rRjRQpI1YCn5jTysoaDujFs= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.0 h1:pyvfUqkNLMipdKNAtu7OVbRxUrR2BMaKccIPpk/Hkak= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.0/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= +github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -165,7 +186,11 @@ github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEM 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/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 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/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -200,6 +225,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -217,7 +243,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.94.0/go.mod h1:LWZfzOd7PRy8GJ1dJ6mCU6tNdSfOwRac1BUPam4aw6Q= @@ -339,6 +365,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -367,14 +394,20 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= @@ -387,8 +420,8 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregdel/pushover v1.1.0 h1:dwHyvrcpZCOS9V1fAnKPaGRRI5OC55cVaKhMybqNsKQ= -github.com/gregdel/pushover v1.1.0/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= +github.com/gregdel/pushover v1.2.1 h1:IPPJCdzXz60gMqnlzS0ZAW5z5aS1gI4nU+YM0Pe+ssA= +github.com/gregdel/pushover v1.2.1/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -622,8 +655,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= @@ -653,8 +686,8 @@ github.com/spaceapegames/go-wavefront v1.8.1/go.mod h1:GtdIjtJ0URkfPmaKx0+7vMSDv github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +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.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= @@ -680,6 +713,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= @@ -716,6 +750,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= @@ -734,12 +770,14 @@ golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 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 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= 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= @@ -825,16 +863,18 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug 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 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= 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= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 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 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= 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= @@ -848,7 +888,7 @@ 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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= 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= @@ -919,16 +959,18 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= 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 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= 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= @@ -938,11 +980,13 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 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 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= @@ -1030,6 +1074,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.132.0 h1:8t2/+qZ26kAOGSmOiHwVycqVaDg7q3JDILrNi/Z6rvc= +google.golang.org/api v0.132.0/go.mod h1:AeTBC6GpJnJSRJjktDcPX0QwtS8pGYZOV6MSuSCusw0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1069,12 +1115,12 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= 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= @@ -1088,8 +1134,10 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 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.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/mkdocs.yml b/mkdocs.yml index 471359c778..8506973d4f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -75,6 +75,7 @@ nav: - Overview: features/notifications.md - Services: - generated/notification-services/alertmanager.md + - generated/notification-services/awssqs.md - generated/notification-services/email.md - generated/notification-services/github.md - generated/notification-services/googlechat.md From 270f297315a80953ec9701b59a98c4ecb35e174c Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 12 Oct 2023 13:00:01 -0600 Subject: [PATCH 61/90] fix: keep rs informer updated (#3091) * keep rs informer updated Signed-off-by: zachaller * correct bad log Signed-off-by: zachaller * add error context Signed-off-by: zachaller --------- Signed-off-by: zachaller --- rollout/controller.go | 3 ++- rollout/replicaset.go | 4 +++- rollout/replicaset_test.go | 21 +++++++++++++++++---- rollout/sync.go | 10 +++++++++- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/rollout/controller.go b/rollout/controller.go index b5c51914ae..899bc25516 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -131,6 +131,7 @@ type reconcilerBase struct { replicaSetSynced cache.InformerSynced rolloutsInformer cache.SharedIndexInformer rolloutsLister listers.RolloutLister + replicaSetInformer cache.SharedIndexInformer rolloutsSynced cache.InformerSynced rolloutsIndexer cache.Indexer servicesLister v1.ServiceLister @@ -175,7 +176,6 @@ func NewController(cfg ControllerConfig) *Controller { controllerutil.EnqueueAfter(obj, duration, cfg.RolloutWorkQueue) }, } - base := reconcilerBase{ kubeclientset: cfg.KubeClientSet, argoprojclientset: cfg.ArgoProjClientset, @@ -184,6 +184,7 @@ func NewController(cfg ControllerConfig) *Controller { replicaSetLister: cfg.ReplicaSetInformer.Lister(), replicaSetSynced: cfg.ReplicaSetInformer.Informer().HasSynced, rolloutsInformer: cfg.RolloutsInformer.Informer(), + replicaSetInformer: cfg.ReplicaSetInformer.Informer(), rolloutsIndexer: cfg.RolloutsInformer.Informer().GetIndexer(), rolloutsLister: cfg.RolloutsInformer.Lister(), rolloutsSynced: cfg.RolloutsInformer.Informer().HasSynced, diff --git a/rollout/replicaset.go b/rollout/replicaset.go index dceff65aa0..fad23e756e 100644 --- a/rollout/replicaset.go +++ b/rollout/replicaset.go @@ -35,6 +35,7 @@ func (c *rolloutContext) removeScaleDownDelay(rs *appsv1.ReplicaSet) error { _, err := c.kubeclientset.AppsV1().ReplicaSets(rs.Namespace).Patch(ctx, rs.Name, patchtypes.JSONPatchType, []byte(patch), metav1.PatchOptions{}) if err == nil { c.log.Infof("Removed '%s' annotation from RS '%s'", v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, rs.Name) + c.replicaSetInformer.GetIndexer().Update(rs) } return err } @@ -56,9 +57,10 @@ func (c *rolloutContext) addScaleDownDelay(rs *appsv1.ReplicaSet, scaleDownDelay } deadline := timeutil.MetaNow().Add(scaleDownDelaySeconds).UTC().Format(time.RFC3339) patch := fmt.Sprintf(addScaleDownAtAnnotationsPatch, v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, deadline) - _, err := c.kubeclientset.AppsV1().ReplicaSets(rs.Namespace).Patch(ctx, rs.Name, patchtypes.JSONPatchType, []byte(patch), metav1.PatchOptions{}) + rs, err := c.kubeclientset.AppsV1().ReplicaSets(rs.Namespace).Patch(ctx, rs.Name, patchtypes.JSONPatchType, []byte(patch), metav1.PatchOptions{}) if err == nil { c.log.Infof("Set '%s' annotation on '%s' to %s (%s)", v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, rs.Name, deadline, scaleDownDelaySeconds) + c.replicaSetInformer.GetIndexer().Update(rs) } return err } diff --git a/rollout/replicaset_test.go b/rollout/replicaset_test.go index b1588ff4ce..7baba5e7a3 100644 --- a/rollout/replicaset_test.go +++ b/rollout/replicaset_test.go @@ -195,16 +195,29 @@ func TestReconcileNewReplicaSet(t *testing.T) { rollout := newBlueGreenRollout("foo", test.rolloutReplicas, nil, "", "") fake := fake.Clientset{} k8sfake := k8sfake.Clientset{} + + f := newFixture(t) + defer f.Close() + f.objects = append(f.objects, rollout) + f.replicaSetLister = append(f.replicaSetLister, oldRS, newRS) + f.kubeobjects = append(f.kubeobjects, oldRS, newRS) + _, informers, k8sInformer := f.newController(noResyncPeriodFunc) + stopCh := make(chan struct{}) + informers.Start(stopCh) + informers.WaitForCacheSync(stopCh) + close(stopCh) + roCtx := rolloutContext{ log: logutil.WithRollout(rollout), rollout: rollout, newRS: newRS, stableRS: oldRS, reconcilerBase: reconcilerBase{ - argoprojclientset: &fake, - kubeclientset: &k8sfake, - recorder: record.NewFakeEventRecorder(), - resyncPeriod: 30 * time.Second, + argoprojclientset: &fake, + kubeclientset: &k8sfake, + recorder: record.NewFakeEventRecorder(), + resyncPeriod: 30 * time.Second, + replicaSetInformer: k8sInformer.Apps().V1().ReplicaSets().Informer(), }, pauseContext: &pauseContext{ rollout: rollout, diff --git a/rollout/sync.go b/rollout/sync.go index 98990b4596..a4682fad70 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -85,7 +85,14 @@ func (c *rolloutContext) syncReplicaSetRevision() (*appsv1.ReplicaSet, error) { if annotationsUpdated || minReadySecondsNeedsUpdate || affinityNeedsUpdate { rsCopy.Spec.MinReadySeconds = c.rollout.Spec.MinReadySeconds rsCopy.Spec.Template.Spec.Affinity = replicasetutil.GenerateReplicaSetAffinity(*c.rollout) - return c.kubeclientset.AppsV1().ReplicaSets(rsCopy.ObjectMeta.Namespace).Update(ctx, rsCopy, metav1.UpdateOptions{}) + 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) + c.replicaSetInformer.GetIndexer().Update(rs) + return rs, nil } // Should use the revision in existingNewRS's annotation, since it set by before @@ -360,6 +367,7 @@ func (c *rolloutContext) scaleReplicaSet(rs *appsv1.ReplicaSet, newScale int32, scaled = true revision, _ := replicasetutil.Revision(rs) c.recorder.Eventf(rollout, record.EventOptions{EventReason: conditions.ScalingReplicaSetReason}, conditions.ScalingReplicaSetMessage, scalingOperation, rs.Name, revision, oldScale, newScale) + c.replicaSetInformer.GetIndexer().Update(rs) } } return scaled, rs, err From e1ba61f2512f0195ca335ebbc74db83a7b130257 Mon Sep 17 00:00:00 2001 From: AS <11219262+ashutosh16@users.noreply.github.com> Date: Fri, 13 Oct 2023 06:55:48 -0700 Subject: [PATCH 62/90] chore: add missing rollout fields (#3062) * chores: add missing rollout fields Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com> * chores: add missing rollout fields Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com> * chores: add missing rollout fields Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com> * chores: add missing rollout fields Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com> * chores: add missing rollout fields Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com> --------- Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com> --- pkg/apiclient/rollout/rollout.pb.go | 573 +++++-- pkg/apiclient/rollout/rollout.proto | 10 + pkg/apiclient/rollout/rollout.swagger.json | 905 +++++++++- .../info/analysisrun_info.go | 6 + ui/src/models/rollout/generated/api.ts | 1487 +++++++++++++++-- 5 files changed, 2695 insertions(+), 286 deletions(-) diff --git a/pkg/apiclient/rollout/rollout.pb.go b/pkg/apiclient/rollout/rollout.pb.go index 4f36576290..54e4c099a2 100644 --- a/pkg/apiclient/rollout/rollout.pb.go +++ b/pkg/apiclient/rollout/rollout.pb.go @@ -1380,28 +1380,87 @@ func (m *JobInfo) GetStartedAt() *v1.Time { return nil } +type AnalysisRunSpecAndStatus struct { + Spec *v1alpha1.AnalysisRunSpec `protobuf:"bytes,1,opt,name=spec,proto3" json:"spec,omitempty"` + Status *v1alpha1.AnalysisRunStatus `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AnalysisRunSpecAndStatus) Reset() { *m = AnalysisRunSpecAndStatus{} } +func (m *AnalysisRunSpecAndStatus) String() string { return proto.CompactTextString(m) } +func (*AnalysisRunSpecAndStatus) ProtoMessage() {} +func (*AnalysisRunSpecAndStatus) Descriptor() ([]byte, []int) { + return fileDescriptor_99101d942e8912a7, []int{18} +} +func (m *AnalysisRunSpecAndStatus) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AnalysisRunSpecAndStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AnalysisRunSpecAndStatus.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AnalysisRunSpecAndStatus) XXX_Merge(src proto.Message) { + xxx_messageInfo_AnalysisRunSpecAndStatus.Merge(m, src) +} +func (m *AnalysisRunSpecAndStatus) XXX_Size() int { + return m.Size() +} +func (m *AnalysisRunSpecAndStatus) XXX_DiscardUnknown() { + xxx_messageInfo_AnalysisRunSpecAndStatus.DiscardUnknown(m) +} + +var xxx_messageInfo_AnalysisRunSpecAndStatus proto.InternalMessageInfo + +func (m *AnalysisRunSpecAndStatus) GetSpec() *v1alpha1.AnalysisRunSpec { + if m != nil { + return m.Spec + } + return nil +} + +func (m *AnalysisRunSpecAndStatus) GetStatus() *v1alpha1.AnalysisRunStatus { + if m != nil { + return m.Status + } + return nil +} + type AnalysisRunInfo struct { - ObjectMeta *v1.ObjectMeta `protobuf:"bytes,1,opt,name=objectMeta,proto3" json:"objectMeta,omitempty"` - Icon string `protobuf:"bytes,2,opt,name=icon,proto3" json:"icon,omitempty"` - Revision int64 `protobuf:"varint,3,opt,name=revision,proto3" json:"revision,omitempty"` - Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` - Successful int32 `protobuf:"varint,5,opt,name=successful,proto3" json:"successful,omitempty"` - Failed int32 `protobuf:"varint,6,opt,name=failed,proto3" json:"failed,omitempty"` - Inconclusive int32 `protobuf:"varint,7,opt,name=inconclusive,proto3" json:"inconclusive,omitempty"` - Error int32 `protobuf:"varint,8,opt,name=error,proto3" json:"error,omitempty"` - Jobs []*JobInfo `protobuf:"bytes,9,rep,name=jobs,proto3" json:"jobs,omitempty"` - NonJobInfo []*NonJobInfo `protobuf:"bytes,10,rep,name=nonJobInfo,proto3" json:"nonJobInfo,omitempty"` - Metrics []*Metrics `protobuf:"bytes,11,rep,name=metrics,proto3" json:"metrics,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + ObjectMeta *v1.ObjectMeta `protobuf:"bytes,1,opt,name=objectMeta,proto3" json:"objectMeta,omitempty"` + // + //field type from 161 -170 will be deprecated in future. + Icon string `protobuf:"bytes,2,opt,name=icon,proto3" json:"icon,omitempty"` + Revision int64 `protobuf:"varint,3,opt,name=revision,proto3" json:"revision,omitempty"` + Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` + Successful int32 `protobuf:"varint,5,opt,name=successful,proto3" json:"successful,omitempty"` + Failed int32 `protobuf:"varint,6,opt,name=failed,proto3" json:"failed,omitempty"` + Inconclusive int32 `protobuf:"varint,7,opt,name=inconclusive,proto3" json:"inconclusive,omitempty"` + Error int32 `protobuf:"varint,8,opt,name=error,proto3" json:"error,omitempty"` + Jobs []*JobInfo `protobuf:"bytes,9,rep,name=jobs,proto3" json:"jobs,omitempty"` + NonJobInfo []*NonJobInfo `protobuf:"bytes,10,rep,name=nonJobInfo,proto3" json:"nonJobInfo,omitempty"` + Metrics []*Metrics `protobuf:"bytes,11,rep,name=metrics,proto3" json:"metrics,omitempty"` + // The new API changes should use SpecAndStatus field type. + SpecAndStatus *AnalysisRunSpecAndStatus `protobuf:"bytes,12,opt,name=specAndStatus,proto3" json:"specAndStatus,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *AnalysisRunInfo) Reset() { *m = AnalysisRunInfo{} } func (m *AnalysisRunInfo) String() string { return proto.CompactTextString(m) } func (*AnalysisRunInfo) ProtoMessage() {} func (*AnalysisRunInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_99101d942e8912a7, []int{18} + return fileDescriptor_99101d942e8912a7, []int{19} } func (m *AnalysisRunInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1507,6 +1566,13 @@ func (m *AnalysisRunInfo) GetMetrics() []*Metrics { return nil } +func (m *AnalysisRunInfo) GetSpecAndStatus() *AnalysisRunSpecAndStatus { + if m != nil { + return m.SpecAndStatus + } + return nil +} + type NonJobInfo struct { Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` @@ -1521,7 +1587,7 @@ func (m *NonJobInfo) Reset() { *m = NonJobInfo{} } func (m *NonJobInfo) String() string { return proto.CompactTextString(m) } func (*NonJobInfo) ProtoMessage() {} func (*NonJobInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_99101d942e8912a7, []int{19} + return fileDescriptor_99101d942e8912a7, []int{20} } func (m *NonJobInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1593,7 +1659,7 @@ func (m *Metrics) Reset() { *m = Metrics{} } func (m *Metrics) String() string { return proto.CompactTextString(m) } func (*Metrics) ProtoMessage() {} func (*Metrics) Descriptor() ([]byte, []int) { - return fileDescriptor_99101d942e8912a7, []int{20} + return fileDescriptor_99101d942e8912a7, []int{21} } func (m *Metrics) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1676,6 +1742,7 @@ func init() { proto.RegisterType((*PodInfo)(nil), "rollout.PodInfo") proto.RegisterType((*ContainerInfo)(nil), "rollout.ContainerInfo") proto.RegisterType((*JobInfo)(nil), "rollout.JobInfo") + proto.RegisterType((*AnalysisRunSpecAndStatus)(nil), "rollout.AnalysisRunSpecAndStatus") proto.RegisterType((*AnalysisRunInfo)(nil), "rollout.AnalysisRunInfo") proto.RegisterType((*NonJobInfo)(nil), "rollout.NonJobInfo") proto.RegisterType((*Metrics)(nil), "rollout.Metrics") @@ -1686,117 +1753,121 @@ func init() { } var fileDescriptor_99101d942e8912a7 = []byte{ - // 1751 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcd, 0x6f, 0x1c, 0x49, - 0x15, 0x57, 0x7b, 0x3c, 0xf6, 0xf8, 0x8d, 0x3f, 0xc6, 0xe5, 0x6c, 0xb6, 0x77, 0x36, 0x58, 0xa6, - 0x17, 0x09, 0xc7, 0x40, 0xb7, 0x93, 0x8d, 0xb2, 0x2c, 0x1f, 0x87, 0x90, 0x58, 0xde, 0xa0, 0xec, - 0x12, 0x3a, 0xc0, 0x0a, 0x24, 0x88, 0x6a, 0x7a, 0xca, 0xe3, 0x4e, 0x7a, 0xba, 0x9a, 0xae, 0xea, - 0x09, 0x23, 0x6b, 0x0e, 0xf0, 0x0f, 0x70, 0xe0, 0x5f, 0x58, 0x09, 0x71, 0x42, 0x48, 0x5c, 0x38, - 0x70, 0x45, 0x1c, 0x91, 0xf8, 0x07, 0x50, 0xc4, 0x85, 0x23, 0x17, 0xce, 0xa8, 0x5e, 0x57, 0x57, - 0x7f, 0x78, 0xec, 0x38, 0xb2, 0x21, 0x7b, 0x9a, 0x7a, 0xef, 0xd5, 0x7b, 0xef, 0x57, 0xf3, 0x3e, - 0xaa, 0xfa, 0xc1, 0x7b, 0xc9, 0xf3, 0x91, 0x47, 0x93, 0x30, 0x88, 0x42, 0x16, 0x4b, 0x2f, 0xe5, - 0x51, 0xc4, 0x33, 0xf3, 0xeb, 0x26, 0x29, 0x97, 0x9c, 0x2c, 0x6b, 0xb2, 0x7f, 0x63, 0xc4, 0xf9, - 0x28, 0x62, 0x4a, 0xc1, 0xa3, 0x71, 0xcc, 0x25, 0x95, 0x21, 0x8f, 0x45, 0xbe, 0xad, 0xff, 0x68, - 0x14, 0xca, 0xe3, 0x6c, 0xe0, 0x06, 0x7c, 0xec, 0xd1, 0x74, 0xc4, 0x93, 0x94, 0x3f, 0xc3, 0xc5, - 0xd7, 0xb4, 0xbe, 0xf0, 0xb4, 0x37, 0xe1, 0x19, 0xce, 0xe4, 0x16, 0x8d, 0x92, 0x63, 0x7a, 0xcb, - 0x1b, 0xb1, 0x98, 0xa5, 0x54, 0xb2, 0xa1, 0xb6, 0x76, 0xe7, 0xf9, 0xd7, 0x85, 0x1b, 0x72, 0xb5, - 0x7d, 0x4c, 0x83, 0xe3, 0x30, 0x66, 0xe9, 0xb4, 0xd4, 0x1f, 0x33, 0x49, 0xbd, 0xc9, 0x69, 0xad, - 0x77, 0x35, 0x42, 0xa4, 0x06, 0xd9, 0x91, 0xc7, 0xc6, 0x89, 0x9c, 0xe6, 0x42, 0xe7, 0x01, 0xf4, - 0xfc, 0xdc, 0xef, 0xc3, 0xf8, 0x88, 0x7f, 0x3f, 0x63, 0xe9, 0x94, 0x10, 0x58, 0x8c, 0xe9, 0x98, - 0xd9, 0xd6, 0x8e, 0xb5, 0xbb, 0xe2, 0xe3, 0x9a, 0xdc, 0x80, 0x15, 0xf5, 0x2b, 0x12, 0x1a, 0x30, - 0x7b, 0x01, 0x05, 0x25, 0xc3, 0xb9, 0x03, 0xd7, 0x2a, 0x56, 0x1e, 0x85, 0x42, 0xe6, 0x96, 0x6a, - 0x5a, 0x56, 0x53, 0xeb, 0xd7, 0x16, 0x6c, 0x3c, 0x61, 0xf2, 0xe1, 0x98, 0x8e, 0x98, 0xcf, 0x7e, - 0x9e, 0x31, 0x21, 0x89, 0x0d, 0xc5, 0x3f, 0xab, 0xf7, 0x17, 0xa4, 0xb2, 0x15, 0xf0, 0x58, 0x52, - 0x75, 0xea, 0x02, 0x81, 0x61, 0x90, 0x6b, 0xd0, 0x0e, 0x95, 0x1d, 0xbb, 0x85, 0x92, 0x9c, 0x20, - 0x3d, 0x68, 0x49, 0x3a, 0xb2, 0x17, 0x91, 0xa7, 0x96, 0x75, 0x44, 0xed, 0x26, 0xa2, 0x63, 0x20, - 0x3f, 0x8c, 0x87, 0x5c, 0x9f, 0xe5, 0xd5, 0x98, 0xfa, 0xd0, 0x49, 0xd9, 0x24, 0x14, 0x21, 0x8f, - 0x11, 0x52, 0xcb, 0x37, 0x74, 0xdd, 0x53, 0xab, 0xe9, 0xe9, 0x21, 0xbc, 0xe5, 0x33, 0x21, 0x69, - 0x2a, 0x1b, 0xce, 0x5e, 0xff, 0xcf, 0xff, 0x29, 0xbc, 0xf5, 0x38, 0xe5, 0x63, 0x2e, 0xd9, 0x65, - 0x4d, 0x29, 0x8d, 0xa3, 0x2c, 0x8a, 0x10, 0x6e, 0xc7, 0xc7, 0xb5, 0x73, 0x08, 0x5b, 0xf7, 0x06, - 0xfc, 0x0a, 0x70, 0x1e, 0xc2, 0x96, 0xcf, 0x64, 0x3a, 0xbd, 0xb4, 0xa1, 0xa7, 0xb0, 0xa9, 0x6d, - 0x7c, 0x4a, 0x65, 0x70, 0x7c, 0x30, 0x61, 0x31, 0x9a, 0x91, 0xd3, 0xc4, 0x98, 0x51, 0x6b, 0x72, - 0x17, 0xba, 0x69, 0x99, 0x96, 0x68, 0xa8, 0x7b, 0xfb, 0x9a, 0x5b, 0x54, 0x72, 0x25, 0x65, 0xfd, - 0xea, 0x46, 0xe7, 0x29, 0xac, 0x7d, 0x52, 0x78, 0x53, 0x8c, 0xf3, 0xf3, 0x98, 0xec, 0xc3, 0x16, - 0x9d, 0xd0, 0x30, 0xa2, 0x83, 0x88, 0x19, 0x3d, 0x61, 0x2f, 0xec, 0xb4, 0x76, 0x57, 0xfc, 0x79, - 0x22, 0xe7, 0x3e, 0x6c, 0x34, 0xea, 0x85, 0xec, 0x43, 0xa7, 0x68, 0x00, 0xb6, 0xb5, 0xd3, 0x3a, - 0x13, 0xa8, 0xd9, 0xe5, 0x7c, 0x00, 0xdd, 0x1f, 0xb1, 0x54, 0xe5, 0x1a, 0x62, 0xdc, 0x85, 0x8d, - 0x42, 0xa4, 0xd9, 0x1a, 0x69, 0x93, 0xed, 0xfc, 0x76, 0x09, 0xba, 0x15, 0x93, 0xe4, 0x31, 0x00, - 0x1f, 0x3c, 0x63, 0x81, 0xfc, 0x98, 0x49, 0x8a, 0x4a, 0xdd, 0xdb, 0xfb, 0x6e, 0xde, 0x6b, 0xdc, - 0x6a, 0xaf, 0x71, 0x93, 0xe7, 0x23, 0xc5, 0x10, 0xae, 0xea, 0x35, 0xee, 0xe4, 0x96, 0xfb, 0x3d, - 0xa3, 0xe7, 0x57, 0x6c, 0x90, 0xeb, 0xb0, 0x24, 0x24, 0x95, 0x99, 0xd0, 0xc1, 0xd3, 0x94, 0xaa, - 0xa4, 0x31, 0x13, 0xa2, 0xac, 0xd3, 0x82, 0x54, 0xe1, 0x0b, 0x03, 0x1e, 0xeb, 0x52, 0xc5, 0xb5, - 0xaa, 0x2e, 0x21, 0x55, 0x27, 0x1b, 0x4d, 0x75, 0xa9, 0x1a, 0x5a, 0xed, 0x17, 0x92, 0x25, 0xf6, - 0x52, 0xbe, 0x5f, 0xad, 0x55, 0x94, 0x04, 0x93, 0x9f, 0xb2, 0x70, 0x74, 0x2c, 0xed, 0xe5, 0x3c, - 0x4a, 0x86, 0x41, 0x1c, 0x58, 0xa5, 0x81, 0xcc, 0x68, 0xa4, 0x37, 0x74, 0x70, 0x43, 0x8d, 0xa7, - 0xba, 0x48, 0xca, 0xe8, 0x70, 0x6a, 0xaf, 0xec, 0x58, 0xbb, 0x6d, 0x3f, 0x27, 0x14, 0xea, 0x20, - 0x4b, 0x53, 0x16, 0x4b, 0x1b, 0x90, 0x5f, 0x90, 0x4a, 0x32, 0x64, 0x22, 0x4c, 0xd9, 0xd0, 0xee, - 0xe6, 0x12, 0x4d, 0x2a, 0x49, 0x96, 0x0c, 0x55, 0x17, 0xb6, 0x57, 0x73, 0x89, 0x26, 0x15, 0x4a, - 0x93, 0x12, 0xf6, 0x1a, 0xca, 0x4a, 0x06, 0xd9, 0x81, 0x6e, 0x9a, 0xf7, 0x05, 0x36, 0xbc, 0x27, - 0xed, 0x75, 0x04, 0x59, 0x65, 0x91, 0x6d, 0x00, 0xdd, 0xe1, 0x55, 0x88, 0x37, 0x70, 0x43, 0x85, - 0x43, 0x3e, 0x54, 0x16, 0x92, 0x28, 0x0c, 0xe8, 0x13, 0x26, 0x85, 0xdd, 0xc3, 0x5c, 0x7a, 0xbb, - 0xcc, 0x25, 0x23, 0xd3, 0x79, 0x5f, 0xee, 0x55, 0xaa, 0xec, 0x17, 0x09, 0x4b, 0xc3, 0x31, 0x8b, - 0xa5, 0xb0, 0x37, 0x1b, 0xaa, 0x07, 0x46, 0x96, 0xab, 0x56, 0xf6, 0x92, 0x6f, 0xc1, 0x2a, 0x8d, - 0x69, 0x34, 0x15, 0xa1, 0xf0, 0xb3, 0x58, 0xd8, 0x04, 0x75, 0x6d, 0xa3, 0x7b, 0xaf, 0x14, 0xa2, - 0x72, 0x6d, 0x37, 0xb9, 0x0b, 0x60, 0x5a, 0xb9, 0xb0, 0xb7, 0x50, 0xf7, 0xba, 0xd1, 0xbd, 0x5f, - 0x88, 0x50, 0xb3, 0xb2, 0x93, 0xfc, 0x0c, 0xda, 0x2a, 0xf2, 0xc2, 0xbe, 0x86, 0x2a, 0x1f, 0xb9, - 0xe5, 0x75, 0xeb, 0x16, 0xd7, 0x2d, 0x2e, 0x9e, 0x16, 0x35, 0x50, 0xa6, 0xb0, 0xe1, 0x14, 0xd7, - 0xad, 0x7b, 0x9f, 0xc6, 0x34, 0x9d, 0x3e, 0x91, 0x2c, 0xf1, 0x73, 0xb3, 0xce, 0x9f, 0x17, 0x60, - 0xbd, 0x7e, 0xea, 0xff, 0x41, 0xb1, 0x14, 0xa9, 0xbf, 0x50, 0x4f, 0x7d, 0x73, 0xb1, 0xb4, 0x1a, - 0x17, 0x4b, 0x59, 0x5c, 0x8b, 0x67, 0x15, 0x57, 0xbb, 0x5e, 0x5c, 0x8d, 0x94, 0x58, 0x7a, 0x8d, - 0x94, 0x68, 0xc6, 0x75, 0xf9, 0x75, 0xe2, 0xea, 0xfc, 0xa7, 0x05, 0xeb, 0x75, 0xeb, 0xff, 0xc7, - 0x66, 0x53, 0xfc, 0xaf, 0xad, 0x33, 0xfe, 0xd7, 0xc5, 0xb9, 0xff, 0xab, 0xaa, 0xca, 0x36, 0x5e, - 0x7f, 0x9a, 0x52, 0xfc, 0x00, 0x33, 0x03, 0x9b, 0x4d, 0xc7, 0xd7, 0x94, 0xe2, 0xd3, 0x40, 0x86, - 0x13, 0x86, 0xbd, 0xa6, 0xe3, 0x6b, 0x4a, 0xc5, 0x21, 0x51, 0x46, 0xd9, 0x0b, 0xec, 0x31, 0x1d, - 0xbf, 0x20, 0x73, 0xef, 0xf8, 0x6f, 0x08, 0xdd, 0x61, 0x0c, 0x5d, 0x6f, 0x0b, 0xd0, 0x6c, 0x0b, - 0x7d, 0xe8, 0x48, 0x36, 0x4e, 0x22, 0x2a, 0x19, 0x76, 0x9a, 0x15, 0xdf, 0xd0, 0xe4, 0xab, 0xb0, - 0x29, 0x02, 0x1a, 0xb1, 0x07, 0xfc, 0x45, 0xfc, 0x80, 0xd1, 0x61, 0x14, 0xc6, 0x0c, 0x9b, 0xce, - 0x8a, 0x7f, 0x5a, 0xa0, 0x50, 0xe3, 0xdb, 0x48, 0xd8, 0x6b, 0x78, 0x3f, 0x69, 0x8a, 0x7c, 0x09, - 0x16, 0x13, 0x3e, 0x14, 0xf6, 0x3a, 0x06, 0xb8, 0x67, 0x02, 0xfc, 0x98, 0x0f, 0x31, 0xb0, 0x28, - 0x55, 0xff, 0x69, 0x12, 0xc6, 0x23, 0x6c, 0x3b, 0x1d, 0x1f, 0xd7, 0xc8, 0xe3, 0xf1, 0xc8, 0xee, - 0x69, 0x1e, 0x8f, 0x47, 0xce, 0x9f, 0x2c, 0x58, 0xd6, 0x9a, 0x6f, 0x38, 0xe2, 0xa6, 0xa5, 0xe7, - 0xc5, 0xa2, 0x5b, 0x3a, 0x46, 0x02, 0x7b, 0xaa, 0xc0, 0x68, 0x63, 0x24, 0x72, 0xda, 0xf9, 0x10, - 0xd6, 0x6a, 0x1d, 0x67, 0xee, 0x0b, 0xc5, 0xbc, 0x37, 0x17, 0x2a, 0xef, 0x4d, 0xe7, 0xdf, 0x16, - 0x2c, 0x7f, 0x97, 0x0f, 0x3e, 0x07, 0xc7, 0xde, 0x06, 0x18, 0x33, 0x99, 0x86, 0x81, 0x7a, 0x75, - 0xe8, 0xb3, 0x57, 0x38, 0xe4, 0x23, 0x58, 0x29, 0x6f, 0x99, 0x36, 0x82, 0xdb, 0xbb, 0x18, 0xb8, - 0x1f, 0x84, 0x63, 0xe6, 0x97, 0xca, 0xce, 0x67, 0x2d, 0xd8, 0x68, 0x74, 0x81, 0xcf, 0x71, 0x93, - 0xdc, 0x06, 0x10, 0x59, 0x10, 0x30, 0x21, 0x8e, 0xb2, 0x48, 0x87, 0xbe, 0xc2, 0x51, 0x7a, 0x47, - 0x34, 0x8c, 0xd8, 0x10, 0x8b, 0xbd, 0xed, 0x6b, 0x4a, 0xbd, 0x1e, 0xc2, 0x38, 0xe0, 0x71, 0x10, - 0x65, 0xa2, 0x28, 0xf9, 0xb6, 0x5f, 0xe3, 0xa9, 0x9c, 0x60, 0x69, 0xca, 0x53, 0x2c, 0xfb, 0xb6, - 0x9f, 0x13, 0xaa, 0xb0, 0x9e, 0xf1, 0x81, 0x2a, 0xf8, 0x7a, 0x61, 0xe9, 0x3c, 0xf1, 0x51, 0x4a, - 0xde, 0x07, 0x88, 0x79, 0xac, 0x79, 0x36, 0xe0, 0xde, 0x2d, 0xb3, 0xf7, 0x13, 0x23, 0xf2, 0x2b, - 0xdb, 0xc8, 0x9e, 0xea, 0xf8, 0x2a, 0xa4, 0xc2, 0xee, 0x36, 0xac, 0x7f, 0x9c, 0xf3, 0xfd, 0x62, - 0x83, 0xf3, 0x99, 0x05, 0x50, 0x9a, 0x51, 0x58, 0x27, 0x34, 0xca, 0x8a, 0xa4, 0xce, 0x89, 0x33, - 0x33, 0xac, 0x9e, 0x4d, 0xad, 0xf3, 0xb3, 0x69, 0xf1, 0x32, 0xd9, 0xf4, 0x07, 0x0b, 0x96, 0x35, - 0xf6, 0xb9, 0x75, 0xb7, 0x07, 0x3d, 0x1d, 0xad, 0xfb, 0x3c, 0x1e, 0x86, 0x32, 0x34, 0x39, 0x71, - 0x8a, 0xaf, 0xce, 0x18, 0xf0, 0x2c, 0x96, 0x08, 0xb8, 0xed, 0xe7, 0x84, 0x6a, 0x97, 0xd5, 0xa8, - 0x3d, 0x0a, 0xc7, 0x61, 0x8e, 0xb9, 0xed, 0x9f, 0x16, 0xa8, 0xb8, 0xab, 0x0c, 0xc8, 0x52, 0xbd, - 0x31, 0xcf, 0x98, 0x1a, 0xef, 0xf6, 0xbf, 0xd6, 0x60, 0x5d, 0xbf, 0xa7, 0x9f, 0xb0, 0x74, 0x12, - 0x06, 0x8c, 0x08, 0x58, 0x3f, 0x64, 0xb2, 0xfa, 0xc8, 0x7e, 0x67, 0xde, 0x6b, 0x1e, 0xbf, 0x92, - 0xfb, 0x73, 0x1f, 0xfa, 0xce, 0xfe, 0xaf, 0xfe, 0xfe, 0xcf, 0xdf, 0x2c, 0xec, 0x91, 0x5d, 0x1c, - 0x2d, 0x4c, 0x6e, 0x95, 0xf3, 0x81, 0x13, 0xf3, 0xe9, 0x31, 0xcb, 0xd7, 0x33, 0x2f, 0x54, 0x2e, - 0x66, 0xd0, 0xc3, 0x0f, 0xa2, 0x4b, 0xb9, 0xbd, 0x8b, 0x6e, 0xf7, 0x89, 0x7b, 0x51, 0xb7, 0xde, - 0x0b, 0xe5, 0x73, 0xdf, 0x22, 0x13, 0xe8, 0xa9, 0x2f, 0x99, 0x8a, 0x31, 0x41, 0xbe, 0x30, 0xcf, - 0x87, 0x99, 0x0f, 0xf4, 0xed, 0xb3, 0xc4, 0xce, 0x4d, 0x84, 0xf1, 0x1e, 0xf9, 0xe2, 0xb9, 0x30, - 0xf0, 0xd8, 0xbf, 0xb4, 0x60, 0xb3, 0x79, 0xee, 0x57, 0x7a, 0xee, 0x37, 0xc5, 0xe5, 0xa7, 0xa4, - 0xe3, 0xa1, 0xef, 0x9b, 0xe4, 0xcb, 0xaf, 0xf4, 0x6d, 0xce, 0xfe, 0x63, 0x58, 0x3d, 0x64, 0xd2, - 0x7c, 0xe1, 0x91, 0xeb, 0x6e, 0x3e, 0x74, 0x71, 0x8b, 0xa1, 0x8b, 0x7b, 0x30, 0x4e, 0xe4, 0xb4, - 0x5f, 0x3e, 0x6a, 0x6b, 0x1f, 0x98, 0xce, 0x3b, 0xe8, 0x72, 0x8b, 0x6c, 0x16, 0x2e, 0xcb, 0xaf, - 0xcb, 0xdf, 0x5b, 0xea, 0x0d, 0x55, 0x1d, 0x15, 0x90, 0xed, 0xca, 0xd3, 0x6d, 0xce, 0x0c, 0xa1, - 0x7f, 0x70, 0xb9, 0x77, 0xb0, 0xb6, 0x56, 0xa4, 0x42, 0xff, 0x2b, 0x17, 0x49, 0x05, 0x7d, 0x7d, - 0x7e, 0xc3, 0xda, 0x43, 0xc4, 0xf5, 0x89, 0x44, 0x05, 0xf1, 0xdc, 0x51, 0xc5, 0x1b, 0x41, 0x9c, - 0xe4, 0x48, 0x14, 0xe2, 0xdf, 0x59, 0xb0, 0x5a, 0x1d, 0x72, 0x90, 0x1b, 0xe5, 0x03, 0xf7, 0xf4, - 0xec, 0xe3, 0xaa, 0xd0, 0xde, 0x41, 0xb4, 0x6e, 0xff, 0xe6, 0x45, 0xd0, 0x52, 0x85, 0x43, 0x61, - 0xfd, 0x4b, 0x3e, 0x35, 0x2b, 0xb2, 0x1a, 0xe7, 0x5c, 0x65, 0x1d, 0x35, 0xe6, 0x69, 0x57, 0x05, - 0xd5, 0x47, 0xa8, 0x8f, 0xfa, 0x87, 0xe7, 0x43, 0xd5, 0xdc, 0x99, 0x27, 0x98, 0xf4, 0x4e, 0xcc, - 0x87, 0xda, 0xcc, 0x3b, 0xc1, 0xf7, 0xd1, 0xb7, 0xf7, 0xf6, 0x66, 0xde, 0x89, 0xa4, 0xa3, 0x99, - 0x3a, 0xc8, 0x1f, 0x2d, 0xe8, 0x56, 0xa6, 0x6d, 0xe4, 0x5d, 0x73, 0x88, 0xd3, 0x33, 0xb8, 0xab, - 0x3a, 0xc7, 0x3d, 0x3c, 0xc7, 0x37, 0xfb, 0x77, 0x2f, 0x78, 0x8e, 0x2c, 0x1e, 0x72, 0xef, 0xa4, - 0x78, 0x55, 0xcc, 0x8a, 0x5c, 0xa9, 0xce, 0xb1, 0x2a, 0xb9, 0x32, 0x67, 0xbc, 0xf5, 0x46, 0x72, - 0x25, 0x55, 0x38, 0x14, 0xd6, 0xc7, 0xb0, 0xac, 0x87, 0x3e, 0x67, 0x76, 0xa4, 0xf2, 0x16, 0xa8, - 0x0c, 0x93, 0x9c, 0xb7, 0xd1, 0xdd, 0x26, 0xd9, 0x28, 0xdc, 0x4d, 0x72, 0xe1, 0x77, 0x0e, 0xfe, - 0xfa, 0x72, 0xdb, 0xfa, 0xdb, 0xcb, 0x6d, 0xeb, 0x1f, 0x2f, 0xb7, 0xad, 0x9f, 0x7c, 0x70, 0xe1, - 0xf1, 0x76, 0x7d, 0x98, 0x3e, 0x58, 0x42, 0x14, 0xef, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0xa1, - 0x08, 0xa7, 0x61, 0x6c, 0x17, 0x00, 0x00, + // 1821 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x59, 0x4f, 0x6f, 0x1c, 0x49, + 0x15, 0x57, 0x7b, 0x3c, 0xf6, 0xf8, 0x8d, 0xff, 0x96, 0xb3, 0xd9, 0xde, 0xd9, 0x60, 0x79, 0x7b, + 0x91, 0x70, 0x0c, 0x74, 0x3b, 0xde, 0x28, 0xcb, 0xf2, 0xe7, 0x60, 0x12, 0xcb, 0x1b, 0x94, 0xec, + 0x86, 0x36, 0xb0, 0x02, 0x09, 0xa2, 0x72, 0x4f, 0x79, 0xdc, 0x49, 0x4f, 0x57, 0xd3, 0x55, 0x3d, + 0x61, 0x64, 0xcd, 0x01, 0xbe, 0x00, 0x07, 0xbe, 0x02, 0x12, 0xe2, 0x84, 0x90, 0xb8, 0x70, 0xe0, + 0x8a, 0x38, 0x22, 0xf1, 0x05, 0x50, 0x84, 0x90, 0x38, 0x70, 0xe0, 0xc2, 0x19, 0xd5, 0xeb, 0xea, + 0xea, 0x3f, 0x1e, 0x27, 0x8e, 0x6c, 0x36, 0x39, 0x4d, 0xbf, 0xf7, 0xea, 0xbd, 0xf7, 0xab, 0xaa, + 0xf7, 0x5e, 0x55, 0xbd, 0x81, 0xf7, 0x93, 0xa7, 0x03, 0x8f, 0x26, 0x61, 0x10, 0x85, 0x2c, 0x96, + 0x5e, 0xca, 0xa3, 0x88, 0x67, 0xe6, 0xd7, 0x4d, 0x52, 0x2e, 0x39, 0x99, 0xd7, 0x64, 0xef, 0xc6, + 0x80, 0xf3, 0x41, 0xc4, 0x94, 0x82, 0x47, 0xe3, 0x98, 0x4b, 0x2a, 0x43, 0x1e, 0x8b, 0x7c, 0x58, + 0xef, 0xc1, 0x20, 0x94, 0x27, 0xd9, 0x91, 0x1b, 0xf0, 0xa1, 0x47, 0xd3, 0x01, 0x4f, 0x52, 0xfe, + 0x04, 0x3f, 0xbe, 0xaa, 0xf5, 0x85, 0xa7, 0xbd, 0x09, 0xcf, 0x70, 0x46, 0xb7, 0x68, 0x94, 0x9c, + 0xd0, 0x5b, 0xde, 0x80, 0xc5, 0x2c, 0xa5, 0x92, 0xf5, 0xb5, 0xb5, 0xdb, 0x4f, 0xbf, 0x26, 0xdc, + 0x90, 0xab, 0xe1, 0x43, 0x1a, 0x9c, 0x84, 0x31, 0x4b, 0xc7, 0xa5, 0xfe, 0x90, 0x49, 0xea, 0x8d, + 0xce, 0x6a, 0xbd, 0xab, 0x11, 0x22, 0x75, 0x94, 0x1d, 0x7b, 0x6c, 0x98, 0xc8, 0x71, 0x2e, 0x74, + 0xee, 0xc1, 0xaa, 0x9f, 0xfb, 0xbd, 0x1f, 0x1f, 0xf3, 0xef, 0x66, 0x2c, 0x1d, 0x13, 0x02, 0xb3, + 0x31, 0x1d, 0x32, 0xdb, 0xda, 0xb4, 0xb6, 0x16, 0x7c, 0xfc, 0x26, 0x37, 0x60, 0x41, 0xfd, 0x8a, + 0x84, 0x06, 0xcc, 0x9e, 0x41, 0x41, 0xc9, 0x70, 0x6e, 0xc3, 0xb5, 0x8a, 0x95, 0x07, 0xa1, 0x90, + 0xb9, 0xa5, 0x9a, 0x96, 0xd5, 0xd4, 0xfa, 0xa5, 0x05, 0x2b, 0x87, 0x4c, 0xde, 0x1f, 0xd2, 0x01, + 0xf3, 0xd9, 0x4f, 0x33, 0x26, 0x24, 0xb1, 0xa1, 0x58, 0x59, 0x3d, 0xbe, 0x20, 0x95, 0xad, 0x80, + 0xc7, 0x92, 0xaa, 0x59, 0x17, 0x08, 0x0c, 0x83, 0x5c, 0x83, 0x76, 0xa8, 0xec, 0xd8, 0x2d, 0x94, + 0xe4, 0x04, 0x59, 0x85, 0x96, 0xa4, 0x03, 0x7b, 0x16, 0x79, 0xea, 0xb3, 0x8e, 0xa8, 0xdd, 0x44, + 0x74, 0x02, 0xe4, 0xfb, 0x71, 0x9f, 0xeb, 0xb9, 0xbc, 0x1c, 0x53, 0x0f, 0x3a, 0x29, 0x1b, 0x85, + 0x22, 0xe4, 0x31, 0x42, 0x6a, 0xf9, 0x86, 0xae, 0x7b, 0x6a, 0x35, 0x3d, 0xdd, 0x87, 0xb7, 0x7c, + 0x26, 0x24, 0x4d, 0x65, 0xc3, 0xd9, 0xab, 0x2f, 0xfe, 0x8f, 0xe1, 0xad, 0x47, 0x29, 0x1f, 0x72, + 0xc9, 0x2e, 0x6b, 0x4a, 0x69, 0x1c, 0x67, 0x51, 0x84, 0x70, 0x3b, 0x3e, 0x7e, 0x3b, 0x07, 0xb0, + 0xbe, 0x77, 0xc4, 0xaf, 0x00, 0xe7, 0x01, 0xac, 0xfb, 0x4c, 0xa6, 0xe3, 0x4b, 0x1b, 0x7a, 0x0c, + 0x6b, 0xda, 0xc6, 0x67, 0x54, 0x06, 0x27, 0xfb, 0x23, 0x16, 0xa3, 0x19, 0x39, 0x4e, 0x8c, 0x19, + 0xf5, 0x4d, 0xee, 0x40, 0x37, 0x2d, 0xc3, 0x12, 0x0d, 0x75, 0x77, 0xaf, 0xb9, 0x45, 0x26, 0x57, + 0x42, 0xd6, 0xaf, 0x0e, 0x74, 0x1e, 0xc3, 0xd2, 0x27, 0x85, 0x37, 0xc5, 0x78, 0x71, 0x1c, 0x93, + 0x1d, 0x58, 0xa7, 0x23, 0x1a, 0x46, 0xf4, 0x28, 0x62, 0x46, 0x4f, 0xd8, 0x33, 0x9b, 0xad, 0xad, + 0x05, 0x7f, 0x9a, 0xc8, 0xb9, 0x0b, 0x2b, 0x8d, 0x7c, 0x21, 0x3b, 0xd0, 0x29, 0x0a, 0x80, 0x6d, + 0x6d, 0xb6, 0xce, 0x05, 0x6a, 0x46, 0x39, 0x1f, 0x42, 0xf7, 0x07, 0x2c, 0x55, 0xb1, 0x86, 0x18, + 0xb7, 0x60, 0xa5, 0x10, 0x69, 0xb6, 0x46, 0xda, 0x64, 0x3b, 0xbf, 0x99, 0x83, 0x6e, 0xc5, 0x24, + 0x79, 0x04, 0xc0, 0x8f, 0x9e, 0xb0, 0x40, 0x3e, 0x64, 0x92, 0xa2, 0x52, 0x77, 0x77, 0xc7, 0xcd, + 0x6b, 0x8d, 0x5b, 0xad, 0x35, 0x6e, 0xf2, 0x74, 0xa0, 0x18, 0xc2, 0x55, 0xb5, 0xc6, 0x1d, 0xdd, + 0x72, 0x3f, 0x35, 0x7a, 0x7e, 0xc5, 0x06, 0xb9, 0x0e, 0x73, 0x42, 0x52, 0x99, 0x09, 0xbd, 0x79, + 0x9a, 0x52, 0x99, 0x34, 0x64, 0x42, 0x94, 0x79, 0x5a, 0x90, 0x6a, 0xfb, 0xc2, 0x80, 0xc7, 0x3a, + 0x55, 0xf1, 0x5b, 0x65, 0x97, 0x90, 0xaa, 0x92, 0x0d, 0xc6, 0x3a, 0x55, 0x0d, 0xad, 0xc6, 0x0b, + 0xc9, 0x12, 0x7b, 0x2e, 0x1f, 0xaf, 0xbe, 0xd5, 0x2e, 0x09, 0x26, 0x3f, 0x63, 0xe1, 0xe0, 0x44, + 0xda, 0xf3, 0xf9, 0x2e, 0x19, 0x06, 0x71, 0x60, 0x91, 0x06, 0x32, 0xa3, 0x91, 0x1e, 0xd0, 0xc1, + 0x01, 0x35, 0x9e, 0xaa, 0x22, 0x29, 0xa3, 0xfd, 0xb1, 0xbd, 0xb0, 0x69, 0x6d, 0xb5, 0xfd, 0x9c, + 0x50, 0xa8, 0x83, 0x2c, 0x4d, 0x59, 0x2c, 0x6d, 0x40, 0x7e, 0x41, 0x2a, 0x49, 0x9f, 0x89, 0x30, + 0x65, 0x7d, 0xbb, 0x9b, 0x4b, 0x34, 0xa9, 0x24, 0x59, 0xd2, 0x57, 0x55, 0xd8, 0x5e, 0xcc, 0x25, + 0x9a, 0x54, 0x28, 0x4d, 0x48, 0xd8, 0x4b, 0x28, 0x2b, 0x19, 0x64, 0x13, 0xba, 0x69, 0x5e, 0x17, + 0x58, 0x7f, 0x4f, 0xda, 0xcb, 0x08, 0xb2, 0xca, 0x22, 0x1b, 0x00, 0xba, 0xc2, 0xab, 0x2d, 0x5e, + 0xc1, 0x01, 0x15, 0x0e, 0xf9, 0x48, 0x59, 0x48, 0xa2, 0x30, 0xa0, 0x87, 0x4c, 0x0a, 0x7b, 0x15, + 0x63, 0xe9, 0xed, 0x32, 0x96, 0x8c, 0x4c, 0xc7, 0x7d, 0x39, 0x56, 0xa9, 0xb2, 0x9f, 0x25, 0x2c, + 0x0d, 0x87, 0x2c, 0x96, 0xc2, 0x5e, 0x6b, 0xa8, 0xee, 0x1b, 0x59, 0xae, 0x5a, 0x19, 0x4b, 0xbe, + 0x09, 0x8b, 0x34, 0xa6, 0xd1, 0x58, 0x84, 0xc2, 0xcf, 0x62, 0x61, 0x13, 0xd4, 0xb5, 0x8d, 0xee, + 0x5e, 0x29, 0x44, 0xe5, 0xda, 0x68, 0x72, 0x07, 0xc0, 0x94, 0x72, 0x61, 0xaf, 0xa3, 0xee, 0x75, + 0xa3, 0x7b, 0xb7, 0x10, 0xa1, 0x66, 0x65, 0x24, 0xf9, 0x09, 0xb4, 0xd5, 0xce, 0x0b, 0xfb, 0x1a, + 0xaa, 0x7c, 0xec, 0x96, 0xc7, 0xad, 0x5b, 0x1c, 0xb7, 0xf8, 0xf1, 0xb8, 0xc8, 0x81, 0x32, 0x84, + 0x0d, 0xa7, 0x38, 0x6e, 0xdd, 0xbb, 0x34, 0xa6, 0xe9, 0xf8, 0x50, 0xb2, 0xc4, 0xcf, 0xcd, 0x3a, + 0x7f, 0x9a, 0x81, 0xe5, 0xfa, 0xac, 0xff, 0x0f, 0xc9, 0x52, 0x84, 0xfe, 0x4c, 0x3d, 0xf4, 0xcd, + 0xc1, 0xd2, 0x6a, 0x1c, 0x2c, 0x65, 0x72, 0xcd, 0x9e, 0x97, 0x5c, 0xed, 0x7a, 0x72, 0x35, 0x42, + 0x62, 0xee, 0x15, 0x42, 0xa2, 0xb9, 0xaf, 0xf3, 0xaf, 0xb2, 0xaf, 0xce, 0x7f, 0x5b, 0xb0, 0x5c, + 0xb7, 0xfe, 0x39, 0x16, 0x9b, 0x62, 0x5d, 0x5b, 0xe7, 0xac, 0xeb, 0xec, 0xd4, 0x75, 0x55, 0x59, + 0xd9, 0xc6, 0xe3, 0x4f, 0x53, 0x8a, 0x1f, 0x60, 0x64, 0x60, 0xb1, 0xe9, 0xf8, 0x9a, 0x52, 0x7c, + 0x1a, 0xc8, 0x70, 0xc4, 0xb0, 0xd6, 0x74, 0x7c, 0x4d, 0xa9, 0x7d, 0x48, 0x94, 0x51, 0xf6, 0x0c, + 0x6b, 0x4c, 0xc7, 0x2f, 0xc8, 0xdc, 0x3b, 0xae, 0x86, 0xd0, 0x15, 0xc6, 0xd0, 0xf5, 0xb2, 0x00, + 0xcd, 0xb2, 0xd0, 0x83, 0x8e, 0x64, 0xc3, 0x24, 0xa2, 0x92, 0x61, 0xa5, 0x59, 0xf0, 0x0d, 0x4d, + 0xbe, 0x02, 0x6b, 0x22, 0xa0, 0x11, 0xbb, 0xc7, 0x9f, 0xc5, 0xf7, 0x18, 0xed, 0x47, 0x61, 0xcc, + 0xb0, 0xe8, 0x2c, 0xf8, 0x67, 0x05, 0x0a, 0x35, 0xde, 0x8d, 0x84, 0xbd, 0x84, 0xe7, 0x93, 0xa6, + 0xc8, 0x17, 0x61, 0x36, 0xe1, 0x7d, 0x61, 0x2f, 0xe3, 0x06, 0xaf, 0x9a, 0x0d, 0x7e, 0xc4, 0xfb, + 0xb8, 0xb1, 0x28, 0x55, 0x6b, 0x9a, 0x84, 0xf1, 0x00, 0xcb, 0x4e, 0xc7, 0xc7, 0x6f, 0xe4, 0xf1, + 0x78, 0x60, 0xaf, 0x6a, 0x1e, 0x8f, 0x07, 0xce, 0x1f, 0x2d, 0x98, 0xd7, 0x9a, 0xaf, 0x79, 0xc7, + 0x4d, 0x49, 0xcf, 0x93, 0x45, 0x97, 0x74, 0xdc, 0x09, 0xac, 0xa9, 0x02, 0x77, 0x1b, 0x77, 0x22, + 0xa7, 0x9d, 0x8f, 0x60, 0xa9, 0x56, 0x71, 0xa6, 0xde, 0x50, 0xcc, 0x7d, 0x73, 0xa6, 0x72, 0xdf, + 0x74, 0xfe, 0x63, 0xc1, 0xfc, 0x77, 0xf8, 0xd1, 0x1b, 0x30, 0xed, 0x0d, 0x80, 0x21, 0x93, 0x69, + 0x18, 0xa8, 0x5b, 0x87, 0x9e, 0x7b, 0x85, 0x43, 0x3e, 0x86, 0x85, 0xf2, 0x94, 0x69, 0x23, 0xb8, + 0xed, 0x8b, 0x81, 0xfb, 0x5e, 0x38, 0x64, 0x7e, 0xa9, 0xec, 0xfc, 0xd3, 0x02, 0xbb, 0x52, 0x05, + 0x0e, 0x13, 0x16, 0xec, 0xc5, 0xfd, 0xc3, 0x1c, 0x1a, 0x85, 0x59, 0x91, 0xb0, 0x40, 0x4f, 0xff, + 0xe1, 0xe5, 0xea, 0x73, 0xc3, 0x8b, 0x8f, 0xa6, 0xc9, 0xa0, 0xb6, 0x2a, 0xdd, 0xdd, 0x4f, 0xaf, + 0xce, 0x09, 0x9a, 0x2d, 0x96, 0xd9, 0xf9, 0x77, 0x0b, 0x56, 0x1a, 0xe5, 0xee, 0x0d, 0x3e, 0x0d, + 0x36, 0x00, 0x44, 0x16, 0x04, 0x4c, 0x88, 0xe3, 0x2c, 0xd2, 0x31, 0x5e, 0xe1, 0x28, 0xbd, 0x63, + 0x1a, 0x46, 0xac, 0x8f, 0x55, 0xad, 0xed, 0x6b, 0x4a, 0x5d, 0x93, 0xc2, 0x38, 0xe0, 0x71, 0x10, + 0x65, 0xa2, 0xa8, 0x6d, 0x6d, 0xbf, 0xc6, 0x53, 0xc1, 0xcf, 0xd2, 0x94, 0xa7, 0x58, 0xdf, 0xda, + 0x7e, 0x4e, 0xa8, 0x0a, 0xf2, 0x84, 0x1f, 0xa9, 0xca, 0x56, 0xaf, 0x20, 0x3a, 0x21, 0x7c, 0x94, + 0x92, 0x0f, 0x00, 0x62, 0x1e, 0x6b, 0x9e, 0x0d, 0x38, 0x76, 0xdd, 0x8c, 0xfd, 0xc4, 0x88, 0xfc, + 0xca, 0x30, 0xb2, 0xad, 0x8e, 0x36, 0x15, 0xbb, 0xc2, 0xee, 0x36, 0xac, 0x3f, 0xcc, 0xf9, 0x7e, + 0x31, 0x80, 0x1c, 0xc0, 0x92, 0xa8, 0xc6, 0x20, 0x96, 0xc2, 0xee, 0xee, 0x7b, 0xd3, 0x8e, 0xac, + 0x5a, 0xb0, 0xfa, 0x75, 0x3d, 0xe7, 0xd7, 0x16, 0x40, 0x89, 0x47, 0x4d, 0x7a, 0x44, 0xa3, 0xac, + 0x28, 0x03, 0x39, 0x71, 0x6e, 0x4e, 0xd6, 0xf3, 0xaf, 0xf5, 0xe2, 0xfc, 0x9b, 0xbd, 0x4c, 0xfe, + 0xfd, 0xde, 0x82, 0x79, 0xbd, 0x08, 0x53, 0x2b, 0xd5, 0x36, 0xac, 0xea, 0x6d, 0xbf, 0xcb, 0xe3, + 0x7e, 0x28, 0x43, 0x13, 0x5c, 0x67, 0xf8, 0x6a, 0x8e, 0x01, 0xcf, 0x62, 0x89, 0x80, 0xdb, 0x7e, + 0x4e, 0xa8, 0x03, 0xa6, 0xba, 0xfd, 0x0f, 0xc2, 0x61, 0x98, 0x63, 0x6e, 0xfb, 0x67, 0x05, 0x2a, + 0x80, 0x54, 0x28, 0x65, 0xa9, 0x1e, 0x98, 0x87, 0x5e, 0x8d, 0xb7, 0xfb, 0xaf, 0x25, 0x58, 0xd6, + 0x2f, 0x90, 0x43, 0x96, 0x8e, 0xc2, 0x80, 0x11, 0x01, 0xcb, 0x07, 0x4c, 0x56, 0x9f, 0x25, 0xef, + 0x4c, 0x7b, 0xff, 0x60, 0x5f, 0xa1, 0x37, 0xf5, 0x69, 0xe4, 0xec, 0xfc, 0xe2, 0x6f, 0xff, 0xf8, + 0xd5, 0xcc, 0x36, 0xd9, 0xc2, 0x66, 0xcc, 0xe8, 0x56, 0xd9, 0x51, 0x39, 0x35, 0x8f, 0xb5, 0x49, + 0xfe, 0x3d, 0xf1, 0x42, 0xe5, 0x62, 0x02, 0xab, 0xf8, 0x84, 0xbc, 0x94, 0xdb, 0x3b, 0xe8, 0x76, + 0x87, 0xb8, 0x17, 0x75, 0xeb, 0x3d, 0x53, 0x3e, 0x77, 0x2c, 0x32, 0x82, 0x55, 0xf5, 0xf6, 0xab, + 0x18, 0x13, 0xe4, 0x0b, 0xd3, 0x7c, 0x98, 0x8e, 0x4a, 0xcf, 0x3e, 0x4f, 0xec, 0xdc, 0x44, 0x18, + 0xef, 0x93, 0xf7, 0x5e, 0x08, 0x03, 0xa7, 0xfd, 0x73, 0x0b, 0xd6, 0x9a, 0xf3, 0x7e, 0xa9, 0xe7, + 0x5e, 0x53, 0x5c, 0x3e, 0xbe, 0x1d, 0x0f, 0x7d, 0xdf, 0x24, 0x5f, 0x7a, 0xa9, 0x6f, 0x33, 0xf7, + 0x1f, 0xc2, 0xe2, 0x01, 0x93, 0xe6, 0x4d, 0x4c, 0xae, 0xbb, 0x79, 0x9b, 0xca, 0x2d, 0xda, 0x54, + 0xee, 0xfe, 0x30, 0x91, 0xe3, 0x5e, 0xf9, 0x0c, 0xa8, 0x3d, 0xc9, 0x9d, 0x77, 0xd0, 0xe5, 0x3a, + 0x59, 0x2b, 0x5c, 0x96, 0xef, 0xf1, 0xdf, 0x59, 0xea, 0xd6, 0x59, 0x6d, 0xae, 0x90, 0x8d, 0xca, + 0x65, 0x77, 0x4a, 0xd7, 0xa5, 0xb7, 0x7f, 0xb9, 0x43, 0x43, 0x5b, 0x2b, 0x42, 0xa1, 0xf7, 0xe5, + 0x8b, 0x84, 0x82, 0xbe, 0x70, 0x7c, 0xdd, 0xda, 0x46, 0xc4, 0xf5, 0x1e, 0x4e, 0x05, 0xf1, 0xd4, + 0xe6, 0xce, 0x6b, 0x41, 0x9c, 0xe4, 0x48, 0x14, 0xe2, 0xdf, 0x5a, 0xb0, 0x58, 0x6d, 0x0b, 0x91, + 0x1b, 0x65, 0x7d, 0x3d, 0xdb, 0x2d, 0xba, 0x2a, 0xb4, 0xb7, 0x11, 0xad, 0xdb, 0xbb, 0x79, 0x11, + 0xb4, 0x54, 0xe1, 0x50, 0x58, 0xff, 0x9c, 0xf7, 0x19, 0x8b, 0xa8, 0xc6, 0xce, 0x60, 0x99, 0x47, + 0x8d, 0x0e, 0xe4, 0x55, 0x41, 0xf5, 0x11, 0xea, 0x83, 0xde, 0xc1, 0x8b, 0xa1, 0x6a, 0xee, 0xc4, + 0x13, 0x4c, 0x7a, 0xa7, 0xe6, 0x69, 0x3b, 0xf1, 0x4e, 0xf1, 0x46, 0xf9, 0xad, 0xed, 0xed, 0x89, + 0x77, 0x2a, 0xe9, 0x60, 0xa2, 0x26, 0xf2, 0x07, 0x0b, 0xba, 0x95, 0xfe, 0x24, 0x79, 0xd7, 0x4c, + 0xe2, 0x6c, 0xd7, 0xf2, 0xaa, 0xe6, 0xb1, 0x87, 0xf3, 0xf8, 0x46, 0xef, 0xce, 0x05, 0xe7, 0x91, + 0xc5, 0x7d, 0xee, 0x9d, 0x16, 0xd7, 0x93, 0x49, 0x11, 0x2b, 0xd5, 0xce, 0x5f, 0x25, 0x56, 0xa6, + 0x34, 0x04, 0x5f, 0x4b, 0xac, 0xa4, 0x0a, 0x87, 0xc2, 0xfa, 0x08, 0xe6, 0x75, 0x9b, 0xec, 0xdc, + 0x8a, 0x54, 0x9e, 0x02, 0x95, 0xf6, 0x9b, 0xf3, 0x36, 0xba, 0x5b, 0x23, 0x2b, 0x85, 0xbb, 0x51, + 0x2e, 0xfc, 0xf6, 0xfe, 0x5f, 0x9e, 0x6f, 0x58, 0x7f, 0x7d, 0xbe, 0x61, 0xfd, 0xfd, 0xf9, 0x86, + 0xf5, 0xa3, 0x0f, 0x2f, 0xfc, 0x87, 0x40, 0xfd, 0xef, 0x87, 0xa3, 0x39, 0x44, 0xf1, 0xc1, 0xff, + 0x02, 0x00, 0x00, 0xff, 0xff, 0x9c, 0x35, 0xff, 0xe4, 0x9e, 0x18, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3496,6 +3567,57 @@ func (m *JobInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *AnalysisRunSpecAndStatus) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AnalysisRunSpecAndStatus) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AnalysisRunSpecAndStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Status != nil { + { + size, err := m.Status.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRollout(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Spec != nil { + { + size, err := m.Spec.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRollout(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *AnalysisRunInfo) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -3520,6 +3642,18 @@ func (m *AnalysisRunInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.SpecAndStatus != nil { + { + size, err := m.SpecAndStatus.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRollout(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + } if len(m.Metrics) > 0 { for iNdEx := len(m.Metrics) - 1; iNdEx >= 0; iNdEx-- { { @@ -4287,6 +4421,26 @@ func (m *JobInfo) Size() (n int) { return n } +func (m *AnalysisRunSpecAndStatus) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Spec != nil { + l = m.Spec.Size() + n += 1 + l + sovRollout(uint64(l)) + } + if m.Status != nil { + l = m.Status.Size() + n += 1 + l + sovRollout(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *AnalysisRunInfo) Size() (n int) { if m == nil { return 0 @@ -4338,6 +4492,10 @@ func (m *AnalysisRunInfo) Size() (n int) { n += 1 + l + sovRollout(uint64(l)) } } + if m.SpecAndStatus != nil { + l = m.SpecAndStatus.Size() + n += 1 + l + sovRollout(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -7736,6 +7894,129 @@ func (m *JobInfo) Unmarshal(dAtA []byte) error { } return nil } +func (m *AnalysisRunSpecAndStatus) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AnalysisRunSpecAndStatus: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AnalysisRunSpecAndStatus: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Spec == nil { + m.Spec = &v1alpha1.AnalysisRunSpec{} + } + if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Status == nil { + m.Status = &v1alpha1.AnalysisRunStatus{} + } + if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRollout(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRollout + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *AnalysisRunInfo) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -8062,6 +8343,42 @@ func (m *AnalysisRunInfo) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpecAndStatus", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SpecAndStatus == nil { + m.SpecAndStatus = &AnalysisRunSpecAndStatus{} + } + if err := m.SpecAndStatus.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRollout(dAtA[iNdEx:]) diff --git a/pkg/apiclient/rollout/rollout.proto b/pkg/apiclient/rollout/rollout.proto index 0d21c5d9d6..7949baddd4 100644 --- a/pkg/apiclient/rollout/rollout.proto +++ b/pkg/apiclient/rollout/rollout.proto @@ -148,8 +148,16 @@ message JobInfo { k8s.io.apimachinery.pkg.apis.meta.v1.Time startedAt = 5; } +message AnalysisRunSpecAndStatus { + github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisRunSpec spec = 1; + github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisRunStatus status = 2; +} + message AnalysisRunInfo { k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta objectMeta = 1; + /* + field type from 161 -170 will be deprecated in future. + */ string icon = 2; int64 revision = 3; string status = 4; @@ -160,6 +168,8 @@ message AnalysisRunInfo { repeated JobInfo jobs = 9; repeated NonJobInfo nonJobInfo = 10; repeated Metrics metrics = 11; + /* The new API changes should use SpecAndStatus field type. */ + AnalysisRunSpecAndStatus specAndStatus = 12; } message NonJobInfo { diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index fb30b4b62e..490c5bcab8 100755 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -598,6 +598,77 @@ }, "title": "AnalysisRunMetadata extra labels to add to the AnalysisRun" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisRunSpec": { + "type": "object", + "properties": { + "metrics": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Metric" + }, + "title": "Metrics contains the list of metrics to query as part of an analysis run\n+patchMergeKey=name\n+patchStrategy=merge" + }, + "args": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Argument" + }, + "title": "Args are the list of arguments used in this run\n+optional\n+patchMergeKey=name\n+patchStrategy=merge" + }, + "terminate": { + "type": "boolean", + "title": "Terminate is used to prematurely stop the run (e.g. rollout completed and analysis is no longer desired)" + }, + "dryRun": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DryRun" + }, + "title": "DryRun object contains the settings for running the analysis in Dry-Run mode\n+patchMergeKey=metricName\n+patchStrategy=merge\n+optional" + }, + "measurementRetention": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MeasurementRetention" + }, + "title": "MeasurementRetention object contains the settings for retaining the number of measurements during the analysis\n+patchMergeKey=metricName\n+patchStrategy=merge\n+optional" + } + }, + "title": "AnalysisRunSpec is the spec for a AnalysisRun resource" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisRunStatus": { + "type": "object", + "properties": { + "phase": { + "type": "string", + "title": "Phase is the status of the analysis run" + }, + "message": { + "type": "string", + "title": "Message is a message explaining current status" + }, + "metricResults": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MetricResult" + }, + "title": "MetricResults contains the metrics collected during the run" + }, + "startedAt": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.Time", + "title": "StartedAt indicates when the analysisRun first started" + }, + "runSummary": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RunSummary", + "title": "RunSummary contains the final results from the metric executions" + }, + "dryRunSummary": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RunSummary", + "title": "DryRunSummary contains the final results from the metric executions in the dry-run mode" + } + }, + "title": "AnalysisRunStatus is the status for a AnalysisRun resource" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisRunStrategy": { "type": "object", "properties": { @@ -710,6 +781,24 @@ }, "title": "AppMeshVirtualService holds information on the virtual service the rollout needs to modify" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Argument": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name is the name of the argument" + }, + "value": { + "type": "string", + "title": "Value is the value of the argument\n+optional" + }, + "valueFrom": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ValueFrom", + "title": "ValueFrom is a reference to where a secret is stored. This field is one of the fields with valueFrom\n+optional" + } + }, + "title": "Argument is an argument to an AnalysisRun" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ArgumentValueFrom": { "type": "object", "properties": { @@ -970,6 +1059,105 @@ }, "title": "CanaryStrategy defines parameters for a Replica Based Canary" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetric": { + "type": "object", + "properties": { + "interval": { + "type": "string" + }, + "metricDataQueries": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetricDataQuery" + } + } + }, + "title": "CloudWatchMetric defines the cloudwatch query to perform canary analysis" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetricDataQuery": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "expression": { + "type": "string" + }, + "label": { + "type": "string" + }, + "metricStat": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetricStat" + }, + "period": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.util.intstr.IntOrString" + }, + "returnData": { + "type": "boolean" + } + }, + "title": "CloudWatchMetricDataQuery defines the cloudwatch query" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetricStat": { + "type": "object", + "properties": { + "metric": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetricStatMetric" + }, + "period": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.util.intstr.IntOrString" + }, + "stat": { + "type": "string" + }, + "unit": { + "type": "string" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetricStatMetric": { + "type": "object", + "properties": { + "dimensions": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetricStatMetricDimension" + } + }, + "metricName": { + "type": "string" + }, + "namespace": { + "type": "string" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetricStatMetricDimension": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DatadogMetric": { + "type": "object", + "properties": { + "interval": { + "type": "string" + }, + "query": { + "type": "string" + }, + "apiVersion": { + "type": "string", + "description": "ApiVersion refers to the Datadog API version being used (default: v1). v1 will eventually be deprecated." + } + } + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DryRun": { "type": "object", "properties": { @@ -989,6 +1177,20 @@ } } }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.GraphiteMetric": { + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Address is the HTTP address and port of the Graphite server" + }, + "query": { + "type": "string", + "title": "Query is a raw Graphite query to perform" + } + }, + "title": "GraphiteMetric defines the Graphite query to perform canary analysis" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.HeaderRoutingMatch": { "type": "object", "properties": { @@ -1002,6 +1204,20 @@ } } }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.InfluxdbMetric": { + "type": "object", + "properties": { + "profile": { + "type": "string", + "title": "Profile is the name of the secret holding InfluxDB account configuration" + }, + "query": { + "type": "string", + "title": "Query is a raw InfluxDB flux query to perform" + } + }, + "title": "InfluxdbMetric defines the InfluxDB Flux query to perform canary analysis" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.IstioDestinationRule": { "type": "object", "properties": { @@ -1070,30 +1286,322 @@ "description": "A list of TCP routes within VirtualService to edit. If omitted, VirtualService must have a single route of this type." } }, - "title": "IstioVirtualService holds information on the virtual service the rollout needs to modify" - }, - "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MangedRoutes": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - } + "title": "IstioVirtualService holds information on the virtual service the rollout needs to modify" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.JobMetric": { + "type": "object", + "properties": { + "metadata": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta" + }, + "spec": { + "$ref": "#/definitions/k8s.io.api.batch.v1.JobSpec" + } + }, + "title": "JobMetric defines a job to run which acts as a metric" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaMetric": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "application": { + "type": "string" + }, + "canaryConfigName": { + "type": "string" + }, + "metricsAccountName": { + "type": "string" + }, + "configurationAccountName": { + "type": "string" + }, + "storageAccountName": { + "type": "string" + }, + "threshold": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaThreshold" + }, + "scopes": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaScope" + } + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaScope": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "controlScope": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ScopeDetail" + }, + "experimentScope": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ScopeDetail" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaThreshold": { + "type": "object", + "properties": { + "pass": { + "type": "string", + "format": "int64" + }, + "marginal": { + "type": "string", + "format": "int64" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MangedRoutes": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Measurement": { + "type": "object", + "properties": { + "phase": { + "type": "string", + "title": "Phase is the status of this single measurement" + }, + "message": { + "type": "string", + "title": "Message contains a message describing current condition (e.g. error messages)" + }, + "startedAt": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.Time", + "title": "StartedAt is the timestamp in which this measurement started to be measured" + }, + "finishedAt": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.Time", + "title": "FinishedAt is the timestamp in which this measurement completed and value was collected" + }, + "value": { + "type": "string", + "title": "Value is the measured value of the metric" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "title": "Metadata stores additional metadata about this metric result, used by the different providers\n(e.g. kayenta run ID, job name)" + }, + "resumeAt": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.Time", + "title": "ResumeAt is the timestamp when the analysisRun should try to resume the measurement" + } + }, + "title": "Measurement is a point in time result value of a single metric, and the time it was measured" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MeasurementRetention": { + "type": "object", + "properties": { + "metricName": { + "type": "string", + "description": "MetricName is the name of the metric on which this retention policy should be applied." + }, + "limit": { + "type": "integer", + "format": "int32", + "description": "Limit is the maximum number of measurements to be retained for this given metric." + } + }, + "description": "MeasurementRetention defines the settings for retaining the number of measurements during the analysis." + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Metric": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name is the name of the metric" + }, + "interval": { + "type": "string", + "title": "Interval defines an interval string (e.g. 30s, 5m, 1h) between each measurement.\nIf omitted, will perform a single measurement" + }, + "initialDelay": { + "type": "string", + "title": "InitialDelay how long the AnalysisRun should wait before starting this metric" + }, + "count": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.util.intstr.IntOrString", + "description": "Count is the number of times to run the measurement. If both interval and count are omitted,\nthe effective count is 1. If only interval is specified, metric runs indefinitely.\nIf count \u003e 1, interval must be specified." + }, + "successCondition": { + "type": "string", + "title": "SuccessCondition is an expression which determines if a measurement is considered successful\nExpression is a goevaluate expression. The keyword `result` is a variable reference to the\nvalue of measurement. Results can be both structured data or primitive.\nExamples:\n result \u003e 10\n (result.requests_made * result.requests_succeeded / 100) \u003e= 90" + }, + "failureCondition": { + "type": "string", + "title": "FailureCondition is an expression which determines if a measurement is considered failed\nIf both success and failure conditions are specified, and the measurement does not fall into\neither condition, the measurement is considered Inconclusive" + }, + "failureLimit": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.util.intstr.IntOrString", + "title": "FailureLimit is the maximum number of times the measurement is allowed to fail, before the\nentire metric is considered Failed (default: 0)" + }, + "inconclusiveLimit": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.util.intstr.IntOrString", + "title": "InconclusiveLimit is the maximum number of times the measurement is allowed to measure\nInconclusive, before the entire metric is considered Inconclusive (default: 0)" + }, + "consecutiveErrorLimit": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.util.intstr.IntOrString", + "title": "ConsecutiveErrorLimit is the maximum number of times the measurement is allowed to error in\nsuccession, before the metric is considered error (default: 4)" + }, + "provider": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MetricProvider", + "title": "Provider configuration to the external system to use to verify the analysis" + } + }, + "title": "Metric defines a metric in which to perform analysis" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MetricProvider": { + "type": "object", + "properties": { + "prometheus": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PrometheusMetric", + "title": "Prometheus specifies the prometheus metric to query" + }, + "kayenta": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaMetric", + "title": "Kayenta specifies a Kayenta metric" + }, + "web": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.WebMetric", + "title": "Web specifies a generic HTTP web metric" + }, + "datadog": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DatadogMetric", + "title": "Datadog specifies a datadog metric to query" + }, + "wavefront": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.WavefrontMetric", + "title": "Wavefront specifies the wavefront metric to query" + }, + "newRelic": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.NewRelicMetric", + "title": "NewRelic specifies the newrelic metric to query" + }, + "job": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.JobMetric", + "title": "Job specifies the job metric run" + }, + "cloudWatch": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CloudWatchMetric", + "title": "CloudWatch specifies the cloudWatch metric to query" + }, + "graphite": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.GraphiteMetric", + "title": "Graphite specifies the Graphite metric to query" + }, + "influxdb": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.InfluxdbMetric", + "title": "Influxdb specifies the influxdb metric to query" + }, + "skywalking": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SkyWalkingMetric", + "title": "SkyWalking specifies the skywalking metric to query" + }, + "plugin": { + "type": "object", + "additionalProperties": { + "type": "string", + "format": "byte" + }, + "title": "+kubebuilder:validation:Schemaless\n+kubebuilder:pruning:PreserveUnknownFields\n+kubebuilder:validation:Type=object\nPlugin specifies the hashicorp go-plugin metric to query" + } + }, + "title": "MetricProvider which external system to use to verify the analysis\nOnly one of the fields in this struct should be non-nil" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MetricResult": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name is the name of the metric" + }, + "phase": { + "type": "string", + "title": "Phase is the overall aggregate status of the metric" + }, + "measurements": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Measurement" + }, + "title": "Measurements holds the most recent measurements collected for the metric" + }, + "message": { + "type": "string", + "title": "Message contains a message describing current condition (e.g. error messages)" + }, + "count": { + "type": "integer", + "format": "int32", + "title": "Count is the number of times the metric was measured without Error\nThis is equal to the sum of Successful, Failed, Inconclusive" + }, + "successful": { + "type": "integer", + "format": "int32", + "title": "Successful is the number of times the metric was measured Successful" + }, + "failed": { + "type": "integer", + "format": "int32", + "title": "Failed is the number of times the metric was measured Failed" + }, + "inconclusive": { + "type": "integer", + "format": "int32", + "title": "Inconclusive is the number of times the metric was measured Inconclusive" + }, + "error": { + "type": "integer", + "format": "int32", + "title": "Error is the number of times an error was encountered during measurement" + }, + "consecutiveError": { + "type": "integer", + "format": "int32", + "title": "ConsecutiveError is the number of times an error was encountered during measurement in succession\nResets to zero when non-errors are encountered" + }, + "dryRun": { + "type": "boolean", + "title": "DryRun indicates whether this metric is running in a dry-run mode or not" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Metadata stores additional metadata about this metric. It is used by different providers to store\nthe final state which gets used while taking measurements. For example, Prometheus uses this field\nto store the final resolved query after substituting the template arguments." + } + }, + "title": "MetricResult contain a list of the most recent measurements for a single metric along with\ncounters on how often the measurement" }, - "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MeasurementRetention": { + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.NewRelicMetric": { "type": "object", "properties": { - "metricName": { + "profile": { "type": "string", - "description": "MetricName is the name of the metric on which this retention policy should be applied." + "title": "Profile is the name of the secret holding NR account configuration" }, - "limit": { - "type": "integer", - "format": "int32", - "description": "Limit is the maximum number of measurements to be retained for this given metric." + "query": { + "type": "string", + "title": "Query is a raw newrelic NRQL query to perform" } }, - "description": "MeasurementRetention defines the settings for retaining the number of measurements during the analysis." + "title": "NewRelicMetric defines the newrelic query to perform canary analysis" }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.NginxTrafficRouting": { "type": "object", @@ -1198,6 +1706,50 @@ }, "title": "PreferredDuringSchedulingIgnoredDuringExecution defines the weight of the anti-affinity injection" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PrometheusAuth": { + "type": "object", + "properties": { + "sigv4": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Sigv4Config", + "title": "+optional" + } + }, + "title": "PrometheusMetric defines the prometheus query to perform canary analysis" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PrometheusMetric": { + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Address is the HTTP address and port of the prometheus server" + }, + "query": { + "type": "string", + "title": "Query is a raw prometheus query to perform" + }, + "authentication": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PrometheusAuth", + "title": "Sigv4 Config is the aws SigV4 configuration to use for SigV4 signing if using Amazon Managed Prometheus\n+optional" + }, + "timeout": { + "type": "string", + "format": "int64", + "title": "Timeout represents the duration within which a prometheus query should complete. It is expressed in seconds.\n+optional" + }, + "insecure": { + "type": "boolean", + "title": "Insecure skips host TLS verification" + }, + "headers": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.WebMetricHeader" + }, + "title": "Headers are optional HTTP headers to use in the request\n+optional\n+patchMergeKey=key\n+patchStrategy=merge" + } + }, + "title": "PrometheusMetric defines the prometheus query to perform canary analysis" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RequiredDuringSchedulingIgnoredDuringExecution": { "type": "object", "title": "RequiredDuringSchedulingIgnoredDuringExecution defines inter-pod scheduling rule to be RequiredDuringSchedulingIgnoredDuringExecution" @@ -1708,6 +2260,37 @@ } } }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RunSummary": { + "type": "object", + "properties": { + "count": { + "type": "integer", + "format": "int32", + "title": "This is equal to the sum of Successful, Failed, Inconclusive" + }, + "successful": { + "type": "integer", + "format": "int32", + "title": "Successful is the number of times the metric was measured Successful" + }, + "failed": { + "type": "integer", + "format": "int32", + "title": "Failed is the number of times the metric was measured Failed" + }, + "inconclusive": { + "type": "integer", + "format": "int32", + "title": "Inconclusive is the number of times the metric was measured Inconclusive" + }, + "error": { + "type": "integer", + "format": "int32", + "title": "Error is the number of times an error was encountered during measurement" + } + }, + "title": "RunSummary contains the final results from the metric executions" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SMITrafficRouting": { "type": "object", "properties": { @@ -1722,6 +2305,40 @@ }, "title": "SMITrafficRouting configuration for TrafficSplit Custom Resource to control traffic routing" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ScopeDetail": { + "type": "object", + "properties": { + "scope": { + "type": "string" + }, + "region": { + "type": "string" + }, + "step": { + "type": "string", + "format": "int64" + }, + "start": { + "type": "string" + }, + "end": { + "type": "string" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SecretKeyRef": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name is the name of the secret" + }, + "key": { + "type": "string", + "description": "Key is the key of the secret to select from." + } + } + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetCanaryScale": { "type": "object", "properties": { @@ -1779,6 +2396,37 @@ } } }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Sigv4Config": { + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Region is the AWS Region to sign the SigV4 Request" + }, + "profile": { + "type": "string", + "title": "Profile is the Credential Profile used to sign the SigV4 Request" + }, + "roleArn": { + "type": "string", + "title": "RoleARN is the IAM role used to sign the SIgV4 Request" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SkyWalkingMetric": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + }, + "interval": { + "type": "string" + } + } + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StickinessConfig": { "type": "object", "properties": { @@ -1882,6 +2530,86 @@ }, "title": "TrafficWeights describes the current status of how traffic has been split" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ValueFrom": { + "type": "object", + "properties": { + "secretKeyRef": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SecretKeyRef", + "title": "Secret is a reference to where a secret is stored. This field is one of the fields with valueFrom\n+optional" + }, + "fieldRef": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.FieldRef", + "title": "FieldRef is a reference to the fields in metadata which we are referencing. This field is one of the fields with\nvalueFrom\n+optional" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.WavefrontMetric": { + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Address is the HTTP address and port of the wavefront server" + }, + "query": { + "type": "string", + "title": "Query is a raw wavefront query to perform" + } + }, + "title": "WavefrontMetric defines the wavefront query to perform canary analysis" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.WebMetric": { + "type": "object", + "properties": { + "method": { + "type": "string", + "title": "Method is the method of the web metric (empty defaults to GET)" + }, + "url": { + "type": "string", + "title": "URL is the address of the web metric" + }, + "headers": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.WebMetricHeader" + }, + "title": "+patchMergeKey=key\n+patchStrategy=merge\nHeaders are optional HTTP headers to use in the request" + }, + "body": { + "type": "string", + "title": "Body is the body of the web metric (must be POST/PUT)" + }, + "timeoutSeconds": { + "type": "string", + "format": "int64", + "title": "TimeoutSeconds is the timeout for the request in seconds (default: 10)" + }, + "jsonPath": { + "type": "string", + "title": "JSONPath is a JSON Path to use as the result variable (default: \"{$}\")" + }, + "insecure": { + "type": "boolean", + "title": "Insecure skips host TLS verification" + }, + "jsonBody": { + "type": "string", + "format": "byte", + "title": "+kubebuilder:validation:Schemaless\n+kubebuilder:pruning:PreserveUnknownFields\n+kubebuilder:validation:Type=object\nJSONBody is the body of the web metric in a json format (method must be POST/PUT)" + } + } + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.WebMetricHeader": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.WeightDestination": { "type": "object", "properties": { @@ -1958,6 +2686,131 @@ } } }, + "k8s.io.api.batch.v1.JobSpec": { + "type": "object", + "properties": { + "parallelism": { + "type": "integer", + "format": "int32", + "title": "Specifies the maximum desired number of pods the job should\nrun at any given time. The actual number of pods running in steady state will\nbe less than this number when ((.spec.completions - .status.successful) \u003c .spec.parallelism),\ni.e. when the work left to do is less than max parallelism.\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/\n+optional" + }, + "completions": { + "type": "integer", + "format": "int32", + "title": "Specifies the desired number of successfully finished pods the\njob should be run with. Setting to nil means that the success of any\npod signals the success of all pods, and allows parallelism to have any positive\nvalue. Setting to 1 means that parallelism is limited to 1 and the success of that\npod signals the success of the job.\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/\n+optional" + }, + "activeDeadlineSeconds": { + "type": "string", + "format": "int64", + "title": "Specifies the duration in seconds relative to the startTime that the job\nmay be continuously active before the system tries to terminate it; value\nmust be positive integer. If a Job is suspended (at creation or through an\nupdate), this timer will effectively be stopped and reset when the Job is\nresumed again.\n+optional" + }, + "podFailurePolicy": { + "$ref": "#/definitions/k8s.io.api.batch.v1.PodFailurePolicy", + "description": "Specifies the policy of handling failed pods. In particular, it allows to\nspecify the set of actions and conditions which need to be\nsatisfied to take the associated action.\nIf empty, the default behaviour applies - the counter of failed pods,\nrepresented by the jobs's .status.failed field, is incremented and it is\nchecked against the backoffLimit. This field cannot be used in combination\nwith restartPolicy=OnFailure.\n\nThis field is alpha-level. To use this field, you must enable the\n`JobPodFailurePolicy` feature gate (disabled by default).\n+optional" + }, + "backoffLimit": { + "type": "integer", + "format": "int32", + "title": "Specifies the number of retries before marking this job failed.\nDefaults to 6\n+optional" + }, + "selector": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector", + "title": "A label query over pods that should match the pod count.\nNormally, the system sets this field for you.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors\n+optional" + }, + "manualSelector": { + "type": "boolean", + "title": "manualSelector controls generation of pod labels and pod selectors.\nLeave `manualSelector` unset unless you are certain what you are doing.\nWhen false or unset, the system pick labels unique to this job\nand appends those labels to the pod template. When true,\nthe user is responsible for picking unique labels and specifying\nthe selector. Failure to pick a unique label may cause this\nand other jobs to not function correctly. However, You may see\n`manualSelector=true` in jobs that were created with the old `extensions/v1beta1`\nAPI.\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector\n+optional" + }, + "template": { + "$ref": "#/definitions/k8s.io.api.core.v1.PodTemplateSpec", + "title": "Describes the pod that will be created when executing a job.\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/" + }, + "ttlSecondsAfterFinished": { + "type": "integer", + "format": "int32", + "title": "ttlSecondsAfterFinished limits the lifetime of a Job that has finished\nexecution (either Complete or Failed). If this field is set,\nttlSecondsAfterFinished after the Job finishes, it is eligible to be\nautomatically deleted. When the Job is being deleted, its lifecycle\nguarantees (e.g. finalizers) will be honored. If this field is unset,\nthe Job won't be automatically deleted. If this field is set to zero,\nthe Job becomes eligible to be deleted immediately after it finishes.\n+optional" + }, + "completionMode": { + "type": "string", + "description": "CompletionMode specifies how Pod completions are tracked. It can be\n`NonIndexed` (default) or `Indexed`.\n\n`NonIndexed` means that the Job is considered complete when there have\nbeen .spec.completions successfully completed Pods. Each Pod completion is\nhomologous to each other.\n\n`Indexed` means that the Pods of a\nJob get an associated completion index from 0 to (.spec.completions - 1),\navailable in the annotation batch.kubernetes.io/job-completion-index.\nThe Job is considered complete when there is one successfully completed Pod\nfor each index.\nWhen value is `Indexed`, .spec.completions must be specified and\n`.spec.parallelism` must be less than or equal to 10^5.\nIn addition, The Pod name takes the form\n`$(job-name)-$(index)-$(random-string)`,\nthe Pod hostname takes the form `$(job-name)-$(index)`.\n\nMore completion modes can be added in the future.\nIf the Job controller observes a mode that it doesn't recognize, which\nis possible during upgrades due to version skew, the controller\nskips updates for the Job.\n+optional" + }, + "suspend": { + "type": "boolean", + "description": "Suspend specifies whether the Job controller should create Pods or not. If\na Job is created with suspend set to true, no Pods are created by the Job\ncontroller. If a Job is suspended after creation (i.e. the flag goes from\nfalse to true), the Job controller will delete all active Pods associated\nwith this Job. Users must design their workload to gracefully handle this.\nSuspending a Job will reset the StartTime field of the Job, effectively\nresetting the ActiveDeadlineSeconds timer too. Defaults to false.\n\n+optional" + } + }, + "description": "JobSpec describes how the job execution will look like." + }, + "k8s.io.api.batch.v1.PodFailurePolicy": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/k8s.io.api.batch.v1.PodFailurePolicyRule" + }, + "title": "A list of pod failure policy rules. The rules are evaluated in order.\nOnce a rule matches a Pod failure, the remaining of the rules are ignored.\nWhen no rule matches the Pod failure, the default handling applies - the\ncounter of pod failures is incremented and it is checked against\nthe backoffLimit. At most 20 elements are allowed.\n+listType=atomic" + } + }, + "description": "PodFailurePolicy describes how failed pods influence the backoffLimit." + }, + "k8s.io.api.batch.v1.PodFailurePolicyOnExitCodesRequirement": { + "type": "object", + "properties": { + "containerName": { + "type": "string", + "title": "Restricts the check for exit codes to the container with the\nspecified name. When null, the rule applies to all containers.\nWhen specified, it should match one the container or initContainer\nnames in the pod template.\n+optional" + }, + "operator": { + "type": "string", + "description": "Represents the relationship between the container exit code(s) and the\nspecified values. Containers completed with success (exit code 0) are\nexcluded from the requirement check. Possible values are:\n- In: the requirement is satisfied if at least one container exit code\n (might be multiple if there are multiple containers not restricted\n by the 'containerName' field) is in the set of specified values.\n- NotIn: the requirement is satisfied if at least one container exit code\n (might be multiple if there are multiple containers not restricted\n by the 'containerName' field) is not in the set of specified values.\nAdditional values are considered to be added in the future. Clients should\nreact to an unknown operator by assuming the requirement is not satisfied." + }, + "values": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "title": "Specifies the set of values. Each returned container exit code (might be\nmultiple in case of multiple containers) is checked against this set of\nvalues with respect to the operator. The list of values must be ordered\nand must not contain duplicates. Value '0' cannot be used for the In operator.\nAt least one element is required. At most 255 elements are allowed.\n+listType=set" + } + }, + "description": "PodFailurePolicyOnExitCodesRequirement describes the requirement for handling\na failed pod based on its container exit codes. In particular, it lookups the\n.state.terminated.exitCode for each app container and init container status,\nrepresented by the .status.containerStatuses and .status.initContainerStatuses\nfields in the Pod status, respectively. Containers completed with success\n(exit code 0) are excluded from the requirement check." + }, + "k8s.io.api.batch.v1.PodFailurePolicyOnPodConditionsPattern": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Specifies the required Pod condition type. To match a pod condition\nit is required that specified type equals the pod condition type." + }, + "status": { + "type": "string", + "description": "Specifies the required Pod condition status. To match a pod condition\nit is required that the specified status equals the pod condition status.\nDefaults to True." + } + }, + "description": "PodFailurePolicyOnPodConditionsPattern describes a pattern for matching\nan actual pod condition type." + }, + "k8s.io.api.batch.v1.PodFailurePolicyRule": { + "type": "object", + "properties": { + "action": { + "type": "string", + "description": "Specifies the action taken on a pod failure when the requirements are satisfied.\nPossible values are:\n- FailJob: indicates that the pod's job is marked as Failed and all\n running pods are terminated.\n- Ignore: indicates that the counter towards the .backoffLimit is not\n incremented and a replacement pod is created.\n- Count: indicates that the pod is handled in the default way - the\n counter towards the .backoffLimit is incremented.\nAdditional values are considered to be added in the future. Clients should\nreact to an unknown action by skipping the rule." + }, + "onExitCodes": { + "$ref": "#/definitions/k8s.io.api.batch.v1.PodFailurePolicyOnExitCodesRequirement", + "title": "Represents the requirement on the container exit codes.\n+optional" + }, + "onPodConditions": { + "type": "array", + "items": { + "$ref": "#/definitions/k8s.io.api.batch.v1.PodFailurePolicyOnPodConditionsPattern" + }, + "title": "Represents the requirement on the pod conditions. The requirement is represented\nas a list of pod condition patterns. The requirement is satisfied if at\nleast one pattern matches an actual pod condition. At most 20 elements are allowed.\n+listType=atomic" + } + }, + "description": "PodFailurePolicyRule describes how a pod failure is handled when the requirements are met.\nOne of OnExitCodes and onPodConditions, but not both, can be used in each rule." + }, "k8s.io.api.core.v1.AWSElasticBlockStoreVolumeSource": { "type": "object", "properties": { @@ -4677,7 +5530,8 @@ "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta" }, "icon": { - "type": "string" + "type": "string", + "description": "field type from 161 -170 will be deprecated in future." }, "revision": { "type": "string", @@ -4719,6 +5573,21 @@ "items": { "$ref": "#/definitions/rollout.Metrics" } + }, + "specAndStatus": { + "$ref": "#/definitions/rollout.AnalysisRunSpecAndStatus", + "description": "The new API changes should use SpecAndStatus field type." + } + } + }, + "rollout.AnalysisRunSpecAndStatus": { + "type": "object", + "properties": { + "spec": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisRunSpec" + }, + "status": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisRunStatus" } } }, diff --git a/pkg/kubectl-argo-rollouts/info/analysisrun_info.go b/pkg/kubectl-argo-rollouts/info/analysisrun_info.go index 9c60ccad87..abf19b1273 100644 --- a/pkg/kubectl-argo-rollouts/info/analysisrun_info.go +++ b/pkg/kubectl-argo-rollouts/info/analysisrun_info.go @@ -26,6 +26,12 @@ func getAnalysisRunInfo(ownerUID types.UID, allAnalysisRuns []*v1alpha1.Analysis UID: run.UID, }, } + + arInfo.SpecAndStatus = &rollout.AnalysisRunSpecAndStatus{ + Spec: &run.Spec, + Status: &run.Status, + } + if run.Spec.Metrics != nil { for _, metric := range run.Spec.Metrics { diff --git a/ui/src/models/rollout/generated/api.ts b/ui/src/models/rollout/generated/api.ts index 151eb4b672..fe2a8eca01 100755 --- a/ui/src/models/rollout/generated/api.ts +++ b/ui/src/models/rollout/generated/api.ts @@ -208,6 +208,86 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRun */ annotations?: { [key: string]: string; }; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunSpec + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunSpec { + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunSpec + */ + metrics?: Array; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunSpec + */ + args?: Array; + /** + * + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunSpec + */ + terminate?: boolean; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunSpec + */ + dryRun?: Array; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunSpec + */ + measurementRetention?: Array; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus + */ + phase?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus + */ + message?: string; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus + */ + metricResults?: Array; + /** + * + * @type {K8sIoApimachineryPkgApisMetaV1Time} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus + */ + startedAt?: K8sIoApimachineryPkgApisMetaV1Time; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus + */ + runSummary?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus + */ + dryRunSummary?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary; +} /** * * @export @@ -348,6 +428,31 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirt */ routes?: Array; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Argument + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Argument { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Argument + */ + name?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Argument + */ + value?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ValueFrom} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Argument + */ + valueFrom?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ValueFrom; +} /** * * @export @@ -668,204 +773,815 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrat canaryMetadata?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PodTemplateMetadata; /** * - * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PodTemplateMetadata} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PodTemplateMetadata} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + stableMetadata?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PodTemplateMetadata; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + scaleDownDelaySeconds?: number; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + scaleDownDelayRevisionLimit?: number; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + abortScaleDownDelaySeconds?: number; + /** + * DynamicStableScale is a traffic routing feature which dynamically scales the stable ReplicaSet to minimize total pods which are running during an update. This is calculated by scaling down the stable as traffic is increased to canary. When disabled (the default behavior) the stable ReplicaSet remains fully scaled to support instantaneous aborts. + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + dynamicStableScale?: boolean; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + pingPong?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + minPodsPerReplicaSet?: number; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetric + */ + interval?: string; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetric + */ + metricDataQueries?: Array; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricDataQuery + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricDataQuery { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricDataQuery + */ + id?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricDataQuery + */ + expression?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricDataQuery + */ + label?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStat} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricDataQuery + */ + metricStat?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStat; + /** + * + * @type {K8sIoApimachineryPkgUtilIntstrIntOrString} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricDataQuery + */ + period?: K8sIoApimachineryPkgUtilIntstrIntOrString; + /** + * + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricDataQuery + */ + returnData?: boolean; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStat + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStat { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStat + */ + metric?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetric; + /** + * + * @type {K8sIoApimachineryPkgUtilIntstrIntOrString} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStat + */ + period?: K8sIoApimachineryPkgUtilIntstrIntOrString; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStat + */ + stat?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStat + */ + unit?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetric { + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetric + */ + dimensions?: Array; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetric + */ + metricName?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetric + */ + namespace?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetricDimension + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetricDimension { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetricDimension + */ + name?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetricStatMetricDimension + */ + value?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DatadogMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DatadogMetric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DatadogMetric + */ + interval?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DatadogMetric + */ + query?: string; + /** + * ApiVersion refers to the Datadog API version being used (default: v1). v1 will eventually be deprecated. + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DatadogMetric + */ + apiVersion?: string; +} +/** + * DryRun defines the settings for running the analysis in Dry-Run mode. + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DryRun + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DryRun { + /** + * Name of the metric which needs to be evaluated in the Dry-Run mode. Wildcard '*' is supported and denotes all the available metrics. + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DryRun + */ + metricName?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef + */ + fieldPath?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1GraphiteMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1GraphiteMetric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1GraphiteMetric + */ + address?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1GraphiteMetric + */ + query?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch + */ + headerName?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch + */ + headerValue?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1InfluxdbMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1InfluxdbMetric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1InfluxdbMetric + */ + profile?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1InfluxdbMetric + */ + query?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule + */ + name?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule + */ + canarySubsetName?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule + */ + stableSubsetName?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting + */ + virtualService?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting + */ + destinationRule?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting + */ + virtualServices?: Array; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + */ + name?: string; + /** + * A list of HTTP routes within VirtualService to edit. If omitted, VirtualService must have a single route of this type. + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + */ + routes?: Array; + /** + * A list of TLS/HTTPS routes within VirtualService to edit. If omitted, VirtualService must have a single route of this type. + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + */ + tlsRoutes?: Array; + /** + * A list of TCP routes within VirtualService to edit. If omitted, VirtualService must have a single route of this type. + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + */ + tcpRoutes?: Array; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1JobMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1JobMetric { + /** + * + * @type {K8sIoApimachineryPkgApisMetaV1ObjectMeta} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1JobMetric + */ + metadata?: K8sIoApimachineryPkgApisMetaV1ObjectMeta; + /** + * + * @type {K8sIoApiBatchV1JobSpec} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1JobMetric + */ + spec?: K8sIoApiBatchV1JobSpec; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric + */ + address?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric + */ + application?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric + */ + canaryConfigName?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric + */ + metricsAccountName?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric + */ + configurationAccountName?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric + */ + storageAccountName?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaThreshold} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric + */ + threshold?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaThreshold; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric + */ + scopes?: Array; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaScope + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaScope { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaScope + */ + name?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaScope + */ + controlScope?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaScope + */ + experimentScope?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaThreshold + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaThreshold { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaThreshold + */ + pass?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaThreshold + */ + marginal?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes + */ + name?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Measurement + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Measurement { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Measurement + */ + phase?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Measurement + */ + message?: string; + /** + * + * @type {K8sIoApimachineryPkgApisMetaV1Time} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Measurement + */ + startedAt?: K8sIoApimachineryPkgApisMetaV1Time; + /** + * + * @type {K8sIoApimachineryPkgApisMetaV1Time} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Measurement + */ + finishedAt?: K8sIoApimachineryPkgApisMetaV1Time; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Measurement + */ + value?: string; + /** + * + * @type {{ [key: string]: string; }} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Measurement + */ + metadata?: { [key: string]: string; }; + /** + * + * @type {K8sIoApimachineryPkgApisMetaV1Time} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Measurement + */ + resumeAt?: K8sIoApimachineryPkgApisMetaV1Time; +} +/** + * MeasurementRetention defines the settings for retaining the number of measurements during the analysis. + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention { + /** + * MetricName is the name of the metric on which this retention policy should be applied. + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention + */ + metricName?: string; + /** + * Limit is the maximum number of measurements to be retained for this given metric. + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention + */ + limit?: number; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + name?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + interval?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + initialDelay?: string; + /** + * + * @type {K8sIoApimachineryPkgUtilIntstrIntOrString} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + count?: K8sIoApimachineryPkgUtilIntstrIntOrString; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + successCondition?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + failureCondition?: string; + /** + * + * @type {K8sIoApimachineryPkgUtilIntstrIntOrString} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + failureLimit?: K8sIoApimachineryPkgUtilIntstrIntOrString; + /** + * + * @type {K8sIoApimachineryPkgUtilIntstrIntOrString} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + inconclusiveLimit?: K8sIoApimachineryPkgUtilIntstrIntOrString; + /** + * + * @type {K8sIoApimachineryPkgUtilIntstrIntOrString} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + consecutiveErrorLimit?: K8sIoApimachineryPkgUtilIntstrIntOrString; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Metric + */ + provider?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider + */ + prometheus?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - stableMetadata?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PodTemplateMetadata; + kayenta?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1KayentaMetric; /** * - * @type {number} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - scaleDownDelaySeconds?: number; + web?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric; /** * - * @type {number} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DatadogMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - scaleDownDelayRevisionLimit?: number; + datadog?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DatadogMetric; /** * - * @type {number} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WavefrontMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - abortScaleDownDelaySeconds?: number; + wavefront?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WavefrontMetric; /** - * DynamicStableScale is a traffic routing feature which dynamically scales the stable ReplicaSet to minimize total pods which are running during an update. This is calculated by scaling down the stable as traffic is increased to canary. When disabled (the default behavior) the stable ReplicaSet remains fully scaled to support instantaneous aborts. - * @type {boolean} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1NewRelicMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - dynamicStableScale?: boolean; + newRelic?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1NewRelicMetric; /** * - * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1JobMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - pingPong?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec; + job?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1JobMetric; /** * - * @type {number} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - minPodsPerReplicaSet?: number; -} -/** - * DryRun defines the settings for running the analysis in Dry-Run mode. - * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DryRun - */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DryRun { + cloudWatch?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CloudWatchMetric; /** - * Name of the metric which needs to be evaluated in the Dry-Run mode. Wildcard '*' is supported and denotes all the available metrics. - * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DryRun + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1GraphiteMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - metricName?: string; -} -/** - * - * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef - */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef { + graphite?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1GraphiteMetric; /** * - * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1InfluxdbMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - fieldPath?: string; -} -/** - * - * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch - */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch { + influxdb?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1InfluxdbMetric; /** * - * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SkyWalkingMetric} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - headerName?: string; + skywalking?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SkyWalkingMetric; /** * - * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch + * @type {{ [key: string]: string; }} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricProvider */ - headerValue?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; + plugin?: { [key: string]: string; }; } /** * * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule { +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult { /** * * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ name?: string; /** * * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ - canarySubsetName?: string; + phase?: string; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult + */ + measurements?: Array; /** * * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ - stableSubsetName?: string; -} -/** - * - * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting - */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting { + message?: string; /** * - * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ - virtualService?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService; + count?: number; /** * - * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ - destinationRule?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule; + successful?: number; /** * - * @type {Array} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ - virtualServices?: Array; -} -/** - * - * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService - */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService { + failed?: number; /** * - * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ - name?: string; + inconclusive?: number; /** - * A list of HTTP routes within VirtualService to edit. If omitted, VirtualService must have a single route of this type. - * @type {Array} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ - routes?: Array; + error?: number; /** - * A list of TLS/HTTPS routes within VirtualService to edit. If omitted, VirtualService must have a single route of this type. - * @type {Array} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ - tlsRoutes?: Array; + consecutiveError?: number; /** - * A list of TCP routes within VirtualService to edit. If omitted, VirtualService must have a single route of this type. - * @type {Array} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + * + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult */ - tcpRoutes?: Array; + dryRun?: boolean; + /** + * Metadata stores additional metadata about this metric. It is used by different providers to store the final state which gets used while taking measurements. For example, Prometheus uses this field to store the final resolved query after substituting the template arguments. + * @type {{ [key: string]: string; }} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MetricResult + */ + metadata?: { [key: string]: string; }; } /** * * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1NewRelicMetric */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes { +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1NewRelicMetric { /** * * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1NewRelicMetric */ - name?: string; -} -/** - * MeasurementRetention defines the settings for retaining the number of measurements during the analysis. - * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention - */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention { + profile?: string; /** - * MetricName is the name of the metric on which this retention policy should be applied. + * * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention - */ - metricName?: string; - /** - * Limit is the maximum number of measurements to be retained for this given metric. - * @type {number} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1NewRelicMetric */ - limit?: number; + query?: string; } /** * @@ -993,6 +1709,62 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PreferredDu */ weight?: number; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusAuth + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusAuth { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Sigv4Config} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusAuth + */ + sigv4?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Sigv4Config; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric + */ + address?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric + */ + query?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusAuth} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric + */ + authentication?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusAuth; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric + */ + timeout?: string; + /** + * + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric + */ + insecure?: boolean; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PrometheusMetric + */ + headers?: Array; +} /** * * @export @@ -1642,46 +2414,139 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTraf /** * * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + */ + method?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + */ + path?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; + /** + * + * @type {{ [key: string]: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; }} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + */ + headers?: { [key: string]: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; }; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary { + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary + */ + count?: number; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary + */ + successful?: number; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary + */ + failed?: number; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary + */ + inconclusive?: number; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RunSummary + */ + error?: number; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SMITrafficRouting + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SMITrafficRouting { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SMITrafficRouting + */ + rootService?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SMITrafficRouting + */ + trafficSplitName?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch { +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail { /** * - * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail */ - method?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; + scope?: string; /** * - * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail */ - path?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; + region?: string; /** * - * @type {{ [key: string]: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; }} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail */ - headers?: { [key: string]: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; }; + step?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail + */ + start?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ScopeDetail + */ + end?: string; } /** * * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SMITrafficRouting + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SecretKeyRef */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SMITrafficRouting { +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SecretKeyRef { /** * * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SMITrafficRouting + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SecretKeyRef */ - rootService?: string; + name?: string; /** - * + * Key is the key of the secret to select from. * @type {string} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SMITrafficRouting + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SecretKeyRef */ - trafficSplitName?: string; + key?: string; } /** * @@ -1752,6 +2617,56 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRo */ percentage?: number; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Sigv4Config + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Sigv4Config { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Sigv4Config + */ + address?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Sigv4Config + */ + profile?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1Sigv4Config + */ + roleArn?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SkyWalkingMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SkyWalkingMetric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SkyWalkingMetric + */ + address?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SkyWalkingMetric + */ + query?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SkyWalkingMetric + */ + interval?: string; +} /** * * @export @@ -1885,6 +2800,118 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TrafficWeig */ verified?: boolean; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ValueFrom + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ValueFrom { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SecretKeyRef} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ValueFrom + */ + secretKeyRef?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SecretKeyRef; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ValueFrom + */ + fieldRef?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WavefrontMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WavefrontMetric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WavefrontMetric + */ + address?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WavefrontMetric + */ + query?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric + */ + method?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric + */ + url?: string; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric + */ + headers?: Array; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric + */ + body?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric + */ + timeoutSeconds?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric + */ + jsonPath?: string; + /** + * + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric + */ + insecure?: boolean; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetric + */ + jsonBody?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetricHeader + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetricHeader { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetricHeader + */ + key?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WebMetricHeader + */ + value?: string; +} /** * * @export @@ -1997,6 +3024,161 @@ export interface GrpcGatewayRuntimeStreamError { */ details?: Array; } +/** + * JobSpec describes how the job execution will look like. + * @export + * @interface K8sIoApiBatchV1JobSpec + */ +export interface K8sIoApiBatchV1JobSpec { + /** + * + * @type {number} + * @memberof K8sIoApiBatchV1JobSpec + */ + parallelism?: number; + /** + * + * @type {number} + * @memberof K8sIoApiBatchV1JobSpec + */ + completions?: number; + /** + * + * @type {string} + * @memberof K8sIoApiBatchV1JobSpec + */ + activeDeadlineSeconds?: string; + /** + * + * @type {K8sIoApiBatchV1PodFailurePolicy} + * @memberof K8sIoApiBatchV1JobSpec + */ + podFailurePolicy?: K8sIoApiBatchV1PodFailurePolicy; + /** + * + * @type {number} + * @memberof K8sIoApiBatchV1JobSpec + */ + backoffLimit?: number; + /** + * + * @type {K8sIoApimachineryPkgApisMetaV1LabelSelector} + * @memberof K8sIoApiBatchV1JobSpec + */ + selector?: K8sIoApimachineryPkgApisMetaV1LabelSelector; + /** + * + * @type {boolean} + * @memberof K8sIoApiBatchV1JobSpec + */ + manualSelector?: boolean; + /** + * + * @type {K8sIoApiCoreV1PodTemplateSpec} + * @memberof K8sIoApiBatchV1JobSpec + */ + template?: K8sIoApiCoreV1PodTemplateSpec; + /** + * + * @type {number} + * @memberof K8sIoApiBatchV1JobSpec + */ + ttlSecondsAfterFinished?: number; + /** + * CompletionMode specifies how Pod completions are tracked. It can be `NonIndexed` (default) or `Indexed`. `NonIndexed` means that the Job is considered complete when there have been .spec.completions successfully completed Pods. Each Pod completion is homologous to each other. `Indexed` means that the Pods of a Job get an associated completion index from 0 to (.spec.completions - 1), available in the annotation batch.kubernetes.io/job-completion-index. The Job is considered complete when there is one successfully completed Pod for each index. When value is `Indexed`, .spec.completions must be specified and `.spec.parallelism` must be less than or equal to 10^5. In addition, The Pod name takes the form `$(job-name)-$(index)-$(random-string)`, the Pod hostname takes the form `$(job-name)-$(index)`. More completion modes can be added in the future. If the Job controller observes a mode that it doesn't recognize, which is possible during upgrades due to version skew, the controller skips updates for the Job. +optional + * @type {string} + * @memberof K8sIoApiBatchV1JobSpec + */ + completionMode?: string; + /** + * Suspend specifies whether the Job controller should create Pods or not. If a Job is created with suspend set to true, no Pods are created by the Job controller. If a Job is suspended after creation (i.e. the flag goes from false to true), the Job controller will delete all active Pods associated with this Job. Users must design their workload to gracefully handle this. Suspending a Job will reset the StartTime field of the Job, effectively resetting the ActiveDeadlineSeconds timer too. Defaults to false. +optional + * @type {boolean} + * @memberof K8sIoApiBatchV1JobSpec + */ + suspend?: boolean; +} +/** + * PodFailurePolicy describes how failed pods influence the backoffLimit. + * @export + * @interface K8sIoApiBatchV1PodFailurePolicy + */ +export interface K8sIoApiBatchV1PodFailurePolicy { + /** + * + * @type {Array} + * @memberof K8sIoApiBatchV1PodFailurePolicy + */ + rules?: Array; +} +/** + * PodFailurePolicyOnExitCodesRequirement describes the requirement for handling a failed pod based on its container exit codes. In particular, it lookups the .state.terminated.exitCode for each app container and init container status, represented by the .status.containerStatuses and .status.initContainerStatuses fields in the Pod status, respectively. Containers completed with success (exit code 0) are excluded from the requirement check. + * @export + * @interface K8sIoApiBatchV1PodFailurePolicyOnExitCodesRequirement + */ +export interface K8sIoApiBatchV1PodFailurePolicyOnExitCodesRequirement { + /** + * + * @type {string} + * @memberof K8sIoApiBatchV1PodFailurePolicyOnExitCodesRequirement + */ + containerName?: string; + /** + * Represents the relationship between the container exit code(s) and the specified values. Containers completed with success (exit code 0) are excluded from the requirement check. Possible values are: - In: the requirement is satisfied if at least one container exit code (might be multiple if there are multiple containers not restricted by the 'containerName' field) is in the set of specified values. - NotIn: the requirement is satisfied if at least one container exit code (might be multiple if there are multiple containers not restricted by the 'containerName' field) is not in the set of specified values. Additional values are considered to be added in the future. Clients should react to an unknown operator by assuming the requirement is not satisfied. + * @type {string} + * @memberof K8sIoApiBatchV1PodFailurePolicyOnExitCodesRequirement + */ + operator?: string; + /** + * + * @type {Array} + * @memberof K8sIoApiBatchV1PodFailurePolicyOnExitCodesRequirement + */ + values?: Array; +} +/** + * PodFailurePolicyOnPodConditionsPattern describes a pattern for matching an actual pod condition type. + * @export + * @interface K8sIoApiBatchV1PodFailurePolicyOnPodConditionsPattern + */ +export interface K8sIoApiBatchV1PodFailurePolicyOnPodConditionsPattern { + /** + * Specifies the required Pod condition type. To match a pod condition it is required that specified type equals the pod condition type. + * @type {string} + * @memberof K8sIoApiBatchV1PodFailurePolicyOnPodConditionsPattern + */ + type?: string; + /** + * Specifies the required Pod condition status. To match a pod condition it is required that the specified status equals the pod condition status. Defaults to True. + * @type {string} + * @memberof K8sIoApiBatchV1PodFailurePolicyOnPodConditionsPattern + */ + status?: string; +} +/** + * PodFailurePolicyRule describes how a pod failure is handled when the requirements are met. One of OnExitCodes and onPodConditions, but not both, can be used in each rule. + * @export + * @interface K8sIoApiBatchV1PodFailurePolicyRule + */ +export interface K8sIoApiBatchV1PodFailurePolicyRule { + /** + * Specifies the action taken on a pod failure when the requirements are satisfied. Possible values are: - FailJob: indicates that the pod's job is marked as Failed and all running pods are terminated. - Ignore: indicates that the counter towards the .backoffLimit is not incremented and a replacement pod is created. - Count: indicates that the pod is handled in the default way - the counter towards the .backoffLimit is incremented. Additional values are considered to be added in the future. Clients should react to an unknown action by skipping the rule. + * @type {string} + * @memberof K8sIoApiBatchV1PodFailurePolicyRule + */ + action?: string; + /** + * + * @type {K8sIoApiBatchV1PodFailurePolicyOnExitCodesRequirement} + * @memberof K8sIoApiBatchV1PodFailurePolicyRule + */ + onExitCodes?: K8sIoApiBatchV1PodFailurePolicyOnExitCodesRequirement; + /** + * + * @type {Array} + * @memberof K8sIoApiBatchV1PodFailurePolicyRule + */ + onPodConditions?: Array; +} /** * Represents a Persistent Disk resource in AWS. An AWS EBS disk must exist before mounting to a container. The disk must also be in the same AWS zone as the kubelet. An AWS EBS disk can only be mounted as read/write once. AWS EBS volumes support ownership management and SELinux relabeling. * @export @@ -5503,7 +6685,7 @@ export interface RolloutAnalysisRunInfo { */ objectMeta?: K8sIoApimachineryPkgApisMetaV1ObjectMeta; /** - * + * field type from 161 -170 will be deprecated in future. * @type {string} * @memberof RolloutAnalysisRunInfo */ @@ -5562,6 +6744,31 @@ export interface RolloutAnalysisRunInfo { * @memberof RolloutAnalysisRunInfo */ metrics?: Array; + /** + * + * @type {RolloutAnalysisRunSpecAndStatus} + * @memberof RolloutAnalysisRunInfo + */ + specAndStatus?: RolloutAnalysisRunSpecAndStatus; +} +/** + * + * @export + * @interface RolloutAnalysisRunSpecAndStatus + */ +export interface RolloutAnalysisRunSpecAndStatus { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunSpec} + * @memberof RolloutAnalysisRunSpecAndStatus + */ + spec?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunSpec; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus} + * @memberof RolloutAnalysisRunSpecAndStatus + */ + status?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStatus; } /** * From 487ccfd77443d1d16a30bf637bfcdaa2fa9afabb Mon Sep 17 00:00:00 2001 From: zachaller Date: Wed, 25 Oct 2023 09:13:06 -0500 Subject: [PATCH 63/90] fix dependency mismatch breaking build due to cherry pick conflict Signed-off-by: zachaller --- go.mod | 22 +++++++++++----------- go.sum | 55 ++++++++++++++++++++++--------------------------------- 2 files changed, 33 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index 955e644fff..2858c544a0 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/antonmedv/expr v1.15.3 github.com/argoproj/notifications-engine v0.4.1-0.20231011160156-2d2d1a75dbee github.com/argoproj/pkg v0.13.6 - github.com/aws/aws-sdk-go-v2 v1.21.1 - github.com/aws/aws-sdk-go-v2/config v1.18.33 + github.com/aws/aws-sdk-go-v2 v1.21.2 + github.com/aws/aws-sdk-go-v2/config v1.19.1 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.27.2 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.21.0 github.com/blang/semver v3.5.1+incompatible @@ -82,16 +82,16 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20220708192748-b73dcb041214 // indirect github.com/aws/aws-sdk-go v1.44.116 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.41 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.42 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.36 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.43 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 // indirect github.com/aws/aws-sdk-go-v2/service/sqs v1.20.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.15.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.23.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 // indirect github.com/aws/smithy-go v1.15.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect diff --git a/go.sum b/go.sum index 6265f6e972..674e220433 100644 --- a/go.sum +++ b/go.sum @@ -105,51 +105,40 @@ github.com/aws/aws-sdk-go v1.44.116 h1:NpLIhcvLWXJZAEwvPj3TDHeqp7DleK6ZUVYyW01WN github.com/aws/aws-sdk-go v1.44.116/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac= -github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= -github.com/aws/aws-sdk-go-v2 v1.21.1 h1:wjHYshtPpYOZm+/mu3NhVgRRc0baM6LJZOmxPZ5Cwzs= -github.com/aws/aws-sdk-go-v2 v1.21.1/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= -github.com/aws/aws-sdk-go-v2/config v1.18.33 h1:JKcw5SFxFW/rpM4mOPjv0VQ11E2kxW13F3exWOy7VZU= -github.com/aws/aws-sdk-go-v2/config v1.18.33/go.mod h1:hXO/l9pgY3K5oZJldamP0pbZHdPqqk+4/maa7DSD3cA= -github.com/aws/aws-sdk-go-v2/credentials v1.13.32/go.mod h1:lL8U3v/Y79YRG69WlAho0OHIKUXCyFvSXaIvfo81sls= -github.com/aws/aws-sdk-go-v2/credentials v1.13.41 h1:dgbKq1tamtboYAKSXWbqL0lKO9rmEzEhbZFh9JQW/Bg= -github.com/aws/aws-sdk-go-v2/credentials v1.13.41/go.mod h1:cc3Fn7DkKbJalPtQnudHGZZ8ml9+hwtbc1CJONsYYqk= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8/go.mod h1:ce7BgLQfYr5hQFdy67oX2svto3ufGtm6oBvmsHScI1Q= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8= +github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= +github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= +github.com/aws/aws-sdk-go-v2/config v1.19.1 h1:oe3vqcGftyk40icfLymhhhNysAwk0NfiwkDi2GTPMXs= +github.com/aws/aws-sdk-go-v2/config v1.19.1/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= +github.com/aws/aws-sdk-go-v2/credentials v1.13.43 h1:LU8vo40zBlo3R7bAvBVy/ku4nxGEyZe9N8MqAeFTzF8= +github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 h1:PIktER+hwIG286DqXyvVENjgLTAwGgoeriLDD5C+YlQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38/go.mod h1:qggunOChCMu9ZF/UkAfhTz25+U2rLVb3ya0Ua6TTfCA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.42 h1:817VqVe6wvwE46xXy6YF5RywvjOX6U2zRQQ6IbQFK0s= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.42/go.mod h1:oDfgXoBBmj+kXnqxDDnIDnC56QBosglKp8ftRCTxR+0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 h1:nFBQlGtkbPzp/NjZLuFxRqmT91rLJkgvsEQs68h962Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32/go.mod h1:0ZXSqrty4FtQ7p8TEuRde/SZm9X05KT18LAUlR40Ln0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.36 h1:7ZApaXzWbo8slc+W5TynuUlB4z66g44h7uqa3/d/BsY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.36/go.mod h1:rwr4WnmFi3RJO0M4dxbJtgi9BPLMpVBMX1nUte5ha9U= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39/go.mod h1:WLAW8PT7+JhjZfLSWe7WEJaJu0GNo0cKc2Zyo003RBs= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 h1:g+qlObJH4Kn4n21g69DjspU0hKTjWtq7naZ9OLCv0ew= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 h1:JRVhO25+r3ar2mKGP7E0LDl8K9/G36gjlqca5iQbaqc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 h1:hze8YsjSh8Wl1rYa1CJpRmXP21BvOBuc76YhW0HsuQ4= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.27.2 h1:HbEoy5QzXicnGgGWF4moCgsbio2xytgVQcs70xD3j3w= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.27.2/go.mod h1:Fc5ZJyxghsjGp1KqbLb2HTJjsJjSv6AXUikHUJYmCHM= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.21.0 h1:lSCNS+ZMztgQWoLz/I27HdYjKlUaKEMWApM0dVOR/y8= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.21.0/go.mod h1:AZv/T0/2rhNBLiY2k109TT6HJ7Z0P8Z+SYvs0jqVkXE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32/go.mod h1:4jwAWKEkCR0anWk5+1RbfSg1R5Gzld7NLiuaq5bTR/Y= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 h1:WWZA/I2K4ptBS1kg0kV1JbBtG/umed0vwHRrmcr9z7k= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37/go.mod h1:vBmDnwWXWxNPFRMmG2m/3MKOe+xEcMDo1tanpaWCcck= github.com/aws/aws-sdk-go-v2/service/sqs v1.20.0 h1:tQoMg8i4nFAB70cJ4wiAYEiZRYo2P6uDmU2D6ys/igo= github.com/aws/aws-sdk-go-v2/service/sqs v1.20.0/go.mod h1:jQhN5f4p3PALMNlUtfb/0wGIFlV7vGtJlPDVfxfNfPY= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.2/go.mod h1:ju+nNXUunfIFamXUIZQiICjnO/TPlOmWcYhZcSy7xaE= -github.com/aws/aws-sdk-go-v2/service/sso v1.15.0 h1:vuGK1vHNP9zx0PfOrtPumbwR2af0ATQ1Z2H6p75AgRQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.15.0/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2/go.mod h1:ubDBBaDFs1GHijSOTi8ljppML15GLG0HxhILtbjNNYQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 h1:8lKOidPkmSmfUtiTgtdXWgaKItCZ/g75/jEk6Ql6GsA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.2/go.mod h1:FQ/DQcOfESELfJi5ED+IPPAjI5xC6nxtSolVVB773jM= -github.com/aws/aws-sdk-go-v2/service/sts v1.23.0 h1:pyvfUqkNLMipdKNAtu7OVbRxUrR2BMaKccIPpk/Hkak= -github.com/aws/aws-sdk-go-v2/service/sts v1.23.0/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 h1:JuPGc7IkOP4AaqcZSIcyqLpFSqBWK32rM9+a1g6u73k= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 h1:HFiiRkf1SdaAmV3/BHOFZ9DjFynPHj8G/UIO1lQS+fk= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3/go.mod h1:a7bHA82fyUXOm+ZSWKU6PIoBxrjSprdLoM8xPYvzYVg= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwFYTCZVhlsSSBvlbU= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= From bd1565c2045472236320b0fe7768ddb36dc6a0ac Mon Sep 17 00:00:00 2001 From: zachaller Date: Wed, 25 Oct 2023 09:14:55 -0500 Subject: [PATCH 64/90] make codegen Signed-off-by: zachaller --- .../rollouts/v1alpha1/openapi_generated.go | 148 ++++++++++++++---- 1 file changed, 117 insertions(+), 31 deletions(-) diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index f91a313c76..01b39597e2 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -52,6 +52,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualService": schema_pkg_apis_rollouts_v1alpha1_AppMeshVirtualService(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Argument": schema_pkg_apis_rollouts_v1alpha1_Argument(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ArgumentValueFrom": schema_pkg_apis_rollouts_v1alpha1_ArgumentValueFrom(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication": schema_pkg_apis_rollouts_v1alpha1_Authentication(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AwsResourceRef": schema_pkg_apis_rollouts_v1alpha1_AwsResourceRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.BlueGreenStatus": schema_pkg_apis_rollouts_v1alpha1_BlueGreenStatus(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.BlueGreenStrategy": schema_pkg_apis_rollouts_v1alpha1_BlueGreenStrategy(ref), @@ -93,12 +94,12 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MetricResult": schema_pkg_apis_rollouts_v1alpha1_MetricResult(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NewRelicMetric": schema_pkg_apis_rollouts_v1alpha1_NewRelicMetric(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NginxTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_NginxTrafficRouting(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.OAuth2Config": schema_pkg_apis_rollouts_v1alpha1_OAuth2Config(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ObjectRef": schema_pkg_apis_rollouts_v1alpha1_ObjectRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PauseCondition": schema_pkg_apis_rollouts_v1alpha1_PauseCondition(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PingPongSpec": schema_pkg_apis_rollouts_v1alpha1_PingPongSpec(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PodTemplateMetadata": schema_pkg_apis_rollouts_v1alpha1_PodTemplateMetadata(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PreferredDuringSchedulingIgnoredDuringExecution": schema_pkg_apis_rollouts_v1alpha1_PreferredDuringSchedulingIgnoredDuringExecution(ref), - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusAuth": schema_pkg_apis_rollouts_v1alpha1_PrometheusAuth(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusMetric": schema_pkg_apis_rollouts_v1alpha1_PrometheusMetric(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RequiredDuringSchedulingIgnoredDuringExecution": schema_pkg_apis_rollouts_v1alpha1_RequiredDuringSchedulingIgnoredDuringExecution(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RollbackWindowSpec": schema_pkg_apis_rollouts_v1alpha1_RollbackWindowSpec(ref), @@ -1099,6 +1100,35 @@ func schema_pkg_apis_rollouts_v1alpha1_ArgumentValueFrom(ref common.ReferenceCal } } +func schema_pkg_apis_rollouts_v1alpha1_Authentication(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Authentication method", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "sigv4": { + SchemaProps: spec.SchemaProps{ + Description: "Sigv4 Config is the aws SigV4 configuration to use for SigV4 signing if using Amazon Managed Prometheus", + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Sigv4Config"), + }, + }, + "oauth2": { + SchemaProps: spec.SchemaProps{ + Description: "OAuth2 config", + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.OAuth2Config"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.OAuth2Config", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Sigv4Config"}, + } +} + func schema_pkg_apis_rollouts_v1alpha1_AwsResourceRef(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -1805,16 +1835,39 @@ func schema_pkg_apis_rollouts_v1alpha1_DatadogMetric(ref common.ReferenceCallbac Type: []string{"object"}, Properties: map[string]spec.Schema{ "interval": { + SchemaProps: spec.SchemaProps{ + Description: "Interval refers to the Interval time window in Datadog (default: 5m). Not to be confused with the polling rate for the metric.", + Type: []string{"string"}, + Format: "", + }, + }, + "query": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "", }, }, - "query": { + "queries": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Queries is a map of query_name_as_key: query. You can then use query_name_as_key inside Formula.Used for v2", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "formula": { + SchemaProps: spec.SchemaProps{ + Description: "Formula refers to the Formula made up of the queries. Only useful with Queries. Used for v2", + Type: []string{"string"}, + Format: "", }, }, "apiVersion": { @@ -1825,7 +1878,6 @@ func schema_pkg_apis_rollouts_v1alpha1_DatadogMetric(ref common.ReferenceCallbac }, }, }, - Required: []string{"query"}, }, }, } @@ -3242,6 +3294,54 @@ func schema_pkg_apis_rollouts_v1alpha1_NginxTrafficRouting(ref common.ReferenceC } } +func schema_pkg_apis_rollouts_v1alpha1_OAuth2Config(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "tokenUrl": { + SchemaProps: spec.SchemaProps{ + Description: "OAuth2 provider token URL", + Type: []string{"string"}, + Format: "", + }, + }, + "clientId": { + SchemaProps: spec.SchemaProps{ + Description: "OAuth2 client ID", + Type: []string{"string"}, + Format: "", + }, + }, + "clientSecret": { + SchemaProps: spec.SchemaProps{ + Description: "OAuth2 client secret", + Type: []string{"string"}, + Format: "", + }, + }, + "scopes": { + SchemaProps: spec.SchemaProps{ + Description: "OAuth2 scopes", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_ObjectRef(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3402,27 +3502,6 @@ func schema_pkg_apis_rollouts_v1alpha1_PreferredDuringSchedulingIgnoredDuringExe } } -func schema_pkg_apis_rollouts_v1alpha1_PrometheusAuth(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PrometheusMetric defines the prometheus query to perform canary analysis", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "sigv4": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Sigv4Config"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Sigv4Config"}, - } -} - func schema_pkg_apis_rollouts_v1alpha1_PrometheusMetric(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3446,9 +3525,9 @@ func schema_pkg_apis_rollouts_v1alpha1_PrometheusMetric(ref common.ReferenceCall }, "authentication": { SchemaProps: spec.SchemaProps{ - Description: "Sigv4 Config is the aws SigV4 configuration to use for SigV4 signing if using Amazon Managed Prometheus", + Description: "Authentication details", Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusAuth"), + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication"), }, }, "timeout": { @@ -3489,7 +3568,7 @@ func schema_pkg_apis_rollouts_v1alpha1_PrometheusMetric(ref common.ReferenceCall }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusAuth", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetricHeader"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetricHeader"}, } } @@ -5458,12 +5537,19 @@ func schema_pkg_apis_rollouts_v1alpha1_WebMetric(ref common.ReferenceCallback) c Format: "byte", }, }, + "authentication": { + SchemaProps: spec.SchemaProps{ + Description: "Authentication details", + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication"), + }, + }, }, Required: []string{"url"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetricHeader"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetricHeader"}, } } From e47e130299b05fd980fa85470bca9d3a71c57ed0 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Fri, 29 Sep 2023 15:01:46 -0700 Subject: [PATCH 65/90] fix: prevent hot loop when fully promoted rollout is aborted (#3064) * fix: prevent hot loop when fully promoted rollout is aborted Signed-off-by: Jesse Suen * test: change expectations of abort tests Signed-off-by: Jesse Suen --------- Signed-off-by: Jesse Suen --- experiments/controller_test.go | 6 ++-- experiments/experiment_test.go | 2 +- experiments/replicaset_test.go | 4 +-- rollout/analysis_test.go | 64 +++++++++++++++++----------------- rollout/bluegreen_test.go | 16 ++++----- rollout/canary_test.go | 51 +++++++++++++-------------- rollout/controller.go | 5 +++ rollout/controller_test.go | 4 +-- rollout/experiment_test.go | 14 ++++---- rollout/service_test.go | 4 +-- test/e2e/istio_test.go | 4 +-- 11 files changed, 89 insertions(+), 85 deletions(-) diff --git a/experiments/controller_test.go b/experiments/controller_test.go index 1e7eb14f13..9babd92d21 100644 --- a/experiments/controller_test.go +++ b/experiments/controller_test.go @@ -805,7 +805,7 @@ func TestAddInvalidSpec(t *testing.T) { "status":{ } }`, nil, cond) - assert.Equal(t, expectedPatch, patch) + assert.JSONEq(t, expectedPatch, patch) } func TestKeepInvalidSpec(t *testing.T) { @@ -852,7 +852,7 @@ func TestUpdateInvalidSpec(t *testing.T) { "status":{ } }`, nil, cond) - assert.Equal(t, expectedPatch, patch) + assert.JSONEq(t, expectedPatch, patch) } @@ -892,7 +892,7 @@ func TestRemoveInvalidSpec(t *testing.T) { "status":{ } }`, templateStatus, cond) - assert.Equal(t, expectedPatch, patch) + assert.JSONEq(t, expectedPatch, patch) } func TestRun(t *testing.T) { diff --git a/experiments/experiment_test.go b/experiments/experiment_test.go index 0853a3b361..ae8df335af 100644 --- a/experiments/experiment_test.go +++ b/experiments/experiment_test.go @@ -282,7 +282,7 @@ func TestSuccessAfterDurationPasses(t *testing.T) { "phase": "Successful" } }`, templateStatuses, cond) - assert.Equal(t, expectedPatch, patch) + assert.JSONEq(t, expectedPatch, patch) } // TestDontRequeueWithoutDuration verifies we don't requeue if an experiment does not have diff --git a/experiments/replicaset_test.go b/experiments/replicaset_test.go index e4d1cdf231..030414f2df 100644 --- a/experiments/replicaset_test.go +++ b/experiments/replicaset_test.go @@ -42,7 +42,7 @@ func TestCreateMultipleRS(t *testing.T) { "status":{ } }`, templateStatus, cond) - assert.Equal(t, expectedPatch, patch) + assert.JSONEq(t, expectedPatch, patch) } func TestCreateMissingRS(t *testing.T) { @@ -72,7 +72,7 @@ func TestCreateMissingRS(t *testing.T) { generateTemplatesStatus("bar", 0, 0, v1alpha1.TemplateStatusProgressing, now()), generateTemplatesStatus("baz", 0, 0, v1alpha1.TemplateStatusProgressing, now()), } - assert.Equal(t, calculatePatch(e, expectedPatch, templateStatuses, cond), patch) + assert.JSONEq(t, calculatePatch(e, expectedPatch, templateStatuses, cond), patch) } func TestTemplateHasMultipleRS(t *testing.T) { diff --git a/rollout/analysis_test.go b/rollout/analysis_test.go index f0313d7ea0..de9a5e1db3 100644 --- a/rollout/analysis_test.go +++ b/rollout/analysis_test.go @@ -180,7 +180,7 @@ func TestCreateBackgroundAnalysisRun(t *testing.T) { } } }` - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) } func TestCreateBackgroundAnalysisRunWithTemplates(t *testing.T) { @@ -241,7 +241,7 @@ func TestCreateBackgroundAnalysisRunWithTemplates(t *testing.T) { } } }` - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) } func TestCreateBackgroundAnalysisRunWithClusterTemplates(t *testing.T) { @@ -303,7 +303,7 @@ func TestCreateBackgroundAnalysisRunWithClusterTemplates(t *testing.T) { } } }` - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) } func TestInvalidSpecMissingClusterTemplatesBackgroundAnalysis(t *testing.T) { @@ -339,7 +339,7 @@ func TestInvalidSpecMissingClusterTemplatesBackgroundAnalysis(t *testing.T) { expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, progressingCond, string(invalidSpecBytes), strings.ReplaceAll(errmsg, "\"", "\\\"")) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r, expectedPatch), patch) } func TestCreateBackgroundAnalysisRunWithClusterTemplatesAndTemplate(t *testing.T) { @@ -416,7 +416,7 @@ func TestCreateBackgroundAnalysisRunWithClusterTemplatesAndTemplate(t *testing.T } } }` - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) } // TestCreateAnalysisRunWithCollision ensures we will create an new analysis run with a new name @@ -487,7 +487,7 @@ func TestCreateAnalysisRunWithCollision(t *testing.T) { } } }` - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedAR.Name)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedAR.Name)), patch) } // TestCreateAnalysisRunWithCollisionAndSemanticEquality will ensure we do not create an extra @@ -550,7 +550,7 @@ func TestCreateAnalysisRunWithCollisionAndSemanticEquality(t *testing.T) { } } }` - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ar.Name)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ar.Name)), patch) } func TestCreateAnalysisRunOnAnalysisStep(t *testing.T) { @@ -611,7 +611,7 @@ func TestCreateAnalysisRunOnAnalysisStep(t *testing.T) { } } }` - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) } func TestFailCreateStepAnalysisRunIfInvalidTemplateRef(t *testing.T) { @@ -653,7 +653,7 @@ func TestFailCreateStepAnalysisRunIfInvalidTemplateRef(t *testing.T) { expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, progressingCond, string(invalidSpecBytes), strings.ReplaceAll(errmsg, "\"", "\\\"")) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r, expectedPatch), patch) } func TestFailCreateBackgroundAnalysisRunIfInvalidTemplateRef(t *testing.T) { @@ -698,7 +698,7 @@ func TestFailCreateBackgroundAnalysisRunIfInvalidTemplateRef(t *testing.T) { expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, progressingCond, string(invalidSpecBytes), strings.ReplaceAll(errmsg, "\"", "\\\"")) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r, expectedPatch), patch) } func TestFailCreateBackgroundAnalysisRunIfMetricRepeated(t *testing.T) { @@ -745,7 +745,7 @@ func TestFailCreateBackgroundAnalysisRunIfMetricRepeated(t *testing.T) { expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, progressingCond, string(invalidSpecBytes), strings.ReplaceAll(errmsg, "\"", "\\\"")) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r, expectedPatch), patch) } func TestDoNothingWithAnalysisRunsWhileBackgroundAnalysisRunRunning(t *testing.T) { @@ -798,7 +798,7 @@ func TestDoNothingWithAnalysisRunsWhileBackgroundAnalysisRunRunning(t *testing.T patchIndex := f.expectPatchRolloutAction(r2) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) } func TestDoNothingWhileStepBasedAnalysisRunRunning(t *testing.T) { @@ -847,7 +847,7 @@ func TestDoNothingWhileStepBasedAnalysisRunRunning(t *testing.T) { patchIndex := f.expectPatchRolloutAction(r2) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) } func TestCancelOlderAnalysisRuns(t *testing.T) { @@ -915,7 +915,7 @@ func TestCancelOlderAnalysisRuns(t *testing.T) { } } }` - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestDeleteAnalysisRunsWithNoMatchingRS(t *testing.T) { @@ -971,7 +971,7 @@ func TestDeleteAnalysisRunsWithNoMatchingRS(t *testing.T) { deletedAr := f.getDeletedAnalysisRun(deletedIndex) assert.Equal(t, deletedAr, arWithDiffPodHash.Name) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) } func TestDeleteAnalysisRunsAfterRSDelete(t *testing.T) { @@ -1083,7 +1083,7 @@ func TestIncrementStepAfterSuccessfulAnalysisRun(t *testing.T) { }` condition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition)), patch) } func TestPausedOnInconclusiveBackgroundAnalysisRun(t *testing.T) { @@ -1152,7 +1152,7 @@ func TestPausedOnInconclusiveBackgroundAnalysisRun(t *testing.T) { }` condition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, v1alpha1.PauseReasonInconclusiveAnalysis, now, v1alpha1.PauseReasonInconclusiveAnalysis)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, v1alpha1.PauseReasonInconclusiveAnalysis, now, v1alpha1.PauseReasonInconclusiveAnalysis)), patch) } func TestPausedStepAfterInconclusiveAnalysisRun(t *testing.T) { @@ -1215,7 +1215,7 @@ func TestPausedStepAfterInconclusiveAnalysisRun(t *testing.T) { } }` condition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, v1alpha1.PauseReasonInconclusiveAnalysis, now, v1alpha1.PauseReasonInconclusiveAnalysis)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, v1alpha1.PauseReasonInconclusiveAnalysis, now, v1alpha1.PauseReasonInconclusiveAnalysis)), patch) } func TestErrorConditionAfterErrorAnalysisRunStep(t *testing.T) { @@ -1282,7 +1282,7 @@ func TestErrorConditionAfterErrorAnalysisRunStep(t *testing.T) { errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 2) + ": " + ar.Status.Message condition := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, errmsg, false) expectedPatch = fmt.Sprintf(expectedPatch, condition, now, errmsg) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestErrorConditionAfterErrorAnalysisRunBackground(t *testing.T) { @@ -1358,7 +1358,7 @@ func TestErrorConditionAfterErrorAnalysisRunBackground(t *testing.T) { condition := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "", false) now := timeutil.Now().UTC().Format(time.RFC3339) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, now, errmsg)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, now, errmsg)), patch) } func TestCancelAnalysisRunsWhenAborted(t *testing.T) { @@ -1419,7 +1419,7 @@ func TestCancelAnalysisRunsWhenAborted(t *testing.T) { }` errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 2) now := timeutil.Now().UTC().Format(time.RFC3339) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, newConditions, now, errmsg)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, newConditions, now, errmsg)), patch) } func TestCancelBackgroundAnalysisRunWhenRolloutIsCompleted(t *testing.T) { @@ -1521,7 +1521,7 @@ func TestDoNotCreateBackgroundAnalysisRunAfterInconclusiveRun(t *testing.T) { f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) } func TestDoNotCreateBackgroundAnalysisRunOnNewCanaryRollout(t *testing.T) { @@ -1647,7 +1647,7 @@ func TestCreatePrePromotionAnalysisRun(t *testing.T) { } } }`, ar.Name) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } // TestDoNotCreatePrePromotionAnalysisProgressedRollout ensures a pre-promotion analysis is not created after a Rollout @@ -1771,7 +1771,7 @@ func TestDoNotCreatePrePromotionAnalysisRunOnNotReadyReplicaSet(t *testing.T) { f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchRolloutIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) } func TestRolloutPrePromotionAnalysisBecomesInconclusive(t *testing.T) { @@ -1841,7 +1841,7 @@ func TestRolloutPrePromotionAnalysisBecomesInconclusive(t *testing.T) { } } }`, now, now) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestRolloutPrePromotionAnalysisSwitchServiceAfterSuccess(t *testing.T) { @@ -1905,7 +1905,7 @@ func TestRolloutPrePromotionAnalysisSwitchServiceAfterSuccess(t *testing.T) { "message": null } }`, rs2PodHash, rs2PodHash, rs2PodHash) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestRolloutPrePromotionAnalysisHonorAutoPromotionSeconds(t *testing.T) { @@ -1971,7 +1971,7 @@ func TestRolloutPrePromotionAnalysisHonorAutoPromotionSeconds(t *testing.T) { "message": null } }`, rs2PodHash, rs2PodHash, rs2PodHash) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestRolloutPrePromotionAnalysisDoNothingOnInconclusiveAnalysis(t *testing.T) { @@ -2096,7 +2096,7 @@ func TestAbortRolloutOnErrorPrePromotionAnalysis(t *testing.T) { now := timeutil.MetaNow().UTC().Format(time.RFC3339) progressingFalseAborted, _ := newProgressingCondition(conditions.RolloutAbortedReason, r2, "") newConditions := updateConditionsPatch(*r2, progressingFalseAborted) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, newConditions, conditions.RolloutAbortedReason, progressingFalseAborted.Message)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, newConditions, conditions.RolloutAbortedReason, progressingFalseAborted.Message)), patch) } func TestCreatePostPromotionAnalysisRun(t *testing.T) { @@ -2143,7 +2143,7 @@ func TestCreatePostPromotionAnalysisRun(t *testing.T) { } } }`, ar.Name) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestRolloutPostPromotionAnalysisSuccess(t *testing.T) { @@ -2199,7 +2199,7 @@ func TestRolloutPostPromotionAnalysisSuccess(t *testing.T) { "message": null } }`, rs2PodHash) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } // TestPostPromotionAnalysisRunHandleInconclusive ensures that the Rollout does not scale down a old ReplicaSet if @@ -2264,7 +2264,7 @@ func TestPostPromotionAnalysisRunHandleInconclusive(t *testing.T) { "message": "InconclusiveAnalysisRun" } }`) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestAbortRolloutOnErrorPostPromotionAnalysis(t *testing.T) { @@ -2334,7 +2334,7 @@ func TestAbortRolloutOnErrorPostPromotionAnalysis(t *testing.T) { now := timeutil.MetaNow().UTC().Format(time.RFC3339) progressingFalseAborted, _ := newProgressingCondition(conditions.RolloutAbortedReason, r2, "") newConditions := updateConditionsPatch(*r2, progressingFalseAborted) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, newConditions, conditions.RolloutAbortedReason, progressingFalseAborted.Message)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, newConditions, conditions.RolloutAbortedReason, progressingFalseAborted.Message)), patch) } func TestCreateAnalysisRunWithCustomAnalysisRunMetadataAndROCopyLabels(t *testing.T) { diff --git a/rollout/bluegreen_test.go b/rollout/bluegreen_test.go index 42b521a565..cff894e8ca 100644 --- a/rollout/bluegreen_test.go +++ b/rollout/bluegreen_test.go @@ -290,7 +290,7 @@ func TestBlueGreenHandlePause(t *testing.T) { f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchRolloutIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) }) t.Run("AddPause", func(t *testing.T) { f := newFixture(t) @@ -334,7 +334,7 @@ func TestBlueGreenHandlePause(t *testing.T) { } }` now := timeutil.Now().UTC().Format(time.RFC3339) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, v1alpha1.PauseReasonBlueGreenPause, now)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, v1alpha1.PauseReasonBlueGreenPause, now)), patch) }) @@ -376,7 +376,7 @@ func TestBlueGreenHandlePause(t *testing.T) { } }` addedConditions := generateConditionsPatchWithPause(true, conditions.RolloutPausedReason, rs2, true, "", true, false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, addedConditions)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, addedConditions)), patch) }) t.Run("NoActionsAfterPausing", func(t *testing.T) { @@ -417,7 +417,7 @@ func TestBlueGreenHandlePause(t *testing.T) { patchIndex := f.expectPatchRolloutActionWithPatch(r2, OnlyObservedGenerationPatch) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) }) t.Run("NoActionsAfterPausedOnInconclusiveRun", func(t *testing.T) { @@ -468,7 +468,7 @@ func TestBlueGreenHandlePause(t *testing.T) { patchIndex := f.expectPatchRolloutActionWithPatch(r2, OnlyObservedGenerationPatch) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) }) t.Run("NoAutoPromoteBeforeDelayTimePasses", func(t *testing.T) { @@ -509,7 +509,7 @@ func TestBlueGreenHandlePause(t *testing.T) { patchIndex := f.expectPatchRolloutActionWithPatch(r2, OnlyObservedGenerationPatch) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) }) t.Run("AutoPromoteAfterDelayTimePasses", func(t *testing.T) { @@ -813,7 +813,7 @@ func TestBlueGreenHandlePause(t *testing.T) { "conditions": %s } }` - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedUnpausePatch, unpauseConditions)), unpausePatch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedUnpausePatch, unpauseConditions)), unpausePatch) generatedConditions := generateConditionsPatchWithCompleted(true, conditions.ReplicaSetUpdatedReason, rs2, true, "", true) expected2ndPatchWithoutSubs := `{ @@ -1453,7 +1453,7 @@ func TestBlueGreenAbort(t *testing.T) { } }`, rs1PodHash, expectedConditions, rs1PodHash, conditions.RolloutAbortedReason, fmt.Sprintf(conditions.RolloutAbortedMessage, 2)) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestBlueGreenHandlePauseAutoPromoteWithConditions(t *testing.T) { diff --git a/rollout/canary_test.go b/rollout/canary_test.go index 9f66cf1078..1d8af7d80e 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -182,7 +182,7 @@ func TestCanaryRolloutEnterPauseState(t *testing.T) { now := timeutil.MetaNow().UTC().Format(time.RFC3339) expectedPatchWithoutObservedGen := fmt.Sprintf(expectedPatchTemplate, v1alpha1.PauseReasonCanaryPauseStep, now, conditions, v1alpha1.PauseReasonCanaryPauseStep) expectedPatch := calculatePatch(r2, expectedPatchWithoutObservedGen) - assert.Equal(t, expectedPatch, patch) + assert.JSONEq(t, expectedPatch, patch) } func TestCanaryRolloutNoProgressWhilePaused(t *testing.T) { @@ -257,7 +257,7 @@ func TestCanaryRolloutUpdatePauseConditionWhilePaused(t *testing.T) { f.run(getKey(r2, t)) patch := f.getPatchedRollout(addPausedConditionPatch) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) } func TestCanaryRolloutResetProgressDeadlineOnRetry(t *testing.T) { @@ -300,7 +300,7 @@ func TestCanaryRolloutResetProgressDeadlineOnRetry(t *testing.T) { "message": "more replicas need to be updated" } }`, retryCondition) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestCanaryRolloutIncrementStepAfterUnPaused(t *testing.T) { @@ -342,7 +342,7 @@ func TestCanaryRolloutIncrementStepAfterUnPaused(t *testing.T) { }` generatedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "", false) expectedPatch := calculatePatch(r2, fmt.Sprintf(expectedPatchTemplate, generatedConditions)) - assert.Equal(t, expectedPatch, patch) + assert.JSONEq(t, expectedPatch, patch) } func TestCanaryRolloutUpdateStatusWhenAtEndOfSteps(t *testing.T) { @@ -383,7 +383,7 @@ func TestCanaryRolloutUpdateStatusWhenAtEndOfSteps(t *testing.T) { }` expectedPatch := fmt.Sprintf(expectedPatchWithoutStableRS, expectedStableRS, generateConditionsPatchWithCompleted(true, conditions.ReplicaSetUpdatedReason, rs2, false, "", true)) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestResetCurrentStepIndexOnStepChange(t *testing.T) { @@ -426,7 +426,7 @@ func TestResetCurrentStepIndexOnStepChange(t *testing.T) { }` newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) expectedPatch := fmt.Sprintf(expectedPatchWithoutPodHash, expectedCurrentPodHash, expectedCurrentStepHash, newConditions) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestResetCurrentStepIndexOnPodSpecChange(t *testing.T) { @@ -467,7 +467,7 @@ func TestResetCurrentStepIndexOnPodSpecChange(t *testing.T) { newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) expectedPatch := fmt.Sprintf(expectedPatchWithoutPodHash, expectedCurrentPodHash, newConditions) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestCanaryRolloutCreateFirstReplicasetNoSteps(t *testing.T) { @@ -505,7 +505,7 @@ func TestCanaryRolloutCreateFirstReplicasetNoSteps(t *testing.T) { newConditions := generateConditionsPatchWithCompleted(false, conditions.ReplicaSetUpdatedReason, rs, false, "", true) - assert.Equal(t, calculatePatch(r, fmt.Sprintf(expectedPatch, newConditions)), patch) + assert.JSONEq(t, calculatePatch(r, fmt.Sprintf(expectedPatch, newConditions)), patch) } func TestCanaryRolloutCreateFirstReplicasetWithSteps(t *testing.T) { @@ -545,7 +545,7 @@ func TestCanaryRolloutCreateFirstReplicasetWithSteps(t *testing.T) { }` expectedPatch := fmt.Sprintf(expectedPatchWithSub, generateConditionsPatchWithCompleted(false, conditions.ReplicaSetUpdatedReason, rs, false, "", true)) - assert.Equal(t, calculatePatch(r, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r, expectedPatch), patch) } func TestCanaryRolloutCreateNewReplicaWithCorrectWeight(t *testing.T) { @@ -843,7 +843,7 @@ func TestRollBackToStable(t *testing.T) { newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs1, false, "", true) expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, hash.ComputePodTemplateHash(&r2.Spec.Template, r2.Status.CollisionCount), newConditions) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestRollBackToActiveReplicaSetWithinWindow(t *testing.T) { @@ -935,7 +935,7 @@ func TestGradualShiftToNewStable(t *testing.T) { newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, newConditions) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestRollBackToStableAndStepChange(t *testing.T) { @@ -983,7 +983,7 @@ func TestRollBackToStableAndStepChange(t *testing.T) { newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs1, false, "", true) expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, newPodHash, newStepHash, newConditions) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestCanaryRolloutIncrementStepIfSetWeightsAreCorrect(t *testing.T) { @@ -1019,7 +1019,7 @@ func TestCanaryRolloutIncrementStepIfSetWeightsAreCorrect(t *testing.T) { } }` newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs3, false, "", false) - assert.Equal(t, calculatePatch(r3, fmt.Sprintf(expectedPatch, newConditions)), patch) + assert.JSONEq(t, calculatePatch(r3, fmt.Sprintf(expectedPatch, newConditions)), patch) } func TestSyncRolloutWaitAddToQueue(t *testing.T) { @@ -1171,7 +1171,7 @@ func TestSyncRolloutWaitIncrementStepIndex(t *testing.T) { "currentStepIndex":2 } }` - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestCanaryRolloutStatusHPAStatusFields(t *testing.T) { @@ -1215,7 +1215,7 @@ func TestCanaryRolloutStatusHPAStatusFields(t *testing.T) { f.run(getKey(r2, t)) patch := f.getPatchedRolloutWithoutConditions(index) - assert.Equal(t, calculatePatch(r2, expectedPatchWithSub), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatchWithSub), patch) } func TestCanaryRolloutWithCanaryService(t *testing.T) { @@ -1656,7 +1656,7 @@ func TestCanaryRolloutScaleWhilePaused(t *testing.T) { patch := f.getPatchedRolloutWithoutConditions(patchIndex) expectedPatch := calculatePatch(r2, OnlyObservedGenerationPatch) - assert.Equal(t, expectedPatch, patch) + assert.JSONEq(t, expectedPatch, patch) } func TestResumeRolloutAfterPauseDuration(t *testing.T) { @@ -1756,7 +1756,7 @@ func TestNoResumeAfterPauseDurationIfUserPaused(t *testing.T) { "message": "manually paused" } }` - assert.Equal(t, calculatePatch(r2, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) } func TestHandleNilNewRSOnScaleAndImageChange(t *testing.T) { @@ -1803,7 +1803,7 @@ func TestHandleNilNewRSOnScaleAndImageChange(t *testing.T) { patchIndex := f.expectPatchRolloutAction(r2) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) } func TestHandleCanaryAbort(t *testing.T) { @@ -1850,10 +1850,10 @@ func TestHandleCanaryAbort(t *testing.T) { }` errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 2) newConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, newConditions, conditions.RolloutAbortedReason, errmsg)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, newConditions, conditions.RolloutAbortedReason, errmsg)), patch) }) - t.Run("Do not reset currentStepCount if newRS is stableRS", func(t *testing.T) { + t.Run("Do not reset currentStepCount and reset abort if newRS is stableRS", func(t *testing.T) { f := newFixture(t) defer f.Close() @@ -1881,13 +1881,12 @@ func TestHandleCanaryAbort(t *testing.T) { patch := f.getPatchedRollout(patchIndex) expectedPatch := `{ "status":{ - "conditions": %s, - "phase": "Degraded", - "message": "%s: %s" + "abort": null, + "abortedAt": null, + "conditions": %s } }` - errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 1) - newConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r1, false, "", true) - assert.Equal(t, calculatePatch(r1, fmt.Sprintf(expectedPatch, newConditions, conditions.RolloutAbortedReason, errmsg)), patch) + newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r1, false, "", true) + assert.JSONEq(t, calculatePatch(r1, fmt.Sprintf(expectedPatch, newConditions)), patch) }) } diff --git a/rollout/controller.go b/rollout/controller.go index 899bc25516..75601661ca 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -56,6 +56,7 @@ import ( logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" + rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" serviceutil "github.com/argoproj/argo-rollouts/utils/service" timeutil "github.com/argoproj/argo-rollouts/utils/time" unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" @@ -521,6 +522,10 @@ func (c *Controller) newRolloutContext(rollout *v1alpha1.Rollout) (*rolloutConte }, reconcilerBase: c.reconcilerBase, } + if rolloututil.IsFullyPromoted(rollout) && roCtx.pauseContext.IsAborted() { + logCtx.Warnf("Removing abort condition from fully promoted rollout") + roCtx.pauseContext.RemoveAbort() + } // carry over existing recorded weights roCtx.newStatus.Canary.Weights = rollout.Status.Canary.Weights return &roCtx, nil diff --git a/rollout/controller_test.go b/rollout/controller_test.go index d2c78d70c1..a893353053 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -1346,7 +1346,7 @@ func TestSwitchInvalidSpecMessage(t *testing.T) { expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, progressingCond, string(invalidSpecBytes), conditions.InvalidSpecReason, strings.ReplaceAll(errmsg, "\"", "\\\"")) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r, expectedPatch), patch) } // TestPodTemplateHashEquivalence verifies the hash is computed consistently when there are slight @@ -1549,7 +1549,7 @@ func TestSwitchBlueGreenToCanary(t *testing.T) { "selector": "foo=bar" } }`, addedConditions, conditions.ComputeStepHash(r)) - assert.Equal(t, calculatePatch(r, expectedPatch), patch) + assert.JSONEq(t, calculatePatch(r, expectedPatch), patch) } func newInvalidSpecCondition(reason string, resourceObj runtime.Object, optionalMessage string) (v1alpha1.RolloutCondition, string) { diff --git a/rollout/experiment_test.go b/rollout/experiment_test.go index bcd10cad92..233dd16ca5 100644 --- a/rollout/experiment_test.go +++ b/rollout/experiment_test.go @@ -69,7 +69,7 @@ func TestRolloutCreateExperiment(t *testing.T) { } }` conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ex.Name, conds)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ex.Name, conds)), patch) } func TestRolloutCreateClusterTemplateExperiment(t *testing.T) { @@ -126,7 +126,7 @@ func TestRolloutCreateClusterTemplateExperiment(t *testing.T) { } }` conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ex.Name, conds)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ex.Name, conds)), patch) } func TestCreateExperimentWithCollision(t *testing.T) { @@ -178,7 +178,7 @@ func TestCreateExperimentWithCollision(t *testing.T) { } }` conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, createdEx.Name, conds)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, createdEx.Name, conds)), patch) } func TestCreateExperimentWithCollisionAndSemanticEquality(t *testing.T) { @@ -229,7 +229,7 @@ func TestCreateExperimentWithCollisionAndSemanticEquality(t *testing.T) { } }` conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ex.Name, conds)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ex.Name, conds)), patch) } func TestRolloutExperimentProcessingDoNothing(t *testing.T) { @@ -267,7 +267,7 @@ func TestRolloutExperimentProcessingDoNothing(t *testing.T) { f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - assert.Equal(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) + assert.JSONEq(t, calculatePatch(r2, OnlyObservedGenerationPatch), patch) } @@ -314,7 +314,7 @@ func TestAbortRolloutAfterFailedExperiment(t *testing.T) { }` now := timeutil.Now().UTC().Format(time.RFC3339) generatedConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, generatedConditions, conditions.RolloutAbortedReason, fmt.Sprintf(conditions.RolloutAbortedMessage, 2))), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, generatedConditions, conditions.RolloutAbortedReason, fmt.Sprintf(conditions.RolloutAbortedMessage, 2))), patch) } func TestPauseRolloutAfterInconclusiveExperiment(t *testing.T) { @@ -481,7 +481,7 @@ func TestRolloutExperimentFinishedIncrementStep(t *testing.T) { }` generatedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "", false) - assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, generatedConditions)), patch) + assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, generatedConditions)), patch) } func TestRolloutDoNotCreateExperimentWithoutStableRS(t *testing.T) { diff --git a/rollout/service_test.go b/rollout/service_test.go index 393faf87a0..e29ee53b4a 100644 --- a/rollout/service_test.go +++ b/rollout/service_test.go @@ -144,7 +144,7 @@ func TestActiveServiceNotFound(t *testing.T) { } }` _, pausedCondition := newInvalidSpecCondition(conditions.InvalidSpecReason, notUsedActiveSvc, errmsg) - assert.Equal(t, calculatePatch(r, fmt.Sprintf(expectedPatch, pausedCondition, conditions.InvalidSpecReason, strings.ReplaceAll(errmsg, "\"", "\\\""))), patch) + assert.JSONEq(t, calculatePatch(r, fmt.Sprintf(expectedPatch, pausedCondition, conditions.InvalidSpecReason, strings.ReplaceAll(errmsg, "\"", "\\\""))), patch) } func TestPreviewServiceNotFound(t *testing.T) { @@ -173,7 +173,7 @@ func TestPreviewServiceNotFound(t *testing.T) { } }` _, pausedCondition := newInvalidSpecCondition(conditions.InvalidSpecReason, notUsedPreviewSvc, errmsg) - assert.Equal(t, calculatePatch(r, fmt.Sprintf(expectedPatch, pausedCondition, conditions.InvalidSpecReason, strings.ReplaceAll(errmsg, "\"", "\\\""))), patch) + assert.JSONEq(t, calculatePatch(r, fmt.Sprintf(expectedPatch, pausedCondition, conditions.InvalidSpecReason, strings.ReplaceAll(errmsg, "\"", "\\\""))), patch) } diff --git a/test/e2e/istio_test.go b/test/e2e/istio_test.go index 2f993f09bc..7ecbd66fdf 100644 --- a/test/e2e/istio_test.go +++ b/test/e2e/istio_test.go @@ -303,7 +303,7 @@ func (s *IstioSuite) TestIstioAbortUpdate() { Then(). When(). AbortRollout(). - WaitForRolloutStatus("Degraded"). + WaitForRolloutStatus("Healthy"). Then(). ExpectRevisionPodCount("1", 1). When(). @@ -316,7 +316,7 @@ func (s *IstioSuite) TestIstioAbortUpdate() { Then(). When(). AbortRollout(). - WaitForRolloutStatus("Degraded"). + WaitForRolloutStatus("Healthy"). Then(). ExpectRevisionPodCount("2", 1) } From 5b40f081f459c0c1265aa3070cc44cca94830db8 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Mon, 23 Oct 2023 05:51:57 -0700 Subject: [PATCH 66/90] fix: rollback to stable with dynamicStableScale could overwhelm stable pods (#3077) * fix: rollback to stable with dynamicStableScale could go under maxUnavailable Signed-off-by: Jesse Suen * test: add unit tests Signed-off-by: Jesse Suen * test: add e2e tests Signed-off-by: Jesse Suen * refactor: move isReplicaSetReferenced to replicaset.go Signed-off-by: Jesse Suen --------- Signed-off-by: Jesse Suen --- rollout/bluegreen.go | 7 +- rollout/canary.go | 49 ++++---- rollout/canary_test.go | 118 ++++++++++++++++++ rollout/replicaset.go | 55 +++++++++ rollout/replicaset_test.go | 182 ++++++++++++++++++++++++++++ rollout/service.go | 15 ++- rollout/service_test.go | 47 +++---- rollout/trafficrouting.go | 43 ++++--- rollout/trafficrouting_test.go | 97 ++++++++++++++- test/e2e/canary_test.go | 60 +++++++++ test/fixtures/common.go | 8 ++ test/fixtures/when.go | 12 ++ utils/replicaset/canary.go | 9 +- utils/replicaset/replicaset.go | 11 -- utils/replicaset/replicaset_test.go | 42 ------- 15 files changed, 631 insertions(+), 124 deletions(-) diff --git a/rollout/bluegreen.go b/rollout/bluegreen.go index 887e022e28..f1bcf7a7bb 100644 --- a/rollout/bluegreen.go +++ b/rollout/bluegreen.go @@ -220,10 +220,9 @@ func (c *rolloutContext) scaleDownOldReplicaSetsForBlueGreen(oldRSs []*appsv1.Re annotationedRSs := int32(0) rolloutReplicas := defaults.GetReplicasOrDefault(c.rollout.Spec.Replicas) for _, targetRS := range oldRSs { - if replicasetutil.IsStillReferenced(c.rollout.Status, targetRS) { - // We should technically never get here because we shouldn't be passing a replicaset list - // which includes referenced ReplicaSets. But we check just in case - c.log.Warnf("Prevented inadvertent scaleDown of RS '%s'", targetRS.Name) + if c.isReplicaSetReferenced(targetRS) { + // We might get here if user interrupted an an update in order to move back to stable. + c.log.Infof("Skip scale down of older RS '%s': still referenced", targetRS.Name) continue } if *targetRS.Spec.Replicas == 0 { diff --git a/rollout/canary.go b/rollout/canary.go index dff4b52d50..b443db507e 100644 --- a/rollout/canary.go +++ b/rollout/canary.go @@ -180,10 +180,9 @@ func (c *rolloutContext) scaleDownOldReplicaSetsForCanary(oldRSs []*appsv1.Repli annotationedRSs := int32(0) for _, targetRS := range oldRSs { - if replicasetutil.IsStillReferenced(c.rollout.Status, targetRS) { - // We should technically never get here because we shouldn't be passing a replicaset list - // which includes referenced ReplicaSets. But we check just in case - c.log.Warnf("Prevented inadvertent scaleDown of RS '%s'", targetRS.Name) + if c.isReplicaSetReferenced(targetRS) { + // We might get here if user interrupted an an update in order to move back to stable. + c.log.Infof("Skip scale down of older RS '%s': still referenced", targetRS.Name) continue } if maxScaleDown <= 0 { @@ -220,15 +219,8 @@ func (c *rolloutContext) scaleDownOldReplicaSetsForCanary(oldRSs []*appsv1.Repli // and doesn't yet have scale down deadline. This happens when a user changes their // mind in the middle of an V1 -> V2 update, and then applies a V3. We are deciding // what to do with the defunct, intermediate V2 ReplicaSet right now. - if !c.replicaSetReferencedByCanaryTraffic(targetRS) { - // It is safe to scale the intermediate RS down, if no traffic is directed to it. - c.log.Infof("scaling down intermediate RS '%s'", targetRS.Name) - } else { - c.log.Infof("Skip scaling down intermediate RS '%s': still referenced by service", targetRS.Name) - // This ReplicaSet is still referenced by the service. It is not safe to scale - // this down. - continue - } + // It is safe to scale the intermediate RS down, since no traffic is directed to it. + c.log.Infof("scaling down intermediate RS '%s'", targetRS.Name) } } if *targetRS.Spec.Replicas == desiredReplicaCount { @@ -248,19 +240,26 @@ func (c *rolloutContext) scaleDownOldReplicaSetsForCanary(oldRSs []*appsv1.Repli return totalScaledDown, nil } -func (c *rolloutContext) replicaSetReferencedByCanaryTraffic(rs *appsv1.ReplicaSet) bool { - rsPodHash := replicasetutil.GetPodTemplateHash(rs) - ro := c.rollout - - if ro.Status.Canary.Weights == nil { - return false - } - - if ro.Status.Canary.Weights.Canary.PodTemplateHash == rsPodHash || ro.Status.Canary.Weights.Stable.PodTemplateHash == rsPodHash { - return true +// isDynamicallyRollingBackToStable returns true if we were in the middle of an canary update with +// dynamic stable scaling, but was interrupted and are now rolling back to stable RS. This is similar +// to, but different than aborting. With abort, desired hash != stable hash and so we know the +// two hashes to balance traffic against. But with dynamically rolling back to stable, the +// desired hash == stable hash, and so we must use the *previous* desired hash and balance traffic +// between previous desired vs. stable hash, in order to safely shift traffic back to stable. +// This function also returns the previous desired hash (where we are weighted to) +func isDynamicallyRollingBackToStable(ro *v1alpha1.Rollout, desiredRS *appsv1.ReplicaSet) (bool, string) { + if rolloututil.IsFullyPromoted(ro) && ro.Spec.Strategy.Canary.TrafficRouting != nil && ro.Spec.Strategy.Canary.DynamicStableScale { + if ro.Status.Canary.Weights != nil { + currSelector := ro.Status.Canary.Weights.Canary.PodTemplateHash + desiredSelector := replicasetutil.GetPodTemplateHash(desiredRS) + if currSelector != desiredSelector { + if desiredRS.Status.AvailableReplicas < *ro.Spec.Replicas { + return true, currSelector + } + } + } } - - return false + return false, "" } // canProceedWithScaleDownAnnotation returns whether or not it is safe to proceed with annotating diff --git a/rollout/canary_test.go b/rollout/canary_test.go index 1d8af7d80e..b275170eec 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/stretchr/testify/assert" + appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -1890,3 +1891,120 @@ func TestHandleCanaryAbort(t *testing.T) { assert.JSONEq(t, calculatePatch(r1, fmt.Sprintf(expectedPatch, newConditions)), patch) }) } + +func TestIsDynamicallyRollingBackToStable(t *testing.T) { + newRSWithHashAndReplicas := func(hash string, available int32) *appsv1.ReplicaSet { + return &appsv1.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + v1alpha1.DefaultRolloutUniqueLabelKey: hash, + }, + }, + Status: v1.ReplicaSetStatus{ + AvailableReplicas: available, + }, + } + } + + testCases := []struct { + name string + status v1alpha1.RolloutStatus + trafficRoutingDisabled bool + dynamicStableScalingDisabled bool + rsHash string + rsAvailableReplicas *int32 // if nil, will set to rollout replicas + trafficWeights *v1alpha1.TrafficWeights + expectedResult bool + }{ + { + name: "desired RS != stable RS", + status: v1alpha1.RolloutStatus{CurrentPodHash: "abc123", StableRS: "def456"}, + rsHash: "", + expectedResult: false, + }, + { + name: "not using traffic routing", + trafficRoutingDisabled: true, + status: v1alpha1.RolloutStatus{CurrentPodHash: "abc123", StableRS: "abc123"}, + rsHash: "", + expectedResult: false, + }, + { + name: "not using dynamicStableScaling", + dynamicStableScalingDisabled: true, + status: v1alpha1.RolloutStatus{CurrentPodHash: "abc123", StableRS: "abc123"}, + rsHash: "", + expectedResult: false, + }, + { + name: "weighted selector == desired RS", + status: v1alpha1.RolloutStatus{ + CurrentPodHash: "abc123", + StableRS: "abc123", + Canary: v1alpha1.CanaryStatus{ + Weights: &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + PodTemplateHash: "abc123", + }, + }, + }, + }, + rsHash: "abc123", + expectedResult: false, + }, + { + name: "weighted selector != desired RS, desired not fully available", + status: v1alpha1.RolloutStatus{ + CurrentPodHash: "abc123", + StableRS: "abc123", + Canary: v1alpha1.CanaryStatus{ + Weights: &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + PodTemplateHash: "def456", + }, + }, + }, + }, + rsHash: "abc123", + rsAvailableReplicas: pointer.Int32(1), + expectedResult: true, + }, + { + name: "weighted selector != desired RS, desired RS is fully available", + status: v1alpha1.RolloutStatus{ + CurrentPodHash: "abc123", + StableRS: "abc123", + Canary: v1alpha1.CanaryStatus{ + Weights: &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + PodTemplateHash: "def456", + }, + }, + }, + }, + rsHash: "abc123", + expectedResult: true, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ro := newCanaryRollout("test", 10, nil, nil, nil, intstr.FromInt(0), intstr.FromInt(1)) + if !tc.trafficRoutingDisabled { + ro.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{} + } + if !tc.dynamicStableScalingDisabled { + ro.Spec.Strategy.Canary.DynamicStableScale = true + } + ro.Status = tc.status + + desiredRS := newRSWithHashAndReplicas(tc.rsHash, 1) + if tc.rsAvailableReplicas != nil { + desiredRS.Status.AvailableReplicas = *tc.rsAvailableReplicas + } + + rbToStable, _ := isDynamicallyRollingBackToStable(ro, desiredRS) + + assert.Equal(t, tc.expectedResult, rbToStable) + }) + } +} diff --git a/rollout/replicaset.go b/rollout/replicaset.go index fad23e756e..7d9a71f62a 100644 --- a/rollout/replicaset.go +++ b/rollout/replicaset.go @@ -7,6 +7,7 @@ import ( "time" appsv1 "k8s.io/api/apps/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" patchtypes "k8s.io/apimachinery/pkg/types" @@ -15,6 +16,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/defaults" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" + serviceutil "github.com/argoproj/argo-rollouts/utils/service" timeutil "github.com/argoproj/argo-rollouts/utils/time" ) @@ -296,3 +298,56 @@ func (c *rolloutContext) scaleDownDelayHelper(rs *appsv1.ReplicaSet, annotatione return annotationedRSs, desiredReplicaCount, nil } + +// isReplicaSetReferenced returns if the given ReplicaSet is still being referenced by any of +// the current, stable, blue-green services. Used to determine if the ReplicaSet can +// safely be scaled to zero, or deleted. +func (c *rolloutContext) isReplicaSetReferenced(rs *appsv1.ReplicaSet) bool { + rsPodHash := replicasetutil.GetPodTemplateHash(rs) + if rsPodHash == "" { + return false + } + ro := c.rollout + referencesToCheck := []string{ + ro.Status.StableRS, + ro.Status.CurrentPodHash, + ro.Status.BlueGreen.ActiveSelector, + ro.Status.BlueGreen.PreviewSelector, + } + if ro.Status.Canary.Weights != nil { + referencesToCheck = append(referencesToCheck, ro.Status.Canary.Weights.Canary.PodTemplateHash, ro.Status.Canary.Weights.Stable.PodTemplateHash) + } + for _, ref := range referencesToCheck { + if ref == rsPodHash { + return true + } + } + + // The above are static, lightweight checks to see if the selectors we record in our status are + // still referencing the ReplicaSet in question. Those checks aren't always enough. Next, we do + // a deeper check to look up the actual service objects, and see if they are still referencing + // the ReplicaSet. If so, we cannot scale it down. + var servicesToCheck []string + if ro.Spec.Strategy.Canary != nil { + servicesToCheck = []string{ro.Spec.Strategy.Canary.CanaryService, ro.Spec.Strategy.Canary.StableService} + } else { + servicesToCheck = []string{ro.Spec.Strategy.BlueGreen.ActiveService, ro.Spec.Strategy.BlueGreen.PreviewService} + } + for _, svcName := range servicesToCheck { + if svcName == "" { + continue + } + svc, err := c.servicesLister.Services(c.rollout.Namespace).Get(svcName) + if err != nil { + if k8serrors.IsNotFound(err) { + // service doesn't exist + continue + } + return true + } + if serviceutil.GetRolloutSelectorLabel(svc) == rsPodHash { + return true + } + } + return false +} diff --git a/rollout/replicaset_test.go b/rollout/replicaset_test.go index 7baba5e7a3..262bd23dd7 100644 --- a/rollout/replicaset_test.go +++ b/rollout/replicaset_test.go @@ -8,6 +8,9 @@ import ( "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + k8sinformers "k8s.io/client-go/informers" k8sfake "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" "k8s.io/utils/pointer" @@ -353,3 +356,182 @@ func TestReconcileOldReplicaSet(t *testing.T) { }) } } + +func TestIsReplicaSetReferenced(t *testing.T) { + newRSWithPodTemplateHash := func(hash string) *appsv1.ReplicaSet { + return &appsv1.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + v1alpha1.DefaultRolloutUniqueLabelKey: hash, + }, + }, + } + } + + testCases := []struct { + name string + status v1alpha1.RolloutStatus + canaryService string + stableService string + activeService string + previewService string + services []runtime.Object + rsHash string + expectedResult bool + }{ + { + name: "empty hash", + status: v1alpha1.RolloutStatus{StableRS: "abc123"}, + rsHash: "", + expectedResult: false, + }, + { + name: "not referenced", + status: v1alpha1.RolloutStatus{StableRS: "abc123"}, + rsHash: "def456", + expectedResult: false, + }, + { + name: "stable rs referenced", + status: v1alpha1.RolloutStatus{StableRS: "abc123"}, + rsHash: "abc123", + expectedResult: true, + }, + { + name: "current rs referenced", + status: v1alpha1.RolloutStatus{CurrentPodHash: "abc123"}, + rsHash: "abc123", + expectedResult: true, + }, + { + name: "active referenced", + status: v1alpha1.RolloutStatus{BlueGreen: v1alpha1.BlueGreenStatus{ActiveSelector: "abc123"}}, + rsHash: "abc123", + expectedResult: true, + }, + { + name: "active referenced", + status: v1alpha1.RolloutStatus{BlueGreen: v1alpha1.BlueGreenStatus{PreviewSelector: "abc123"}}, + rsHash: "abc123", + expectedResult: true, + }, + { + name: "traffic routed canary current pod hash", + status: v1alpha1.RolloutStatus{Canary: v1alpha1.CanaryStatus{Weights: &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + PodTemplateHash: "abc123", + }, + }}}, + rsHash: "abc123", + expectedResult: true, + }, + { + name: "traffic routed canary current pod hash", + status: v1alpha1.RolloutStatus{Canary: v1alpha1.CanaryStatus{Weights: &v1alpha1.TrafficWeights{ + Stable: v1alpha1.WeightDestination{ + PodTemplateHash: "abc123", + }, + }}}, + rsHash: "abc123", + expectedResult: true, + }, + { + name: "canary service still referenced", + status: v1alpha1.RolloutStatus{ + CurrentPodHash: "abc123", + StableRS: "abc123", + }, + canaryService: "mysvc", + services: []runtime.Object{newService("mysvc", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: "def456"}, nil)}, + rsHash: "def456", + expectedResult: true, + }, + { + name: "stable service still referenced", + status: v1alpha1.RolloutStatus{ + CurrentPodHash: "abc123", + StableRS: "abc123", + }, + stableService: "mysvc", + services: []runtime.Object{newService("mysvc", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: "def456"}, nil)}, + rsHash: "def456", + expectedResult: true, + }, + { + name: "active service still referenced", + status: v1alpha1.RolloutStatus{ + CurrentPodHash: "abc123", + StableRS: "abc123", + }, + activeService: "mysvc", + services: []runtime.Object{newService("mysvc", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: "def456"}, nil)}, + rsHash: "def456", + expectedResult: true, + }, + { + name: "preview service still referenced", + status: v1alpha1.RolloutStatus{ + CurrentPodHash: "abc123", + StableRS: "abc123", + }, + activeService: "mysvc", + previewService: "mysvc2", + services: []runtime.Object{newService("mysvc2", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: "def456"}, nil)}, + rsHash: "def456", + expectedResult: true, + }, + { + name: "service not found", + status: v1alpha1.RolloutStatus{ + CurrentPodHash: "abc123", + StableRS: "abc123", + }, + activeService: "mysvc", + previewService: "mysvc2", + rsHash: "def456", + expectedResult: false, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + + fake := fake.Clientset{} + k8sfake := k8sfake.NewSimpleClientset(tc.services...) + informers := k8sinformers.NewSharedInformerFactory(k8sfake, 0) + servicesLister := informers.Core().V1().Services().Lister() + stopchan := make(chan struct{}) + defer close(stopchan) + informers.Start(stopchan) + informers.WaitForCacheSync(stopchan) + + var r *v1alpha1.Rollout + if tc.activeService != "" { + r = newBlueGreenRollout("test", 1, nil, tc.activeService, tc.previewService) + } else { + r = newCanaryRollout("test", 1, nil, nil, nil, intstr.FromInt(0), intstr.FromInt(1)) + r.Spec.Strategy.Canary.CanaryService = tc.canaryService + r.Spec.Strategy.Canary.StableService = tc.stableService + } + r.Status = tc.status + + roCtx := &rolloutContext{ + rollout: r, + log: logutil.WithRollout(r), + reconcilerBase: reconcilerBase{ + servicesLister: servicesLister, + argoprojclientset: &fake, + kubeclientset: k8sfake, + recorder: record.NewFakeEventRecorder(), + }, + } + rs := newRSWithPodTemplateHash(tc.rsHash) + stillReferenced := roCtx.isReplicaSetReferenced(rs) + + assert.Equal( + t, + tc.expectedResult, + stillReferenced, + ) + }) + } +} diff --git a/rollout/service.go b/rollout/service.go index f808cb55fc..69739b9315 100644 --- a/rollout/service.go +++ b/rollout/service.go @@ -147,7 +147,7 @@ func (c *rolloutContext) awsVerifyTargetGroups(svc *corev1.Service) error { return nil } - c.targetsVerified = pointer.BoolPtr(false) + c.targetsVerified = pointer.Bool(false) // get endpoints of service endpoints, err := c.kubeclientset.CoreV1().Endpoints(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) @@ -177,7 +177,7 @@ func (c *rolloutContext) awsVerifyTargetGroups(svc *corev1.Service) error { } c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: conditions.TargetGroupVerifiedReason}, conditions.TargetGroupVerifiedRegistrationMessage, svc.Name, tgb.Spec.TargetGroupARN, verifyRes.EndpointsRegistered) } - c.targetsVerified = pointer.BoolPtr(true) + c.targetsVerified = pointer.Bool(true) return nil } @@ -266,6 +266,17 @@ func (c *rolloutContext) reconcileStableAndCanaryService() error { return nil } + if dynamicallyRollingBackToStable, currSelector := isDynamicallyRollingBackToStable(c.rollout, c.newRS); dynamicallyRollingBackToStable { + // User may have interrupted an update in order go back to stableRS, and is using dynamic + // stable scaling. If that is the case, the stableRS might be undersized and if we blindly + // switch service selector we could overwhelm stableRS pods. + // If we get here, we detected that the canary service needs to be pointed back to + // stable, but stable is not fully available. Skip the service switch for now. + c.log.Infof("delaying fully promoted service switch of '%s' from %s to %s: ReplicaSet '%s' not fully available", + c.rollout.Spec.Strategy.Canary.CanaryService, currSelector, replicasetutil.GetPodTemplateHash(c.newRS), c.newRS.Name) + return nil + } + err = c.ensureSVCTargets(c.rollout.Spec.Strategy.Canary.CanaryService, c.newRS, true) if err != nil { return err diff --git a/rollout/service_test.go b/rollout/service_test.go index e29ee53b4a..cb15367a3a 100644 --- a/rollout/service_test.go +++ b/rollout/service_test.go @@ -437,26 +437,26 @@ func TestCanaryAWSVerifyTargetGroupsNotYetReady(t *testing.T) { TargetHealthDescriptions: []elbv2types.TargetHealthDescription{ { Target: &elbv2types.TargetDescription{ - Id: pointer.StringPtr("1.2.3.4"), - Port: pointer.Int32Ptr(80), + Id: pointer.String("1.2.3.4"), + Port: pointer.Int32(80), }, }, { Target: &elbv2types.TargetDescription{ - Id: pointer.StringPtr("5.6.7.8"), - Port: pointer.Int32Ptr(80), + Id: pointer.String("5.6.7.8"), + Port: pointer.Int32(80), }, }, { Target: &elbv2types.TargetDescription{ - Id: pointer.StringPtr("2.4.6.8"), // irrelevant - Port: pointer.Int32Ptr(81), // wrong port + Id: pointer.String("2.4.6.8"), // irrelevant + Port: pointer.Int32(81), // wrong port }, }, { Target: &elbv2types.TargetDescription{ - Id: pointer.StringPtr("9.8.7.6"), // irrelevant ip - Port: pointer.Int32Ptr(80), + Id: pointer.String("9.8.7.6"), // irrelevant ip + Port: pointer.Int32(80), }, }, }, @@ -464,8 +464,8 @@ func TestCanaryAWSVerifyTargetGroupsNotYetReady(t *testing.T) { fakeELB.On("DescribeTargetHealth", mock.Anything, mock.Anything).Return(&thOut, nil) r1 := newCanaryRollout("foo", 3, nil, []v1alpha1.CanaryStep{{ - SetWeight: pointer.Int32Ptr(10), - }}, pointer.Int32Ptr(0), intstr.FromString("25%"), intstr.FromString("25%")) + SetWeight: pointer.Int32(10), + }}, pointer.Int32(0), intstr.FromString("25%"), intstr.FromString("25%")) r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ ALB: &v1alpha1.ALBTrafficRouting{ @@ -491,6 +491,7 @@ func TestCanaryAWSVerifyTargetGroupsNotYetReady(t *testing.T) { r2.Status.Message = "" r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) r2.Status.StableRS = rs2PodHash + r2.Status.CurrentStepIndex = pointer.Int32(1) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) healthyCondition, _ := newHealthyCondition(false) @@ -536,26 +537,26 @@ func TestCanaryAWSVerifyTargetGroupsReady(t *testing.T) { TargetHealthDescriptions: []elbv2types.TargetHealthDescription{ { Target: &elbv2types.TargetDescription{ - Id: pointer.StringPtr("1.2.3.4"), - Port: pointer.Int32Ptr(80), + Id: pointer.String("1.2.3.4"), + Port: pointer.Int32(80), }, }, { Target: &elbv2types.TargetDescription{ - Id: pointer.StringPtr("5.6.7.8"), - Port: pointer.Int32Ptr(80), + Id: pointer.String("5.6.7.8"), + Port: pointer.Int32(80), }, }, { Target: &elbv2types.TargetDescription{ - Id: pointer.StringPtr("2.4.6.8"), // irrelevant - Port: pointer.Int32Ptr(80), // wrong port + Id: pointer.String("2.4.6.8"), // irrelevant + Port: pointer.Int32(80), // wrong port }, }, { Target: &elbv2types.TargetDescription{ - Id: pointer.StringPtr("9.8.7.6"), // irrelevant ip - Port: pointer.Int32Ptr(80), + Id: pointer.String("9.8.7.6"), // irrelevant ip + Port: pointer.Int32(80), }, }, }, @@ -563,8 +564,8 @@ func TestCanaryAWSVerifyTargetGroupsReady(t *testing.T) { fakeELB.On("DescribeTargetHealth", mock.Anything, mock.Anything).Return(&thOut, nil) r1 := newCanaryRollout("foo", 3, nil, []v1alpha1.CanaryStep{{ - SetWeight: pointer.Int32Ptr(10), - }}, pointer.Int32Ptr(0), intstr.FromString("25%"), intstr.FromString("25%")) + SetWeight: pointer.Int32(10), + }}, pointer.Int32(0), intstr.FromString("25%"), intstr.FromString("25%")) r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ ALB: &v1alpha1.ALBTrafficRouting{ Ingress: "ingress", @@ -589,6 +590,7 @@ func TestCanaryAWSVerifyTargetGroupsReady(t *testing.T) { r2.Status.Message = "" r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) r2.Status.StableRS = rs2PodHash + r2.Status.CurrentStepIndex = pointer.Int32(1) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) healthyCondition, _ := newHealthyCondition(false) @@ -624,8 +626,8 @@ func TestCanaryAWSVerifyTargetGroupsSkip(t *testing.T) { defer f.Close() r1 := newCanaryRollout("foo", 3, nil, []v1alpha1.CanaryStep{{ - SetWeight: pointer.Int32Ptr(10), - }}, pointer.Int32Ptr(0), intstr.FromString("25%"), intstr.FromString("25%")) + SetWeight: pointer.Int32(10), + }}, pointer.Int32(0), intstr.FromString("25%"), intstr.FromString("25%")) r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ ALB: &v1alpha1.ALBTrafficRouting{ Ingress: "ingress", @@ -652,6 +654,7 @@ func TestCanaryAWSVerifyTargetGroupsSkip(t *testing.T) { r2.Status.Message = "" r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) r2.Status.StableRS = rs2PodHash + r2.Status.CurrentStepIndex = pointer.Int32(1) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) healthyCondition, _ := newHealthyCondition(false) diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index c7b3bf7055..a87e31a9e8 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -163,25 +163,20 @@ func (c *rolloutContext) reconcileTrafficRouting() error { canaryHash = c.newRS.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] } - if rolloututil.IsFullyPromoted(c.rollout) { - // when we are fully promoted. desired canary weight should be 0 + if dynamicallyRollingBackToStable, prevDesiredHash := isDynamicallyRollingBackToStable(c.rollout, c.newRS); dynamicallyRollingBackToStable { + desiredWeight = c.calculateDesiredWeightOnAbortOrStableRollback() + // Since stableRS == desiredRS, we must balance traffic between the + // *previous desired* vs. stable (as opposed to current desired vs. stable). + // The previous desired is remembered in Status.Canary.Weights.Canary.PodTemplateHash. + // See: https://github.com/argoproj/argo-rollouts/issues/3020 + canaryHash = prevDesiredHash + } else if rolloututil.IsFullyPromoted(c.rollout) { err := reconciler.RemoveManagedRoutes() if err != nil { return err } } else if c.pauseContext.IsAborted() { - // when aborted, desired canary weight should immediately be 0 (100% to stable), *unless* - // we are using dynamic stable scaling. In that case, we are dynamically decreasing the - // weight to the canary according to the availability of the stable (whatever it can support). - if c.rollout.Spec.Strategy.Canary.DynamicStableScale { - desiredWeight = 100 - ((100 * c.stableRS.Status.AvailableReplicas) / *c.rollout.Spec.Replicas) - if c.rollout.Status.Canary.Weights != nil { - // This ensures that if we are already at a lower weight, then we will not - // increase the weight because stable availability is flapping (e.g. pod restarts) - desiredWeight = minInt(desiredWeight, c.rollout.Status.Canary.Weights.Canary.Weight) - } - } - + desiredWeight = c.calculateDesiredWeightOnAbortOrStableRollback() if (c.rollout.Spec.Strategy.Canary.DynamicStableScale && desiredWeight == 0) || !c.rollout.Spec.Strategy.Canary.DynamicStableScale { // If we are using dynamic stable scale we need to also make sure that desiredWeight=0 aka we are completely // done with aborting before resetting the canary service selectors back to stable @@ -295,6 +290,26 @@ func (c *rolloutContext) reconcileTrafficRouting() error { return nil } +// calculateDesiredWeightOnAbortOrStableRollback returns the desired weight to use when we are either +// aborting, or rolling back to stable RS. +func (c *rolloutContext) calculateDesiredWeightOnAbortOrStableRollback() int32 { + if !c.rollout.Spec.Strategy.Canary.DynamicStableScale { + // When aborting or rolling back to stable RS and dynamicStableScaling is disabled, + // then desired canary weight should immediately be 0 (100% to stable) since we can trust + // that it is fully scaled up + return 0 + } + // When using dynamic stable scaling, we must dynamically decreasing the weight to the canary + // according to the availability of the stable (whatever it can support). + desiredWeight := 100 - ((100 * c.stableRS.Status.AvailableReplicas) / *c.rollout.Spec.Replicas) + if c.rollout.Status.Canary.Weights != nil { + // This ensures that if we are already at a lower weight, then we will not + // increase the weight because stable availability is flapping (e.g. pod restarts) + desiredWeight = minInt(desiredWeight, c.rollout.Status.Canary.Weights.Canary.Weight) + } + return desiredWeight +} + // trafficWeightUpdatedMessage returns a message we emit for the kubernetes event whenever we adjust traffic weights func trafficWeightUpdatedMessage(prev, new *v1alpha1.TrafficWeights) string { var details []string diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index 21aea362ae..a8f5520ea2 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -2,6 +2,7 @@ package rollout import ( "errors" + "fmt" "strconv" "testing" "time" @@ -752,8 +753,8 @@ func TestCanaryWithTrafficRoutingAddScaleDownDelay(t *testing.T) { defer f.Close() r1 := newCanaryRollout("foo", 1, nil, []v1alpha1.CanaryStep{{ - SetWeight: pointer.Int32Ptr(10), - }}, pointer.Int32Ptr(0), intstr.FromInt(1), intstr.FromInt(1)) + SetWeight: pointer.Int32(10), + }}, pointer.Int32(0), intstr.FromInt(1), intstr.FromInt(1)) r1.Spec.Strategy.Canary.CanaryService = "canary" r1.Spec.Strategy.Canary.StableService = "stable" r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ @@ -765,6 +766,7 @@ func TestCanaryWithTrafficRoutingAddScaleDownDelay(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] r2 = updateCanaryRolloutStatus(r2, rs2PodHash, 2, 1, 2, false) r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) + r2.Status.CurrentStepIndex = pointer.Int32(1) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) completedCondition, _ := newCompletedCondition(true) @@ -1153,3 +1155,94 @@ func TestRolloutReplicaIsAvailableAndGenerationNotBeModifiedShouldModifyVirtualS }).Once().Return(nil) f.run(getKey(r1, t)) } + +// This makes sure we don't set weight to zero if we are rolling back to stable with DynamicStableScale +func TestDontWeightToZeroWhenDynamicallyRollingBackToStable(t *testing.T) { + f := newFixture(t) + defer f.Close() + + steps := []v1alpha1.CanaryStep{ + { + SetWeight: pointer.Int32(90), + }, + { + Pause: &v1alpha1.RolloutPause{}, + }, + } + r1 := newCanaryRollout("foo", 10, nil, steps, pointer.Int32(1), intstr.FromInt(1), intstr.FromInt(1)) + r1.Spec.Strategy.Canary.DynamicStableScale = true + r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + SMI: &v1alpha1.SMITrafficRouting{}, + } + r1.Spec.Strategy.Canary.CanaryService = "canary" + r1.Spec.Strategy.Canary.StableService = "stable" + r1.Status.ReadyReplicas = 10 + r1.Status.AvailableReplicas = 10 + r2 := bumpVersion(r1) + + rs1 := newReplicaSetWithStatus(r1, 1, 1) + rs2 := newReplicaSetWithStatus(r2, 9, 9) + + 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, r1) + stableSvc := newService("stable", 80, stableSelector, r1) + + // simulate rollback to stable + r2.Spec = r1.Spec + r2.Status.StableRS = rs1PodHash + r2.Status.CurrentPodHash = rs1PodHash // will cause IsFullyPromoted() to be true + r2.Status.Canary.Weights = &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + Weight: 10, + ServiceName: "canary", + PodTemplateHash: rs2PodHash, + }, + Stable: v1alpha1.WeightDestination{ + Weight: 90, + ServiceName: "stable", + PodTemplateHash: rs1PodHash, + }, + } + + f.kubeobjects = append(f.kubeobjects, rs1, rs2, canarySvc, stableSvc) + f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) + + f.rolloutLister = append(f.rolloutLister, r2) + f.objects = append(f.objects, r2) + + f.expectUpdateReplicaSetAction(rs1) // Updates the revision annotation from 1 to 3 + f.expectUpdateReplicaSetAction(rs1) // repeat of the above (not sure why) + scaleUpIndex := f.expectUpdateReplicaSetAction(rs1) // this one scales the stable RS to 10 + f.expectPatchRolloutAction(r2) + + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(func(canaryHash, stableHash string, additionalDestinations ...v1alpha1.WeightDestination) error { + // make sure UpdateHash was called with previous desired hash (not current pod hash) + if canaryHash != rs2PodHash { + return fmt.Errorf("UpdateHash was called with canary hash: %s. Expected: %s", canaryHash, rs2PodHash) + } + if stableHash != rs1PodHash { + return fmt.Errorf("UpdateHash was called with stable hash: %s. Expected: %s", canaryHash, rs1PodHash) + } + return nil + + }) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was not changed + if desiredWeight != 10 { + return fmt.Errorf("SetWeight was called with unexpected weight: %d. Expected: 10", desiredWeight) + } + return nil + }) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("RemoveManagedRoutes", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) + f.run(getKey(r1, t)) + + // Make sure we scale up stable ReplicaSet to 10 + rs1Updated := f.getUpdatedReplicaSet(scaleUpIndex) + assert.Equal(t, int32(10), *rs1Updated.Spec.Replicas) +} diff --git a/test/e2e/canary_test.go b/test/e2e/canary_test.go index fe22175074..bc5e60b6c3 100644 --- a/test/e2e/canary_test.go +++ b/test/e2e/canary_test.go @@ -13,6 +13,7 @@ import ( corev1 "k8s.io/api/core/v1" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + rov1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/test/fixtures" ) @@ -620,3 +621,62 @@ func (s *CanarySuite) TestCanaryDynamicStableScale() { ExpectServiceSelector("dynamic-stable-scale-canary", map[string]string{"app": "dynamic-stable-scale", "rollouts-pod-template-hash": "868d98995b"}, false). ExpectRevisionPodCount("1", 4) } + +// TestCanaryDynamicStableScaleRollbackToStable verifies when we rollback to stable with +// DynamicStableScale enabled, we do so in a safe manner without shifting traffic back to stable +// before it can handle it +func (s *CanarySuite) TestCanaryDynamicStableScaleRollbackToStable() { + s.Given(). + RolloutObjects(`@functional/canary-dynamic-stable-scale.yaml`). + When(). + ApplyManifests(). + MarkPodsReady("1", 4). // mark all 4 pods ready + WaitForRolloutStatus("Healthy"). + UpdateSpec(). + MarkPodsReady("2", 1). // mark 1 of 1 canary pods ready + WaitForRolloutStatus("Paused"). + Sleep(2*time.Second). + Then(). + ExpectRevisionPodCount("1", 3). + ExpectRevisionPodCount("2", 1). + When(). + UndoRollout(1). // Rollback to stable (revision 1) + Sleep(2*time.Second). + Then(). + ExpectRevisionPodCount("3", 4). // Ensure we fully scale up the stable (now revision 3) + ExpectRevisionPodCount("2", 1). // And do not scale down the previous desired (revision 2) + Assert(func(t *fixtures.Then) { + // Make sure canary service is still pointing to the previous desired (revision 2) + rs3 := t.GetReplicaSetByRevision("3") + rs2 := t.GetReplicaSetByRevision("2") + canarySvc, stableSvc := t.GetServices() + assert.Equal(s.T(), rs2.Labels[rov1.DefaultRolloutUniqueLabelKey], canarySvc.Spec.Selector["rollouts-pod-template-hash"]) + assert.Equal(s.T(), rs3.Labels[rov1.DefaultRolloutUniqueLabelKey], stableSvc.Spec.Selector["rollouts-pod-template-hash"]) + + // Ensure we did not touch the weights even though we are "fully promoted" + ro := t.GetRollout() + assert.Equal(s.T(), rs2.Labels[rov1.DefaultRolloutUniqueLabelKey], ro.Status.Canary.Weights.Canary.PodTemplateHash) + assert.Equal(s.T(), int32(25), ro.Status.Canary.Weights.Canary.Weight) + assert.Equal(s.T(), rs3.Labels[rov1.DefaultRolloutUniqueLabelKey], ro.Status.Canary.Weights.Stable.PodTemplateHash) + assert.Equal(s.T(), int32(75), ro.Status.Canary.Weights.Stable.Weight) + }). + When(). + MarkPodsReady("3", 1). // marks the 4th pod of stableRS/newRS (revision 3) ready + WaitForRevisionPodCount("2", 0). // make sure we scale down the previous desired (revision 2) + Then(). + Assert(func(t *fixtures.Then) { + // Make sure canary/stable service is updated to point to revision 3 + rs3 := t.GetReplicaSetByRevision("3") + canarySvc, stableSvc := t.GetServices() + assert.Equal(s.T(), rs3.Labels[rov1.DefaultRolloutUniqueLabelKey], canarySvc.Spec.Selector["rollouts-pod-template-hash"]) + assert.Equal(s.T(), rs3.Labels[rov1.DefaultRolloutUniqueLabelKey], stableSvc.Spec.Selector["rollouts-pod-template-hash"]) + + // Ensure we are 100% back to stable + ro := t.GetRollout() + assert.Equal(s.T(), rs3.Labels[rov1.DefaultRolloutUniqueLabelKey], ro.Status.Canary.Weights.Canary.PodTemplateHash) + assert.Equal(s.T(), int32(0), ro.Status.Canary.Weights.Canary.Weight) + assert.Equal(s.T(), rs3.Labels[rov1.DefaultRolloutUniqueLabelKey], ro.Status.Canary.Weights.Stable.PodTemplateHash) + assert.Equal(s.T(), int32(100), ro.Status.Canary.Weights.Stable.Weight) + + }) +} diff --git a/test/fixtures/common.go b/test/fixtures/common.go index 9e060df865..670d2dd2f4 100644 --- a/test/fixtures/common.go +++ b/test/fixtures/common.go @@ -71,6 +71,7 @@ func (c *Common) CheckError(err error) { } } +// Rollout returns the original rollout manifest used in the test func (c *Common) Rollout() *rov1.Rollout { var ro rov1.Rollout err := runtime.DefaultUnstructuredConverter.FromUnstructured(c.rollout.Object, &ro) @@ -78,6 +79,13 @@ func (c *Common) Rollout() *rov1.Rollout { return &ro } +// GetRollout returns the live rollout object in the cluster +func (c *Common) GetRollout() *rov1.Rollout { + ro, err := c.rolloutClient.ArgoprojV1alpha1().Rollouts(c.namespace).Get(context.TODO(), c.Rollout().GetName(), metav1.GetOptions{}) + c.CheckError(err) + return ro +} + func (c *Common) PrintRollout(name string) { streams := genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr} o := options.NewArgoRolloutsOptions(streams) diff --git a/test/fixtures/when.go b/test/fixtures/when.go index 82e84d3a42..0fa77610f4 100644 --- a/test/fixtures/when.go +++ b/test/fixtures/when.go @@ -25,12 +25,14 @@ import ( "sigs.k8s.io/yaml" "github.com/argoproj/argo-rollouts/pkg/apiclient/rollout" + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" rov1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/abort" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/promote" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/restart" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/retry" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/status" + "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/undo" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/viewcontroller" rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" @@ -185,6 +187,16 @@ func (w *When) RetryRollout() *When { return w } +func (w *When) UndoRollout(toRevision int64) *When { + if w.rollout == nil { + w.t.Fatal("Rollout not set") + } + _, err := undo.RunUndoRollout(w.dynamicClient.Resource(v1alpha1.RolloutGVR).Namespace(w.namespace), w.kubeClient, w.rollout.GetName(), toRevision) + w.CheckError(err) + w.log.Infof("Undo rollout to %d", toRevision) + return w +} + func (w *When) RestartRollout() *When { if w.rollout == nil { w.t.Fatal("Rollout not set") diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index a751cd2be2..40eadb7848 100755 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -41,8 +41,13 @@ func AtDesiredReplicaCountsForCanary(ro *v1alpha1.Rollout, newRS, stableRS *apps return false } } - if GetAvailableReplicaCountForReplicaSets(olderRSs) != int32(0) { - return false + if ro.Spec.Strategy.Canary.TrafficRouting == nil { + // For basic canary, all older ReplicaSets must be scaled to zero since they serve traffic. + // For traffic weighted canary, it's okay if they are still scaled up, since the traffic + // router will prevent them from serving traffic + if GetAvailableReplicaCountForReplicaSets(olderRSs) != int32(0) { + return false + } } return true } diff --git a/utils/replicaset/replicaset.go b/utils/replicaset/replicaset.go index 9aec161b66..b2664afd53 100644 --- a/utils/replicaset/replicaset.go +++ b/utils/replicaset/replicaset.go @@ -592,17 +592,6 @@ func (o ReplicaSetsByRevisionNumber) Less(i, j int) bool { return iRevision < jRevision } -// IsStillReferenced returns if the given ReplicaSet is still being referenced by any of -// the current, stable, blue-green active references. Used to determine if the ReplicaSet can -// safely be scaled to zero, or deleted. -func IsStillReferenced(status v1alpha1.RolloutStatus, rs *appsv1.ReplicaSet) bool { - hash := GetPodTemplateHash(rs) - if hash != "" && (hash == status.StableRS || hash == status.CurrentPodHash || hash == status.BlueGreen.ActiveSelector) { - return true - } - return false -} - // HasScaleDownDeadline returns whether or not the given ReplicaSet is annotated with a scale-down delay func HasScaleDownDeadline(rs *appsv1.ReplicaSet) bool { if rs == nil || rs.Annotations == nil { diff --git a/utils/replicaset/replicaset_test.go b/utils/replicaset/replicaset_test.go index 23bf320955..462fa2b835 100644 --- a/utils/replicaset/replicaset_test.go +++ b/utils/replicaset/replicaset_test.go @@ -1078,48 +1078,6 @@ func TestNeedsRestart(t *testing.T) { }) } -func TestIsStillReferenced(t *testing.T) { - newRSWithPodTemplateHash := func(hash string) *appsv1.ReplicaSet { - return &appsv1.ReplicaSet{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - v1alpha1.DefaultRolloutUniqueLabelKey: hash, - }, - }, - } - } - { - status := v1alpha1.RolloutStatus{StableRS: "abc123"} - rs := &appsv1.ReplicaSet{} - assert.False(t, IsStillReferenced(status, rs)) - } - { - status := v1alpha1.RolloutStatus{StableRS: "abc123"} - rs := newRSWithPodTemplateHash("") - assert.False(t, IsStillReferenced(status, rs)) - } - { - status := v1alpha1.RolloutStatus{StableRS: "abc123"} - rs := newRSWithPodTemplateHash("abc123") - assert.True(t, IsStillReferenced(status, rs)) - } - { - status := v1alpha1.RolloutStatus{CurrentPodHash: "abc123"} - rs := newRSWithPodTemplateHash("abc123") - assert.True(t, IsStillReferenced(status, rs)) - } - { - status := v1alpha1.RolloutStatus{BlueGreen: v1alpha1.BlueGreenStatus{ActiveSelector: "abc123"}} - rs := newRSWithPodTemplateHash("abc123") - assert.True(t, IsStillReferenced(status, rs)) - } - { - status := v1alpha1.RolloutStatus{StableRS: "abc123"} - rs := newRSWithPodTemplateHash("def456") - assert.False(t, IsStillReferenced(status, rs)) - } -} - func TestHasScaleDownDeadline(t *testing.T) { { assert.False(t, HasScaleDownDeadline(nil)) From d68e8de2e8bd70c3a4ad6c0195537e08571fb03a Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Wed, 4 Oct 2023 06:14:01 -0700 Subject: [PATCH 67/90] fix: inopportune scaling events would lose some status fields (#3060) fix: inopportune scaling events would result in loss of data Signed-off-by: Jesse Suen --- rollout/sync.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/rollout/sync.go b/rollout/sync.go index a4682fad70..25c0c14813 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -281,10 +281,11 @@ func (c *rolloutContext) syncReplicasOnly() error { if err != nil { return err } + newStatus := c.rollout.Status.DeepCopy() // NOTE: it is possible for newRS to be nil (e.g. when template and replicas changed at same time) if c.rollout.Spec.Strategy.BlueGreen != nil { - previewSvc, activeSvc, err := c.getPreviewAndActiveServices() + _, activeSvc, err := c.getPreviewAndActiveServices() if err != nil { return nil } @@ -293,7 +294,15 @@ func (c *rolloutContext) syncReplicasOnly() error { // so we can abort this resync return err } - return c.syncRolloutStatusBlueGreen(previewSvc, activeSvc) + activeRS, _ := replicasetutil.GetReplicaSetByTemplateHash(c.allRSs, newStatus.BlueGreen.ActiveSelector) + if activeRS != nil { + newStatus.HPAReplicas = activeRS.Status.Replicas + newStatus.AvailableReplicas = activeRS.Status.AvailableReplicas + } else { + // when we do not have an active replicaset, accounting is done on the default rollout selector + newStatus.HPAReplicas = replicasetutil.GetActualReplicaCountForReplicaSets(c.allRSs) + newStatus.AvailableReplicas = replicasetutil.GetAvailableReplicaCountForReplicaSets(c.allRSs) + } } // The controller wants to use the rolloutCanary method to reconcile the rollout if the rollout is not paused. // If there are no scaling events, the rollout should only sync its status @@ -303,9 +312,10 @@ func (c *rolloutContext) syncReplicasOnly() error { // so we can abort this resync return err } - return c.syncRolloutStatusCanary() + newStatus.AvailableReplicas = replicasetutil.GetAvailableReplicaCountForReplicaSets(c.allRSs) + newStatus.HPAReplicas = replicasetutil.GetActualReplicaCountForReplicaSets(c.allRSs) } - return fmt.Errorf("no rollout strategy provided") + return c.persistRolloutStatus(newStatus) } // isScalingEvent checks whether the provided rollout has been updated with a scaling event From 40a80c834471c787873aff9fd1aa9f08e9ae4b9a Mon Sep 17 00:00:00 2001 From: zachaller Date: Mon, 30 Oct 2023 16:13:23 -0500 Subject: [PATCH 68/90] make codegen Signed-off-by: zachaller --- .../rollouts/v1alpha1/openapi_generated.go | 148 ++++-------------- 1 file changed, 31 insertions(+), 117 deletions(-) diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 01b39597e2..f91a313c76 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -52,7 +52,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualService": schema_pkg_apis_rollouts_v1alpha1_AppMeshVirtualService(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Argument": schema_pkg_apis_rollouts_v1alpha1_Argument(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ArgumentValueFrom": schema_pkg_apis_rollouts_v1alpha1_ArgumentValueFrom(ref), - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication": schema_pkg_apis_rollouts_v1alpha1_Authentication(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AwsResourceRef": schema_pkg_apis_rollouts_v1alpha1_AwsResourceRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.BlueGreenStatus": schema_pkg_apis_rollouts_v1alpha1_BlueGreenStatus(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.BlueGreenStrategy": schema_pkg_apis_rollouts_v1alpha1_BlueGreenStrategy(ref), @@ -94,12 +93,12 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MetricResult": schema_pkg_apis_rollouts_v1alpha1_MetricResult(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NewRelicMetric": schema_pkg_apis_rollouts_v1alpha1_NewRelicMetric(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NginxTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_NginxTrafficRouting(ref), - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.OAuth2Config": schema_pkg_apis_rollouts_v1alpha1_OAuth2Config(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ObjectRef": schema_pkg_apis_rollouts_v1alpha1_ObjectRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PauseCondition": schema_pkg_apis_rollouts_v1alpha1_PauseCondition(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PingPongSpec": schema_pkg_apis_rollouts_v1alpha1_PingPongSpec(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PodTemplateMetadata": schema_pkg_apis_rollouts_v1alpha1_PodTemplateMetadata(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PreferredDuringSchedulingIgnoredDuringExecution": schema_pkg_apis_rollouts_v1alpha1_PreferredDuringSchedulingIgnoredDuringExecution(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusAuth": schema_pkg_apis_rollouts_v1alpha1_PrometheusAuth(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusMetric": schema_pkg_apis_rollouts_v1alpha1_PrometheusMetric(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RequiredDuringSchedulingIgnoredDuringExecution": schema_pkg_apis_rollouts_v1alpha1_RequiredDuringSchedulingIgnoredDuringExecution(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RollbackWindowSpec": schema_pkg_apis_rollouts_v1alpha1_RollbackWindowSpec(ref), @@ -1100,35 +1099,6 @@ func schema_pkg_apis_rollouts_v1alpha1_ArgumentValueFrom(ref common.ReferenceCal } } -func schema_pkg_apis_rollouts_v1alpha1_Authentication(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Authentication method", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "sigv4": { - SchemaProps: spec.SchemaProps{ - Description: "Sigv4 Config is the aws SigV4 configuration to use for SigV4 signing if using Amazon Managed Prometheus", - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Sigv4Config"), - }, - }, - "oauth2": { - SchemaProps: spec.SchemaProps{ - Description: "OAuth2 config", - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.OAuth2Config"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.OAuth2Config", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Sigv4Config"}, - } -} - func schema_pkg_apis_rollouts_v1alpha1_AwsResourceRef(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -1835,39 +1805,16 @@ func schema_pkg_apis_rollouts_v1alpha1_DatadogMetric(ref common.ReferenceCallbac Type: []string{"object"}, Properties: map[string]spec.Schema{ "interval": { - SchemaProps: spec.SchemaProps{ - Description: "Interval refers to the Interval time window in Datadog (default: 5m). Not to be confused with the polling rate for the metric.", - Type: []string{"string"}, - Format: "", - }, - }, - "query": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "", }, }, - "queries": { - SchemaProps: spec.SchemaProps{ - Description: "Queries is a map of query_name_as_key: query. You can then use query_name_as_key inside Formula.Used for v2", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "formula": { + "query": { SchemaProps: spec.SchemaProps{ - Description: "Formula refers to the Formula made up of the queries. Only useful with Queries. Used for v2", - Type: []string{"string"}, - Format: "", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "apiVersion": { @@ -1878,6 +1825,7 @@ func schema_pkg_apis_rollouts_v1alpha1_DatadogMetric(ref common.ReferenceCallbac }, }, }, + Required: []string{"query"}, }, }, } @@ -3294,54 +3242,6 @@ func schema_pkg_apis_rollouts_v1alpha1_NginxTrafficRouting(ref common.ReferenceC } } -func schema_pkg_apis_rollouts_v1alpha1_OAuth2Config(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "tokenUrl": { - SchemaProps: spec.SchemaProps{ - Description: "OAuth2 provider token URL", - Type: []string{"string"}, - Format: "", - }, - }, - "clientId": { - SchemaProps: spec.SchemaProps{ - Description: "OAuth2 client ID", - Type: []string{"string"}, - Format: "", - }, - }, - "clientSecret": { - SchemaProps: spec.SchemaProps{ - Description: "OAuth2 client secret", - Type: []string{"string"}, - Format: "", - }, - }, - "scopes": { - SchemaProps: spec.SchemaProps{ - Description: "OAuth2 scopes", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - func schema_pkg_apis_rollouts_v1alpha1_ObjectRef(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3502,6 +3402,27 @@ func schema_pkg_apis_rollouts_v1alpha1_PreferredDuringSchedulingIgnoredDuringExe } } +func schema_pkg_apis_rollouts_v1alpha1_PrometheusAuth(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PrometheusMetric defines the prometheus query to perform canary analysis", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "sigv4": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Sigv4Config"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Sigv4Config"}, + } +} + func schema_pkg_apis_rollouts_v1alpha1_PrometheusMetric(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3525,9 +3446,9 @@ func schema_pkg_apis_rollouts_v1alpha1_PrometheusMetric(ref common.ReferenceCall }, "authentication": { SchemaProps: spec.SchemaProps{ - Description: "Authentication details", + Description: "Sigv4 Config is the aws SigV4 configuration to use for SigV4 signing if using Amazon Managed Prometheus", Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication"), + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusAuth"), }, }, "timeout": { @@ -3568,7 +3489,7 @@ func schema_pkg_apis_rollouts_v1alpha1_PrometheusMetric(ref common.ReferenceCall }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetricHeader"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusAuth", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetricHeader"}, } } @@ -5537,19 +5458,12 @@ func schema_pkg_apis_rollouts_v1alpha1_WebMetric(ref common.ReferenceCallback) c Format: "byte", }, }, - "authentication": { - SchemaProps: spec.SchemaProps{ - Description: "Authentication details", - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication"), - }, - }, }, Required: []string{"url"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Authentication", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetricHeader"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetricHeader"}, } } From c5a45520691371d2e008d57b2780155a8169af22 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Mon, 30 Oct 2023 17:23:34 -0500 Subject: [PATCH 69/90] fix: docs require build.os to be defined (#3133) * fix read the docs build Signed-off-by: zachaller * fix read the docs build Signed-off-by: zachaller --------- Signed-off-by: zachaller --- .readthedocs.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 7b50ab9415..7b5d5d427f 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -4,4 +4,8 @@ mkdocs: fail_on_warning: false python: install: - - requirements: docs/requirements.txt \ No newline at end of file + - requirements: docs/requirements.txt +build: + os: "ubuntu-22.04" + tools: + python: "3.7" \ No newline at end of file From 1dca34e84fa50e27ea0101c71ec6c061ede06626 Mon Sep 17 00:00:00 2001 From: Dennis Nguyen <1750375+dnguy078@users.noreply.github.com> Date: Wed, 1 Nov 2023 07:03:46 -0700 Subject: [PATCH 70/90] fix: istio destionationrule subsets enforcement (#3126) * istio destionationrule subsets enforcement Signed-off-by: Dennis Nguyen * add users Signed-off-by: Dennis Nguyen * add test case for failure cases Signed-off-by: Dennis Nguyen --------- Signed-off-by: Dennis Nguyen --- USERS.md | 1 + rollout/trafficrouting/istio/istio.go | 17 ++++ rollout/trafficrouting/istio/istio_test.go | 110 +++++++++++++++++++++ 3 files changed, 128 insertions(+) diff --git a/USERS.md b/USERS.md index 587548a806..674fd17e26 100644 --- a/USERS.md +++ b/USERS.md @@ -21,6 +21,7 @@ Organizations below are **officially** using Argo Rollouts. Please send a PR wit 1. [Ibotta](https://home.ibotta.com/) 1. [Intuit](https://www.intuit.com/) 1. [New Relic](https://newrelic.com/) +1. [Nextdoor](https://nextdoor.com/) 1. [Nitro](https://www.gonitro.com) 1. [Nozzle](https://nozzle.io) 1. [Opensurvey Inc.](https://opensurvey.co.kr) diff --git a/rollout/trafficrouting/istio/istio.go b/rollout/trafficrouting/istio/istio.go index 70b0cc0e68..d4b136c8ea 100644 --- a/rollout/trafficrouting/istio/istio.go +++ b/rollout/trafficrouting/istio/istio.go @@ -255,6 +255,23 @@ func (r *Reconciler) reconcileVirtualService(obj *unstructured.Unstructured, vsv if err = ValidateHTTPRoutes(r.rollout, vsvcRouteNames, httpRoutes); err != nil { return nil, false, err } + + host, err := r.getDestinationRuleHost() + if err != nil { + return nil, false, err + } + + if host != "" { + var routeDestinations []VirtualServiceRouteDestination + for i, routes := range httpRoutes { + for _, r := range routes.Route { + if r.Destination.Host == host { + routeDestinations = append(routeDestinations, VirtualServiceRouteDestination{Destination: r.Destination, Weight: r.Weight}) + } + } + httpRoutes[i].Route = routeDestinations + } + } } // TLS Routes diff --git a/rollout/trafficrouting/istio/istio_test.go b/rollout/trafficrouting/istio/istio_test.go index ea6474ef5f..20ceb86bed 100644 --- a/rollout/trafficrouting/istio/istio_test.go +++ b/rollout/trafficrouting/istio/istio_test.go @@ -465,6 +465,31 @@ spec: subset: 'canary-subset' weight: 0` +const singleRouteSubsetMultipleDestRuleVsvc = `apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: vsvc + namespace: default +spec: + gateways: + - istio-rollout-gateway + hosts: + - istio-rollout.dev.argoproj.io + http: + - route: + - destination: + host: rollout-service + subset: stable + weight: 100 + - destination: + host: rollout-service + subset: canary + weight: 0 + - destination: + host: additional-service + subset: stable-subset + weight: 20` + const singleRouteTlsVsvc = `apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: @@ -695,6 +720,91 @@ func TestHttpReconcileWeightsBaseCase(t *testing.T) { } } +func TestHttpReconcileMultipleDestRule(t *testing.T) { + ro := rolloutWithDestinationRule() + ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name = "vsvc" + ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes = nil + + dRule1 := unstructuredutil.StrToUnstructuredUnsafe(` +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-destrule + namespace: default +spec: + host: rollout-service + subsets: + - name: stable + - name: canary +`) + dRule2 := unstructuredutil.StrToUnstructuredUnsafe(` +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: additional-istio-destrule + namespace: default +spec: + host: additional-service + subsets: + - name: stable-subset +`) + + obj := unstructuredutil.StrToUnstructuredUnsafe(singleRouteSubsetMultipleDestRuleVsvc) + client := testutil.NewFakeDynamicClient(obj, dRule1, dRule2) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + vsvcRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes + vsvcTLSRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TLSRoutes + vsvcTCPRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TCPRoutes + modifiedObj, _, err := r.reconcileVirtualService(obj, vsvcRoutes, vsvcTLSRoutes, vsvcTCPRoutes, 10) + assert.Nil(t, err) + assert.NotNil(t, modifiedObj) + + httpRoutes := extractHttpRoutes(t, modifiedObj) + + // Assertions + assert.Equal(t, httpRoutes[0].Route[0].Destination.Host, "rollout-service") + assert.Equal(t, httpRoutes[0].Route[1].Destination.Host, "rollout-service") + if httpRoutes[0].Route[0].Destination.Subset == "stable" || httpRoutes[0].Route[1].Destination.Subset == "canary" { + assert.Equal(t, httpRoutes[0].Route[0].Weight, int64(90)) + assert.Equal(t, httpRoutes[0].Route[1].Weight, int64(10)) + } else { + assert.Equal(t, httpRoutes[0].Route[0].Weight, int64(10)) + assert.Equal(t, httpRoutes[0].Route[1].Weight, int64(90)) + } + + assert.Equal(t, httpRoutes[0].Route[2].Destination.Host, "additional-service") + assert.Equal(t, httpRoutes[0].Route[2].Destination.Subset, "stable-subset") + assert.Equal(t, httpRoutes[0].Route[2].Weight, int64(20)) +} + +func TestHttpReconcileInvalidMultipleDestRule(t *testing.T) { + ro := rolloutWithDestinationRule() + // set to invalid destination rule + ro.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule = &v1alpha1.IstioDestinationRule{ + Name: "invalid-destination-rule", + CanarySubsetName: "canary", + StableSubsetName: "stable", + } + + ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name = "vsvc" + ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes = nil + + obj := unstructuredutil.StrToUnstructuredUnsafe(singleRouteSubsetMultipleDestRuleVsvc) + client := testutil.NewFakeDynamicClient(obj) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + vsvcRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes + vsvcTLSRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TLSRoutes + vsvcTCPRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TCPRoutes + _, _, err := r.reconcileVirtualService(obj, vsvcRoutes, vsvcTLSRoutes, vsvcTCPRoutes, 10) + assert.Error(t, err, "expected destination rule not found") +} + func TestHttpReconcileHeaderRouteHostBased(t *testing.T) { ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) obj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvc) From 19b0e9a3aaa55dfc9eaef36d03897905b78397ea Mon Sep 17 00:00:00 2001 From: zachaller Date: Wed, 1 Nov 2023 10:04:14 -0500 Subject: [PATCH 71/90] bump slsa: https://github.com/argoproj/argo-cd/pull/16200 to fix release Signed-off-by: zachaller --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ae80d1f4e0..58ec57f524 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -51,7 +51,7 @@ jobs: id-token: write # for creating OIDC tokens for signing. packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues) # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.8.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0 with: image: quay.io/argoproj/argo-rollouts digest: ${{ needs.controller-image.outputs.image-digest }} @@ -67,7 +67,7 @@ jobs: id-token: write # for creating OIDC tokens for signing. packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues) # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.8.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0 with: image: quay.io/argoproj/kubectl-argo-rollouts digest: ${{ needs.plugin-image.outputs.image-digest }} From 3498a2021412466ae7c4359f82e62ec686578259 Mon Sep 17 00:00:00 2001 From: Justin Marquis <76892343+34fathombelow@users.noreply.github.com> Date: Wed, 1 Nov 2023 13:09:06 -0700 Subject: [PATCH 72/90] chore: upgrade cosign (#3139) Signed-off-by: Justin Marquis Signed-off-by: zachaller --- .github/workflows/image-reuse.yaml | 2 +- .github/workflows/release.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/image-reuse.yaml b/.github/workflows/image-reuse.yaml index a0c157cd3b..10e2df49d5 100644 --- a/.github/workflows/image-reuse.yaml +++ b/.github/workflows/image-reuse.yaml @@ -76,7 +76,7 @@ jobs: - name: Install cosign uses: sigstore/cosign-installer@6e04d228eb30da1757ee4e1dd75a0ec73a653e06 # v3.1.1 with: - cosign-release: 'v2.0.2' + cosign-release: 'v2.2.0' - uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2.2.0 - uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1 # v2.9.1 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 58ec57f524..403aaab60d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -170,9 +170,9 @@ jobs: go-version: ${{ env.GOLANG_VERSION }} - name: Install cosign - uses: sigstore/cosign-installer@204a51a57a74d190b284a0ce69b44bc37201f343 # v3.0.3 + uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2 with: - cosign-release: 'v2.0.2' + cosign-release: 'v2.2.0' - name: Generate SBOM (spdx) id: spdx-builder From 2184a072279c0aca36a6c6fd3840fd7d83593ad5 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 2 Nov 2023 12:50:50 -0500 Subject: [PATCH 73/90] fix: Revert "fix: istio destionationrule subsets enforcement (#3126)" (#3147) Revert "fix: istio destionationrule subsets enforcement (#3126)" This reverts commit 04e11195fb4046e897574478c51fb14692a07578. Signed-off-by: zachaller --- USERS.md | 1 - rollout/trafficrouting/istio/istio.go | 17 ---- rollout/trafficrouting/istio/istio_test.go | 110 --------------------- 3 files changed, 128 deletions(-) diff --git a/USERS.md b/USERS.md index 674fd17e26..587548a806 100644 --- a/USERS.md +++ b/USERS.md @@ -21,7 +21,6 @@ Organizations below are **officially** using Argo Rollouts. Please send a PR wit 1. [Ibotta](https://home.ibotta.com/) 1. [Intuit](https://www.intuit.com/) 1. [New Relic](https://newrelic.com/) -1. [Nextdoor](https://nextdoor.com/) 1. [Nitro](https://www.gonitro.com) 1. [Nozzle](https://nozzle.io) 1. [Opensurvey Inc.](https://opensurvey.co.kr) diff --git a/rollout/trafficrouting/istio/istio.go b/rollout/trafficrouting/istio/istio.go index d4b136c8ea..70b0cc0e68 100644 --- a/rollout/trafficrouting/istio/istio.go +++ b/rollout/trafficrouting/istio/istio.go @@ -255,23 +255,6 @@ func (r *Reconciler) reconcileVirtualService(obj *unstructured.Unstructured, vsv if err = ValidateHTTPRoutes(r.rollout, vsvcRouteNames, httpRoutes); err != nil { return nil, false, err } - - host, err := r.getDestinationRuleHost() - if err != nil { - return nil, false, err - } - - if host != "" { - var routeDestinations []VirtualServiceRouteDestination - for i, routes := range httpRoutes { - for _, r := range routes.Route { - if r.Destination.Host == host { - routeDestinations = append(routeDestinations, VirtualServiceRouteDestination{Destination: r.Destination, Weight: r.Weight}) - } - } - httpRoutes[i].Route = routeDestinations - } - } } // TLS Routes diff --git a/rollout/trafficrouting/istio/istio_test.go b/rollout/trafficrouting/istio/istio_test.go index 20ceb86bed..ea6474ef5f 100644 --- a/rollout/trafficrouting/istio/istio_test.go +++ b/rollout/trafficrouting/istio/istio_test.go @@ -465,31 +465,6 @@ spec: subset: 'canary-subset' weight: 0` -const singleRouteSubsetMultipleDestRuleVsvc = `apiVersion: networking.istio.io/v1alpha3 -kind: VirtualService -metadata: - name: vsvc - namespace: default -spec: - gateways: - - istio-rollout-gateway - hosts: - - istio-rollout.dev.argoproj.io - http: - - route: - - destination: - host: rollout-service - subset: stable - weight: 100 - - destination: - host: rollout-service - subset: canary - weight: 0 - - destination: - host: additional-service - subset: stable-subset - weight: 20` - const singleRouteTlsVsvc = `apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: @@ -720,91 +695,6 @@ func TestHttpReconcileWeightsBaseCase(t *testing.T) { } } -func TestHttpReconcileMultipleDestRule(t *testing.T) { - ro := rolloutWithDestinationRule() - ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name = "vsvc" - ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes = nil - - dRule1 := unstructuredutil.StrToUnstructuredUnsafe(` -apiVersion: networking.istio.io/v1alpha3 -kind: DestinationRule -metadata: - name: istio-destrule - namespace: default -spec: - host: rollout-service - subsets: - - name: stable - - name: canary -`) - dRule2 := unstructuredutil.StrToUnstructuredUnsafe(` -apiVersion: networking.istio.io/v1alpha3 -kind: DestinationRule -metadata: - name: additional-istio-destrule - namespace: default -spec: - host: additional-service - subsets: - - name: stable-subset -`) - - obj := unstructuredutil.StrToUnstructuredUnsafe(singleRouteSubsetMultipleDestRuleVsvc) - client := testutil.NewFakeDynamicClient(obj, dRule1, dRule2) - vsvcLister, druleLister := getIstioListers(client) - r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) - client.ClearActions() - - vsvcRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes - vsvcTLSRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TLSRoutes - vsvcTCPRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TCPRoutes - modifiedObj, _, err := r.reconcileVirtualService(obj, vsvcRoutes, vsvcTLSRoutes, vsvcTCPRoutes, 10) - assert.Nil(t, err) - assert.NotNil(t, modifiedObj) - - httpRoutes := extractHttpRoutes(t, modifiedObj) - - // Assertions - assert.Equal(t, httpRoutes[0].Route[0].Destination.Host, "rollout-service") - assert.Equal(t, httpRoutes[0].Route[1].Destination.Host, "rollout-service") - if httpRoutes[0].Route[0].Destination.Subset == "stable" || httpRoutes[0].Route[1].Destination.Subset == "canary" { - assert.Equal(t, httpRoutes[0].Route[0].Weight, int64(90)) - assert.Equal(t, httpRoutes[0].Route[1].Weight, int64(10)) - } else { - assert.Equal(t, httpRoutes[0].Route[0].Weight, int64(10)) - assert.Equal(t, httpRoutes[0].Route[1].Weight, int64(90)) - } - - assert.Equal(t, httpRoutes[0].Route[2].Destination.Host, "additional-service") - assert.Equal(t, httpRoutes[0].Route[2].Destination.Subset, "stable-subset") - assert.Equal(t, httpRoutes[0].Route[2].Weight, int64(20)) -} - -func TestHttpReconcileInvalidMultipleDestRule(t *testing.T) { - ro := rolloutWithDestinationRule() - // set to invalid destination rule - ro.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule = &v1alpha1.IstioDestinationRule{ - Name: "invalid-destination-rule", - CanarySubsetName: "canary", - StableSubsetName: "stable", - } - - ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name = "vsvc" - ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes = nil - - obj := unstructuredutil.StrToUnstructuredUnsafe(singleRouteSubsetMultipleDestRuleVsvc) - client := testutil.NewFakeDynamicClient(obj) - vsvcLister, druleLister := getIstioListers(client) - r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) - client.ClearActions() - - vsvcRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes - vsvcTLSRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TLSRoutes - vsvcTCPRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TCPRoutes - _, _, err := r.reconcileVirtualService(obj, vsvcRoutes, vsvcTLSRoutes, vsvcTCPRoutes, 10) - assert.Error(t, err, "expected destination rule not found") -} - func TestHttpReconcileHeaderRouteHostBased(t *testing.T) { ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) obj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvc) From 79fbb6075bdf8698eb5dc53a6e6fe097a0bdf5ca Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Mon, 4 Dec 2023 09:32:53 -0600 Subject: [PATCH 74/90] fix: rollouts getting stuck due to bad rs informer updates (#3200) * fix: for rollouts getting stuck due to bad rs informer updates Signed-off-by: Zach Aller * fix error msg Signed-off-by: Zach Aller * change logic Signed-off-by: Zach Aller * error fmt Signed-off-by: Zach Aller * change if logic Signed-off-by: Zach Aller * add test Signed-off-by: Zach Aller * cleanup test Signed-off-by: Zach Aller * cleanup test Signed-off-by: Zach Aller * do not double call Signed-off-by: Zach Aller --------- Signed-off-by: Zach Aller --- rollout/replicaset.go | 20 +++++++++++----- rollout/replicaset_test.go | 47 ++++++++++++++++++++++++++++++++++---- rollout/sync.go | 18 ++++++++++++--- 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/rollout/replicaset.go b/rollout/replicaset.go index 7d9a71f62a..401e1b579d 100644 --- a/rollout/replicaset.go +++ b/rollout/replicaset.go @@ -35,9 +35,13 @@ func (c *rolloutContext) removeScaleDownDelay(rs *appsv1.ReplicaSet) error { } patch := fmt.Sprintf(removeScaleDownAtAnnotationsPatch, v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey) _, err := c.kubeclientset.AppsV1().ReplicaSets(rs.Namespace).Patch(ctx, rs.Name, patchtypes.JSONPatchType, []byte(patch), metav1.PatchOptions{}) - if err == nil { - c.log.Infof("Removed '%s' annotation from RS '%s'", v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, rs.Name) - c.replicaSetInformer.GetIndexer().Update(rs) + if err != nil { + return fmt.Errorf("error removing scale-down-deadline annotation from RS '%s': %w", rs.Name, err) + } + c.log.Infof("Removed '%s' annotation from RS '%s'", v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, rs.Name) + err = c.replicaSetInformer.GetIndexer().Update(rs) + if err != nil { + return fmt.Errorf("error updating replicaset informer in removeScaleDownDelay: %w", err) } return err } @@ -60,9 +64,13 @@ func (c *rolloutContext) addScaleDownDelay(rs *appsv1.ReplicaSet, scaleDownDelay deadline := timeutil.MetaNow().Add(scaleDownDelaySeconds).UTC().Format(time.RFC3339) patch := fmt.Sprintf(addScaleDownAtAnnotationsPatch, v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, deadline) rs, err := c.kubeclientset.AppsV1().ReplicaSets(rs.Namespace).Patch(ctx, rs.Name, patchtypes.JSONPatchType, []byte(patch), metav1.PatchOptions{}) - if err == nil { - c.log.Infof("Set '%s' annotation on '%s' to %s (%s)", v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, rs.Name, deadline, scaleDownDelaySeconds) - c.replicaSetInformer.GetIndexer().Update(rs) + if err != nil { + return fmt.Errorf("error adding scale-down-deadline annotation to RS '%s': %w", rs.Name, err) + } + c.log.Infof("Set '%s' annotation on '%s' to %s (%s)", v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, rs.Name, deadline, scaleDownDelaySeconds) + err = c.replicaSetInformer.GetIndexer().Update(rs) + if err != nil { + return fmt.Errorf("error updating replicaset informer in addScaleDownDelay: %w", err) } return err } diff --git a/rollout/replicaset_test.go b/rollout/replicaset_test.go index 262bd23dd7..d93fa7c546 100644 --- a/rollout/replicaset_test.go +++ b/rollout/replicaset_test.go @@ -1,6 +1,7 @@ package rollout import ( + "fmt" "strconv" "testing" "time" @@ -134,8 +135,9 @@ func TestReconcileNewReplicaSet(t *testing.T) { abortScaleDownAnnotated bool abortScaleDownDelayPassed bool expectedNewReplicas int + failRSUpdate bool + abort bool }{ - { name: "New Replica Set matches rollout replica: No scale", rolloutReplicas: 10, @@ -163,6 +165,7 @@ func TestReconcileNewReplicaSet(t *testing.T) { newReplicas: 10, // ScaleDownOnAbort: true, abortScaleDownDelaySeconds: 5, + abort: true, abortScaleDownAnnotated: true, abortScaleDownDelayPassed: true, scaleExpected: true, @@ -174,6 +177,7 @@ func TestReconcileNewReplicaSet(t *testing.T) { newReplicas: 8, // ScaleDownOnAbort: true, abortScaleDownDelaySeconds: 5, + abort: true, abortScaleDownAnnotated: true, abortScaleDownDelayPassed: false, scaleExpected: false, @@ -184,10 +188,20 @@ func TestReconcileNewReplicaSet(t *testing.T) { rolloutReplicas: 10, newReplicas: 10, abortScaleDownDelaySeconds: 5, + abort: true, abortScaleDownAnnotated: false, scaleExpected: false, expectedNewReplicas: 0, }, + { + name: "Fail to update RS: No scale and add default annotation", + rolloutReplicas: 10, + newReplicas: 10, + scaleExpected: false, + failRSUpdate: true, + abort: true, + abortScaleDownDelaySeconds: -1, + }, } for i := range tests { test := tests[i] @@ -199,6 +213,12 @@ func TestReconcileNewReplicaSet(t *testing.T) { fake := fake.Clientset{} k8sfake := k8sfake.Clientset{} + if test.failRSUpdate { + k8sfake.PrependReactor("patch", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { + return true, &appsv1.ReplicaSet{}, fmt.Errorf("should not patch replica set") + }) + } + f := newFixture(t) defer f.Close() f.objects = append(f.objects, rollout) @@ -226,15 +246,22 @@ func TestReconcileNewReplicaSet(t *testing.T) { rollout: rollout, }, } - roCtx.enqueueRolloutAfter = func(obj interface{}, duration time.Duration) {} + roCtx.enqueueRolloutAfter = func(obj any, duration time.Duration) {} + + rollout.Status.Abort = test.abort + roCtx.stableRS.Status.AvailableReplicas = int32(test.rolloutReplicas) + rollout.Spec.Strategy = v1alpha1.RolloutStrategy{ + BlueGreen: &v1alpha1.BlueGreenStrategy{ + AbortScaleDownDelaySeconds: &test.abortScaleDownDelaySeconds, + }, + } + if test.abortScaleDownDelaySeconds > 0 { - rollout.Status.Abort = true rollout.Spec.Strategy = v1alpha1.RolloutStrategy{ BlueGreen: &v1alpha1.BlueGreenStrategy{ AbortScaleDownDelaySeconds: &test.abortScaleDownDelaySeconds, }, } - if test.abortScaleDownAnnotated { var deadline string if test.abortScaleDownDelayPassed { @@ -246,7 +273,19 @@ func TestReconcileNewReplicaSet(t *testing.T) { } } + if test.abortScaleDownDelaySeconds < 0 { + rollout.Spec.Strategy = v1alpha1.RolloutStrategy{ + BlueGreen: &v1alpha1.BlueGreenStrategy{ + AbortScaleDownDelaySeconds: nil, + }, + } + } + scaled, err := roCtx.reconcileNewReplicaSet() + if test.failRSUpdate { + assert.Error(t, err) + return + } if err != nil { t.Errorf("unexpected error: %v", err) return diff --git a/rollout/sync.go b/rollout/sync.go index 25c0c14813..2baeac1698 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -91,7 +91,10 @@ func (c *rolloutContext) syncReplicaSetRevision() (*appsv1.ReplicaSet, error) { return nil, fmt.Errorf("error updating replicaset revision: %v", err) } c.log.Infof("Synced revision on ReplicaSet '%s' to '%s'", rs.Name, newRevision) - c.replicaSetInformer.GetIndexer().Update(rs) + err = c.replicaSetInformer.GetIndexer().Update(rs) + if err != nil { + return nil, fmt.Errorf("error updating replicaset informer in syncReplicaSetRevision: %w", err) + } return rs, nil } @@ -372,12 +375,21 @@ func (c *rolloutContext) scaleReplicaSet(rs *appsv1.ReplicaSet, newScale int32, if fullScaleDown && !c.shouldDelayScaleDownOnAbort() { delete(rsCopy.Annotations, v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey) } + rs, err = c.kubeclientset.AppsV1().ReplicaSets(rsCopy.Namespace).Update(ctx, rsCopy, metav1.UpdateOptions{}) - if err == nil && sizeNeedsUpdate { + if err != nil { + return scaled, rs, fmt.Errorf("error updating replicaset %s: %w", rs.Name, err) + } + err = c.replicaSetInformer.GetIndexer().Update(rs) + if err != nil { + err = fmt.Errorf("error updating replicaset informer in scaleReplicaSet: %w", err) + return scaled, rs, err + } + + if sizeNeedsUpdate { scaled = true revision, _ := replicasetutil.Revision(rs) c.recorder.Eventf(rollout, record.EventOptions{EventReason: conditions.ScalingReplicaSetReason}, conditions.ScalingReplicaSetMessage, scalingOperation, rs.Name, revision, oldScale, newScale) - c.replicaSetInformer.GetIndexer().Update(rs) } } return scaled, rs, err From c7f7d1eaa9dfab501c768e7869ad7d2d0338c489 Mon Sep 17 00:00:00 2001 From: Linus Ekman <46067241+linus345@users.noreply.github.com> Date: Mon, 4 Dec 2023 17:06:32 +0100 Subject: [PATCH 75/90] build(deps): always resolve momentjs version 2.29.4 (#3182) Before this change both version 2.29.1 and version 2.29.4 of momentjs were brougth in. The bump from v2.29.1 -> v2.29.4 remediates two CVEs: CVE-2022-24785 [1] and CVE-2022-31129 [2]. The most notable change comes with the bump from v2.29.1 -> v2.29.2 which introduces a breaking change to remediate CVE-2022-24785: Forward slash and backward slash is no longer allowed in locale names. Locales containing either of those characters will not be loaded from the filesystem any longer [3]. Other than that it looks like there's only patch fixes which can be seen in the full changelog [4]. [1] https://github.com/moment/moment/security/advisories/GHSA-8hfj-j24r-96c4 [2] https://github.com/moment/moment/security/advisories/GHSA-wc69-rhjr-hc9g [3] https://gist.github.com/ichernev/1904b564f6679d9aac1ae08ce13bc45c [4] https://github.com/moment/moment/blob/536ad0c348f2f99009755698f491080757a48221/CHANGELOG.md Signed-off-by: Linus Ekman --- ui/package.json | 3 ++- ui/yarn.lock | 7 +------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/ui/package.json b/ui/package.json index fac0a758f3..e7d8217969 100644 --- a/ui/package.json +++ b/ui/package.json @@ -71,6 +71,7 @@ "webpack-merge": "^5.7.3" }, "resolutions": { - "@types/react": "16.9.3" + "@types/react": "16.9.3", + "moment": "2.29.4" } } diff --git a/ui/yarn.lock b/ui/yarn.lock index 29f5446d37..447790e646 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -7973,12 +7973,7 @@ moment-timezone@^0.5.33: dependencies: moment ">= 2.9.0" -"moment@>= 2.9.0", moment@^2.20.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" - integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== - -moment@^2.29.4: +moment@2.29.4, "moment@>= 2.9.0", moment@^2.20.1, moment@^2.29.4: version "2.29.4" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== From d30e69cc4c0e7c2625cfff43443c98b64b4dd885 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 5 Dec 2023 16:25:36 +0200 Subject: [PATCH 76/90] feat: release-1.6 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index bc80560fad..9c6d6293b1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.0 +1.6.1 From 9c756f9dd2c4b32128128a68a4ca3e5688a50438 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 5 Dec 2023 16:36:43 +0200 Subject: [PATCH 77/90] feat: release-1.6 --- .github/workflows/docker-publish.yml | 120 ++++++---- .github/workflows/release.yaml | 339 +++++++++------------------ 2 files changed, 183 insertions(+), 276 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 1a51e2a485..7322aab050 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -3,18 +3,12 @@ name: Docker on: push: branches: - - master + # - master # commented due to Codefresh convention - release-* # Run tests for any PRs. pull_request: -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -permissions: {} - jobs: set-vars: permissions: @@ -26,68 +20,98 @@ jobs: platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} steps: + - name: Checkout + uses: actions/checkout@v3.1.0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Docker meta (controller) id: controller-meta uses: docker/metadata-action@v4 with: images: | - quay.io/argoproj/argo-rollouts + quay.io/codefresh/argo-rollouts + # ghcr.io/codefresh-io/argo-rollouts tags: | - type=ref,event=branch,enable=${{ github.ref != 'refs/heads/master'}} - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} + type=ref,event=branch + # commented due to Codefresh convention + # flavor: | + # latest=${{ github.ref == 'refs/heads/master' }} - name: Docker meta (plugin) id: plugin-meta uses: docker/metadata-action@v4 with: images: | - quay.io/argoproj/kubectl-argo-rollouts + quay.io/codefresh/kubectl-argo-rollouts + # ghcr.io/codefresh-io/kubectl-argo-rollouts tags: | - type=ref,event=branch,enable=${{ github.ref != 'refs/heads/master'}} - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} + type=ref,event=branch + # commented due to Codefresh convention + # flavor: | + # latest=${{ github.ref == 'refs/heads/master' }} + + # - name: Login to GitHub Container Registry + # if: github.event_name != 'pull_request' + # uses: docker/login-action@v1 + # with: + # registry: ghcr.io + # username: ${{ github.repository_owner }} + # password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to Quay.io + if: github.event_name != 'pull_request' + uses: docker/login-action@v2 + with: + registry: quay.io + username: ${{ secrets.QUAY_USERNAME }} + password: ${{ secrets.QUAY_ROBOT_TOKEN }} # avoid building linux/arm64 for PRs since it takes so long - name: Set Platform Matrix id: platform-matrix run: | PLATFORM_MATRIX=linux/amd64 - if [[ "${{ github.event_name }}" == "push" || "${{ contains(github.event.pull_request.labels.*.name, 'test-arm-image') }}" == "true" ]] - then + if [ ${{ github.event_name != 'pull_request' }} = true ]; then PLATFORM_MATRIX=$PLATFORM_MATRIX,linux/arm64 fi echo "platform-matrix=$PLATFORM_MATRIX" >> $GITHUB_OUTPUT - build-and-push-controller-image: - needs: [set-vars] - permissions: - contents: read - packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags - id-token: write # for creating OIDC tokens for signing. - uses: ./.github/workflows/image-reuse.yaml - with: - quay_image_name: ${{ needs.set-vars.outputs.controller-meta-tags }} - # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) - go-version: '1.20' - platforms: ${{ needs.set-vars.outputs.platforms }} - push: ${{ github.event_name != 'pull_request' }} - secrets: - quay_username: ${{ secrets.QUAY_USERNAME }} - quay_password: ${{ secrets.QUAY_ROBOT_TOKEN }} + - name: Build and push (controller-image) + uses: docker/build-push-action@v3 + with: + platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.controller-meta.outputs.tags }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache - build-and-push-plugin-image: - needs: [set-vars] - permissions: - contents: read - packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags - id-token: write # for creating OIDC tokens for signing. - uses: ./.github/workflows/image-reuse.yaml - with: - quay_image_name: ${{ needs.set-vars.outputs.plugin-meta-tags }} - # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) - go-version: '1.20' - platforms: ${{ needs.set-vars.outputs.platforms }} - push: ${{ github.event_name != 'pull_request' }} - target: kubectl-argo-rollouts - secrets: - quay_username: ${{ secrets.QUAY_USERNAME }} - quay_password: ${{ secrets.QUAY_ROBOT_TOKEN }} + - name: Build and push (plugin-image) + uses: docker/build-push-action@v3 + with: + target: kubectl-argo-rollouts + platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.plugin-meta.outputs.tags }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + + # Temp fix + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 403aaab60d..2d050379fd 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,114 +1,141 @@ name: Release + on: - push: - tags: - - 'v*' + workflow_dispatch: + inputs: + tag: + description: Git tag to build release from + required: true + update_stable_tag: + description: 'Update stable tag' + required: true + type: boolean + default: 'false' +permissions: + contents: read -permissions: {} +jobs: + release-images: + runs-on: ubuntu-latest -env: - GOLANG_VERSION: '1.20' # Note: go-version must also be set in job controller-image.with.go-version & plugin-image.with.go-version. + steps: + - name: Checkout + uses: actions/checkout@v3.1.0 + with: + ref: ${{ github.event.inputs.tag }} -jobs: - controller-image: - permissions: - contents: read - packages: write # Required and used to push images to `ghcr.io` if used. - id-token: write # For creating OIDC tokens for signing. - uses: ./.github/workflows/image-reuse.yaml - with: - quay_image_name: quay.io/argoproj/argo-rollouts:${{ github.ref_name }} - # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) - go-version: '1.20' - platforms: linux/amd64,linux/arm64 - push: true - secrets: - quay_username: ${{ secrets.QUAY_USERNAME }} - quay_password: ${{ secrets.QUAY_ROBOT_TOKEN }} + - name: Get SHA + id: get-sha + run: echo "::set-output name=sha::$(git log -1 --format='%H')" - plugin-image: - permissions: - contents: read - packages: write # Required and used to push images to `ghcr.io` if used. - id-token: write # For creating OIDC tokens for signing. - uses: ./.github/workflows/image-reuse.yaml - with: - quay_image_name: quay.io/argoproj/kubectl-argo-rollouts:${{ github.ref_name }} - # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) - go-version: '1.20' - platforms: linux/amd64,linux/arm64 - push: true - target: kubectl-argo-rollouts - secrets: - quay_username: ${{ secrets.QUAY_USERNAME }} - quay_password: ${{ secrets.QUAY_ROBOT_TOKEN }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + config-inline: | + [worker.oci] + gc = false - controller-image-provenance: - needs: - - controller-image - permissions: - actions: read # for detecting the Github Actions environment. - id-token: write # for creating OIDC tokens for signing. - packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues) - # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0 - with: - image: quay.io/argoproj/argo-rollouts - digest: ${{ needs.controller-image.outputs.image-digest }} - secrets: - registry-username: ${{ secrets.QUAY_USERNAME }} - registry-password: ${{ secrets.QUAY_ROBOT_TOKEN }} + - name: Print Disk Usage + run: | + df -ah + docker buildx du - plugin-image-provenance: - needs: - - plugin-image - permissions: - actions: read # for detecting the Github Actions environment. - id-token: write # for creating OIDC tokens for signing. - packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues) - # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0 - with: - image: quay.io/argoproj/kubectl-argo-rollouts - digest: ${{ needs.plugin-image.outputs.image-digest }} - secrets: - registry-username: ${{ secrets.QUAY_USERNAME }} - registry-password: ${{ secrets.QUAY_ROBOT_TOKEN }} + - name: Docker meta (controller) + id: controller-meta + uses: docker/metadata-action@v4 + with: + images: | + quay.io/codefresh/argo-rollouts + # ghcr.io/codefresh-io/argo-rollouts + tags: | + type=semver,pattern={{version}},prefix=v,value=${{ github.event.inputs.tag }} + flavor: | + latest=false + + - name: Docker meta (plugin) + id: plugin-meta + uses: docker/metadata-action@v4 + with: + images: | + quay.io/codefresh/kubectl-argo-rollouts + # ghcr.io/codefresh-io/kubectl-argo-rollouts + tags: | + type=semver,pattern={{version}},prefix=v,value=${{ github.event.inputs.tag }} + flavor: | + latest=false + + # - name: Login to GitHub Container Registry + # if: github.event_name != 'pull_request' + # uses: docker/login-action@v2 + # with: + # registry: ghcr.io + # username: ${{ github.repository_owner }} + # password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to Quay.io + if: github.event_name != 'pull_request' + uses: docker/login-action@v2 + with: + registry: quay.io + username: ${{ secrets.QUAY_USERNAME }} + password: ${{ secrets.QUAY_ROBOT_TOKEN }} + - name: Build and push (controller-image) + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4.0.0 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.controller-meta.outputs.tags }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + + - name: Build and push (plugin-image) + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4.0.0 + with: + context: . + target: kubectl-argo-rollouts + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.plugin-meta.outputs.tags }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + + # Temp fix + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache release-artifacts: permissions: contents: write # for softprops/action-gh-release to create GitHub release runs-on: ubuntu-latest - outputs: - hashes: ${{ steps.hash.outputs.hashes }} + needs: release-images steps: - name: Checkout - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@v3.1.0 with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} + ref: ${{ github.event.inputs.tag }} - name: Setup Golang - uses: actions/setup-go@v4.1.0 # v4.0.1 + uses: actions/setup-go@v4 with: - go-version: ${{ env.GOLANG_VERSION }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2.2.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1 # v2.9.1 + go-version: 1.19 - name: Generate release artifacts run: | make release-plugins - make checksums - make manifests IMAGE_TAG=${{ github.ref_name }} + make manifests IMAGE_TAG=${{ github.event.inputs.tag }} - name: Draft release - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 + uses: softprops/action-gh-release@v1 with: tag_name: ${{ github.event.inputs.tag }} draft: true @@ -116,156 +143,12 @@ jobs: dist/kubectl-argo-rollouts-linux-amd64 dist/kubectl-argo-rollouts-linux-arm64 dist/kubectl-argo-rollouts-darwin-amd64 - dist/kubectl-argo-rollouts-darwin-arm64 dist/kubectl-argo-rollouts-windows-amd64 - dist/argo-rollouts-checksums.txt manifests/dashboard-install.yaml manifests/install.yaml manifests/namespace-install.yaml manifests/notifications-install.yaml docs/features/kustomize/rollout_cr_schema.json - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Generate hashes for provenance - id: hash - run: | - echo "hashes=$(sha256sum ./dist/kubectl-argo-rollouts-* ./manifests/*.yaml | base64 -w0)" >> "$GITHUB_OUTPUT" - - - release-artifacts-provenance: - needs: - - release-artifacts - permissions: - actions: read # for detecting the Github Actions environment - id-token: write # Needed for provenance signing and ID - contents: write # Needed for release uploads - # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.8.0 - with: - base64-subjects: "${{ needs.release-artifacts.outputs.hashes }}" - provenance-name: "argo-rollouts.intoto.jsonl" - upload-assets: true - draft-release: true - - generate-sbom: - name: Create Sbom and sign assets - needs: - - release-artifacts - - release-artifacts-provenance - permissions: - contents: write # Needed for release uploads - id-token: write # Needed for signing Sbom - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.3.0 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Golang - uses: actions/setup-go@v4.1.0 # v4.0.0 - with: - go-version: ${{ env.GOLANG_VERSION }} - - - name: Install cosign - uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2 - with: - cosign-release: 'v2.2.0' - - - name: Generate SBOM (spdx) - id: spdx-builder - env: - # defines the spdx/spdx-sbom-generator version to use. - SPDX_GEN_VERSION: v0.0.13 - # defines the sigs.k8s.io/bom version to use. - SIGS_BOM_VERSION: v0.2.1 - # comma delimited list of project relative folders to inspect for package - # managers (gomod, yarn, npm). - PROJECT_FOLDERS: ".,./ui" - # full qualified name of the container image to be inspected - CONTAINER_IMAGE: quay.io/argoproj/argo-rollouts:${{ github.event.inputs.tag }} - - run: | - yarn install --cwd ./ui - go install github.com/spdx/spdx-sbom-generator/cmd/generator@$SPDX_GEN_VERSION - go install sigs.k8s.io/bom/cmd/bom@$SIGS_BOM_VERSION - - # Generate SPDX for project dependencies analyzing package managers - for folder in $(echo $PROJECT_FOLDERS | sed "s/,/ /g") - do - generator -p $folder -o /tmp - done - - # Generate SPDX for binaries analyzing the container image - if [[ ! -z CONTAINER_IMAGE ]]; then - bom generate -o /tmp/bom-docker-image.spdx -i $CONTAINER_IMAGE - fi - - cd /tmp && tar -zcf sbom.tar.gz *.spdx - - - name: Sign SBOM - run: | - cosign sign-blob \ - --output-certificate=/tmp/sbom.tar.gz.pem \ - --output-signature=/tmp/sbom.tar.gz.sig \ - --yes \ /tmp/sbom.tar.gz - - - name: Upload SBOM and signature assets - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref_name }} - draft: true - files: | - /tmp/sbom.tar.* - - post-release: - needs: - - release-artifacts - - generate-sbom - permissions: - contents: write # Needed to push commit to update stable tag - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.3.0 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Git author information - run: | - set -ue - git config --global user.email 'ci@argoproj.com' - git config --global user.name 'CI' - - - name: Check if tag is the latest version and not a pre-release - run: | - set -xue - # Fetch all tag information - git fetch --prune --tags --force - - LATEST_TAG=$(git -c 'versionsort.suffix=-rc' tag --list --sort=version:refname | tail -n1) - - PRE_RELEASE=false - # Check if latest tag is a pre-release - if echo $LATEST_TAG | grep -E -- '-rc[0-9]+$';then - PRE_RELEASE=true - fi - - # Ensure latest tag matches github.ref_name & not a pre-release - if [[ $LATEST_TAG == ${{ github.ref_name }} ]] && [[ $PRE_RELEASE != 'true' ]];then - echo "TAG_STABLE=true" >> $GITHUB_ENV - else - echo "TAG_STABLE=false" >> $GITHUB_ENV - fi - - - name: Update stable tag to latest version - run: | - git tag -f stable ${{ github.ref_name }} - git push -f origin stable - if: ${{ env.TAG_STABLE == 'true' }} From 2675841bfb579495b7d062c359350ef75ee28dc8 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Fri, 12 Jan 2024 21:58:22 +0200 Subject: [PATCH 78/90] feat: release-1.6 logs for priceline --- controller/controller.go | 2 +- rollout/controller.go | 8 +++++++- rollout/sync.go | 6 ++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index afe4bc769b..4a83e7341a 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -85,7 +85,7 @@ const ( DefaultIngressThreads = 10 // DefaultLeaderElect is the default true leader election should be enabled - DefaultLeaderElect = true + DefaultLeaderElect = false // DefaultLeaderElectionLeaseDuration is the default time in seconds that non-leader candidates will wait to force acquire leadership DefaultLeaderElectionLeaseDuration = 15 * time.Second diff --git a/rollout/controller.go b/rollout/controller.go index 75601661ca..95dbe87437 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -234,6 +234,8 @@ func NewController(cfg ControllerConfig) *Controller { controller.enqueueRollout(obj) ro := unstructuredutil.ObjectToRollout(obj) if ro != nil { + logCtx := logutil.WithRollout(ro) + logCtx.Info("rollout enqueue due to add event") if cfg.Recorder != nil { cfg.Recorder.Eventf(ro, record.EventOptions{ EventType: corev1.EventTypeNormal, @@ -258,12 +260,16 @@ func NewController(cfg ControllerConfig) *Controller { controller.IstioController.EnqueueDestinationRule(key) } } + if newRollout != nil { + logCtx := logutil.WithRollout(newRollout) + logCtx.Info("rollout enqueue due to update event") + } controller.enqueueRollout(new) }, DeleteFunc: func(obj interface{}) { if ro := unstructuredutil.ObjectToRollout(obj); ro != nil { logCtx := logutil.WithRollout(ro) - logCtx.Info("rollout deleted") + logCtx.Info("rollout enqueue due to delete event") controller.metricsServer.Remove(ro.Namespace, ro.Name, logutil.RolloutKey) // Rollout is deleted, queue up the referenced Service and/or DestinationRules so // that the rollouts-pod-template-hash can be cleared from each diff --git a/rollout/sync.go b/rollout/sync.go index 2baeac1698..100f318cf6 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -828,11 +828,13 @@ func (c *rolloutContext) requeueStuckRollout(newStatus v1alpha1.RolloutStatus) t // Make it ratelimited so we stay on the safe side, eventually the Deployment should // transition either to a Complete or to a TimedOut condition. if after < time.Second { - c.log.Infof("Queueing up Rollout for a progress check now") + logCtx := logutil.WithRollout(c.rollout) + logCtx.Info("rollout enqueue due to stuck event") c.enqueueRollout(c.rollout) return time.Duration(0) } - c.log.Infof("Queueing up rollout for a progress after %ds", int(after.Seconds())) + logCtx := logutil.WithRollout(c.rollout) + logCtx.Info("Queueing up rollout for a progress after %ds", int(after.Seconds())) // Add a second to avoid milliseconds skew in AddAfter. // See https://github.com/kubernetes/kubernetes/issues/39785#issuecomment-279959133 for more info. c.enqueueRolloutAfter(c.rollout, after+time.Second) From 82d80382bd402454d2b211dfe64ecd543e58d22f Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Fri, 12 Jan 2024 22:06:36 +0200 Subject: [PATCH 79/90] feat: release-1.6 logs for priceline --- rollout/sync.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollout/sync.go b/rollout/sync.go index 100f318cf6..5d07958dc1 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -834,7 +834,7 @@ func (c *rolloutContext) requeueStuckRollout(newStatus v1alpha1.RolloutStatus) t return time.Duration(0) } logCtx := logutil.WithRollout(c.rollout) - logCtx.Info("Queueing up rollout for a progress after %ds", int(after.Seconds())) + logCtx.Infof("Queueing up rollout for a progress after %ds", int(after.Seconds())) // Add a second to avoid milliseconds skew in AddAfter. // See https://github.com/kubernetes/kubernetes/issues/39785#issuecomment-279959133 for more info. c.enqueueRolloutAfter(c.rollout, after+time.Second) From 511f4342b719a7759af9adba2660b4c091b46182 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Fri, 12 Jan 2024 22:29:32 +0200 Subject: [PATCH 80/90] feat: release-1.6 logs for priceline --- rollout/context.go | 3 +++ rollout/pause.go | 5 +++++ rollout/replicaset.go | 7 +++++++ rollout/service.go | 2 ++ rollout/trafficrouting.go | 3 +++ 5 files changed, 20 insertions(+) diff --git a/rollout/context.go b/rollout/context.go index f8fa5b5f03..1f1005e76f 100644 --- a/rollout/context.go +++ b/rollout/context.go @@ -1,6 +1,7 @@ package rollout import ( + logutil "github.com/argoproj/argo-rollouts/utils/log" "time" log "github.com/sirupsen/logrus" @@ -56,6 +57,8 @@ func (c *rolloutContext) reconcile() error { err := c.getRolloutValidationErrors() if err != nil { if vErr, ok := err.(*field.Error); ok { + logCtx := logutil.WithRollout(c.rollout) + logCtx.Info("rollout enqueue due reconcile error") // We want to frequently requeue rollouts with InvalidSpec errors, because the error // condition might be timing related (e.g. the Rollout was applied before the Service). c.enqueueRolloutAfter(c.rollout, 20*time.Second) diff --git a/rollout/pause.go b/rollout/pause.go index 25ae24c3ba..3f1c4a2570 100644 --- a/rollout/pause.go +++ b/rollout/pause.go @@ -1,6 +1,7 @@ package rollout import ( + logutil "github.com/argoproj/argo-rollouts/utils/log" "time" log "github.com/sirupsen/logrus" @@ -209,6 +210,10 @@ func (c *rolloutContext) checkEnqueueRolloutDuringWait(startTime metav1.Time, du if nextResync.After(expiredTime) && expiredTime.After(now.Time) { timeRemaining := expiredTime.Sub(now.Time) c.log.Infof("Enqueueing Rollout in %s seconds", timeRemaining.String()) + + logCtx := logutil.WithRollout(c.rollout) + logCtx.Info("rollout enqueue during wait") + c.enqueueRolloutAfter(c.rollout, timeRemaining) } } diff --git a/rollout/replicaset.go b/rollout/replicaset.go index 401e1b579d..70a190d5c8 100644 --- a/rollout/replicaset.go +++ b/rollout/replicaset.go @@ -3,6 +3,7 @@ package rollout import ( "context" "fmt" + logutil "github.com/argoproj/argo-rollouts/utils/log" "sort" "time" @@ -150,6 +151,8 @@ func (c *rolloutContext) reconcileNewReplicaSet() (bool, error) { c.log.Infof("RS '%s' has not reached the scaleDownTime", c.newRS.Name) remainingTime := scaleDownAt.Sub(now.Time) if remainingTime < c.resyncPeriod { + logCtx := logutil.WithRollout(c.rollout) + logCtx.Info("rollout enqueue due to scaleDownDelay") c.enqueueRolloutAfter(c.rollout, remainingTime) return false, nil } @@ -284,6 +287,8 @@ func (c *rolloutContext) scaleDownDelayHelper(rs *appsv1.ReplicaSet, annotatione if err != nil { return annotationedRSs, desiredReplicaCount, err } + logCtx := logutil.WithRollout(c.rollout) + logCtx.Info("rollout enqueue due to scaleDownDelay v2") c.enqueueRolloutAfter(c.rollout, scaleDownDelaySeconds) } } else if replicasetutil.HasScaleDownDeadline(rs) { @@ -297,6 +302,8 @@ func (c *rolloutContext) scaleDownDelayHelper(rs *appsv1.ReplicaSet, annotatione } else if remainingTime != nil { c.log.Infof("RS '%s' has not reached the scaleDownTime", rs.Name) if *remainingTime < c.resyncPeriod { + logCtx := logutil.WithRollout(c.rollout) + logCtx.Info("rollout enqueue due to scaleDownDelay v3") c.enqueueRolloutAfter(c.rollout, *remainingTime) } desiredReplicaCount = rolloutReplicas diff --git a/rollout/service.go b/rollout/service.go index 69739b9315..097f4160bf 100644 --- a/rollout/service.go +++ b/rollout/service.go @@ -172,6 +172,8 @@ func (c *rolloutContext) awsVerifyTargetGroups(svc *corev1.Service) error { } if !verifyRes.Verified { c.recorder.Warnf(c.rollout, record.EventOptions{EventReason: conditions.TargetGroupUnverifiedReason}, conditions.TargetGroupUnverifiedRegistrationMessage, svc.Name, tgb.Spec.TargetGroupARN, verifyRes.EndpointsRegistered, verifyRes.EndpointsTotal) + logCtx := logutil.WithRollout(c.rollout) + logCtx.Info("rollout enqueue due to awsVerifyTargetGroups") c.enqueueRolloutAfter(c.rollout, defaults.GetRolloutVerifyRetryInterval()) return nil } diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index a87e31a9e8..cc1e552d7c 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -2,6 +2,7 @@ package rollout import ( "fmt" + logutil "github.com/argoproj/argo-rollouts/utils/log" "reflect" "strconv" "strings" @@ -283,6 +284,8 @@ func (c *rolloutContext) reconcileTrafficRouting() error { c.log.Infof("Desired weight (stepIdx: %s) %d verified", indexString, desiredWeight) } else { c.log.Infof("Desired weight (stepIdx: %s) %d not yet verified", indexString, desiredWeight) + logCtx := logutil.WithRollout(c.rollout) + logCtx.Info("rollout enqueue due to trafficrouting") c.enqueueRolloutAfter(c.rollout, defaults.GetRolloutVerifyRetryInterval()) } } From 502be54592e249e70a312ba0df6a4c2bf7b8406c Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Fri, 12 Jan 2024 22:36:04 +0200 Subject: [PATCH 81/90] feat: release-1.6 logs for priceline --- rollout/controller.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rollout/controller.go b/rollout/controller.go index 95dbe87437..e73115d6c8 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -174,6 +174,11 @@ func NewController(cfg ControllerConfig) *Controller { client: cfg.KubeClientSet, resyncPeriod: cfg.ResyncPeriod, enqueueAfter: func(obj interface{}, duration time.Duration) { + ro := unstructuredutil.ObjectToRollout(obj) + if ro != nil { + logCtx := logutil.WithRollout(ro) + logCtx.Info("rollout enqueue due to pod restart") + } controllerutil.EnqueueAfter(obj, duration, cfg.RolloutWorkQueue) }, } From ef75a536abcf98809f553f92292a0ebad173acda Mon Sep 17 00:00:00 2001 From: Oleksandr Saulyak Date: Mon, 11 Dec 2023 16:25:15 +0200 Subject: [PATCH 82/90] fix: canary step analysis run wasn't terminated as keep running after promote action being called. Fixes #3220 (#3221) * fix: canary step analysis run wasn't terminated as keep running after promote action being called Signed-off-by: oleksandr-codefresh * fix unit test: added test case for canary step analysis run wasn't terminated as keep running after promote action being called Signed-off-by: oleksandr-codefresh --------- Signed-off-by: oleksandr-codefresh Co-authored-by: pasha-codefresh (cherry picked from commit 0300af1a5047100d59c7495b7cacc4c1d12571a8) --- rollout/analysis.go | 5 ++- rollout/analysis_test.go | 78 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/rollout/analysis.go b/rollout/analysis.go index b2528aaf3b..49583287f6 100644 --- a/rollout/analysis.go +++ b/rollout/analysis.go @@ -372,7 +372,10 @@ func (c *rolloutContext) reconcileStepBasedAnalysisRun() (*v1alpha1.AnalysisRun, return currentAr, nil } - if step == nil || step.Analysis == nil || index == nil { + // for promotion cases + analysisRunFromPreviousStep := step != nil && step.Analysis != nil && currentAr != nil && currentAr.GetLabels()[v1alpha1.RolloutCanaryStepIndexLabel] != strconv.Itoa(int(*index)) + + if step == nil || step.Analysis == nil || index == nil || analysisRunFromPreviousStep { err := c.cancelAnalysisRuns([]*v1alpha1.AnalysisRun{currentAr}) return nil, err } diff --git a/rollout/analysis_test.go b/rollout/analysis_test.go index de9a5e1db3..624134fbb6 100644 --- a/rollout/analysis_test.go +++ b/rollout/analysis_test.go @@ -614,6 +614,84 @@ func TestCreateAnalysisRunOnAnalysisStep(t *testing.T) { assert.JSONEq(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, expectedArName)), patch) } +func TestCreateAnalysisRunOnPromotedAnalysisStepIfPreviousStepWasAnalysisToo(t *testing.T) { + f := newFixture(t) + defer f.Close() + + at := analysisTemplate("bar") + steps := []v1alpha1.CanaryStep{{ + Analysis: &v1alpha1.RolloutAnalysis{ + Templates: []v1alpha1.RolloutAnalysisTemplate{ + { + TemplateName: at.Name, + }, + }, + }, + }, { + Analysis: &v1alpha1.RolloutAnalysis{ + Templates: []v1alpha1.RolloutAnalysisTemplate{ + { + TemplateName: at.Name, + }, + }, + }, + }} + + r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(0), intstr.FromInt(1)) + r2 := bumpVersion(r1) + ar0Step := analysisRun(at, v1alpha1.RolloutTypeStepLabel, r2) + ar0Step.Status.Phase = v1alpha1.AnalysisPhaseRunning + + rs1 := newReplicaSetWithStatus(r1, 1, 1) + rs2 := newReplicaSetWithStatus(r2, 0, 0) + f.kubeobjects = append(f.kubeobjects, rs1, rs2) + f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) + rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + //rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + + r2 = updateCanaryRolloutStatus(r2, rs1PodHash, 1, 0, 1, false) + progressingCondition, _ := newProgressingCondition(conditions.ReplicaSetUpdatedReason, rs2, "") + conditions.SetRolloutCondition(&r2.Status, progressingCondition) + availableCondition, _ := newAvailableCondition(true) + conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + r2.Status.Canary.CurrentStepAnalysisRunStatus = &v1alpha1.RolloutAnalysisRunStatus{ + Name: ar0Step.Name, + Status: "", + } + + f.rolloutLister = append(f.rolloutLister, r2) + f.analysisTemplateLister = append(f.analysisTemplateLister, at) + f.analysisRunLister = append(f.analysisRunLister, ar0Step) + f.objects = append(f.objects, r2, at, ar0Step) + + patchOldAnalysisIndex := f.expectPatchAnalysisRunAction(ar0Step) + //createdIndex := f.expectCreateAnalysisRunAction(ar0Step) + index := f.expectPatchRolloutAction(r2) + + // simulate promote action + r2.Status.CurrentStepIndex = pointer.Int32Ptr(1) + + f.run(getKey(r2, t)) + + assert.True(t, f.verifyPatchedAnalysisRun(patchOldAnalysisIndex, ar0Step)) + // should terminate analysis run for old step + patchedOldAr := f.getPatchedAnalysisRun(patchOldAnalysisIndex) + assert.True(t, patchedOldAr.Spec.Terminate) + + // should patch rollout with relevant currentStepAnalysisRun + patch := f.getPatchedRollout(index) + expectedPatch := `{ + "status": { + "canary": { + "currentStepAnalysisRunStatus":null + } + } + }` + assert.JSONEq(t, calculatePatch(r2, expectedPatch), patch) +} + func TestFailCreateStepAnalysisRunIfInvalidTemplateRef(t *testing.T) { f := newFixture(t) defer f.Close() From 276789129f4727c07f132b2496c1fdf26e8b15ed Mon Sep 17 00:00:00 2001 From: oleksandr-codefresh Date: Thu, 18 Jan 2024 15:59:34 +0200 Subject: [PATCH 83/90] version updated Signed-off-by: oleksandr-codefresh --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9c6d6293b1..402a79f509 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.1 +1.6.1-analysis-fix From ceda83dd5d24504f4904e52bcd7808f1d60f43d7 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 6 Feb 2024 11:25:47 +0200 Subject: [PATCH 84/90] revert --- controller/controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/controller.go b/controller/controller.go index 4a83e7341a..afe4bc769b 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -85,7 +85,7 @@ const ( DefaultIngressThreads = 10 // DefaultLeaderElect is the default true leader election should be enabled - DefaultLeaderElect = false + DefaultLeaderElect = true // DefaultLeaderElectionLeaseDuration is the default time in seconds that non-leader candidates will wait to force acquire leadership DefaultLeaderElectionLeaseDuration = 15 * time.Second From 4a8f58f5b613057cdce022cb24b33adf5e784bf2 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 6 Feb 2024 11:37:19 +0200 Subject: [PATCH 85/90] fix linters --- rollout/context.go | 3 ++- rollout/pause.go | 3 ++- rollout/replicaset.go | 3 ++- rollout/trafficrouting.go | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/rollout/context.go b/rollout/context.go index 1f1005e76f..b9b5848e2f 100644 --- a/rollout/context.go +++ b/rollout/context.go @@ -1,9 +1,10 @@ package rollout import ( - logutil "github.com/argoproj/argo-rollouts/utils/log" "time" + logutil "github.com/argoproj/argo-rollouts/utils/log" + log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/util/validation/field" diff --git a/rollout/pause.go b/rollout/pause.go index 3f1c4a2570..c714636362 100644 --- a/rollout/pause.go +++ b/rollout/pause.go @@ -1,9 +1,10 @@ package rollout import ( - logutil "github.com/argoproj/argo-rollouts/utils/log" "time" + logutil "github.com/argoproj/argo-rollouts/utils/log" + log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/rollout/replicaset.go b/rollout/replicaset.go index 70a190d5c8..5eac105807 100644 --- a/rollout/replicaset.go +++ b/rollout/replicaset.go @@ -3,10 +3,11 @@ package rollout import ( "context" "fmt" - logutil "github.com/argoproj/argo-rollouts/utils/log" "sort" "time" + logutil "github.com/argoproj/argo-rollouts/utils/log" + appsv1 "k8s.io/api/apps/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index cc1e552d7c..bf03d95ef1 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -2,11 +2,12 @@ package rollout import ( "fmt" - logutil "github.com/argoproj/argo-rollouts/utils/log" "reflect" "strconv" "strings" + logutil "github.com/argoproj/argo-rollouts/utils/log" + "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/plugin" From f8628d25fdfc8b2165debe3a857f52a5c01f46bf Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 6 Feb 2024 11:46:34 +0200 Subject: [PATCH 86/90] regenerate protofiles --- pkg/apis/rollouts/v1alpha1/generated.pb.go | 2 +- pkg/apis/rollouts/v1alpha1/generated.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 7a0c3ccf23..26c7e722a0 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -1,5 +1,5 @@ /* -Copyright 2023 The Kubernetes sample-controller Authors. +Copyright 2024 The Kubernetes sample-controller Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index ea7c60a531..1b3135874c 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -1,5 +1,5 @@ /* -Copyright 2023 The Kubernetes sample-controller Authors. +Copyright 2024 The Kubernetes sample-controller Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 855b76e0e49cb0ca34b38d50d8e4a87db9252461 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 6 Feb 2024 11:55:34 +0200 Subject: [PATCH 87/90] regenerate protofiles --- pkg/apis/rollouts/v1alpha1/openapi_generated.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index f91a313c76..ebd6ce7786 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -2,7 +2,7 @@ // +build !ignore_autogenerated /* -Copyright 2023 The Kubernetes sample-controller Authors. +Copyright 2024 The Kubernetes sample-controller Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From f626e3427d6c627fe358489d849e40a8a8c5345f Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 6 Feb 2024 12:30:57 +0200 Subject: [PATCH 88/90] change version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 402a79f509..691a5db1f8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.1-analysis-fix +1.6.1-additional-logs From 647ded58250f7d5ed3f1ebfc0139df46c1017838 Mon Sep 17 00:00:00 2001 From: Liming Liu Date: Sat, 9 Dec 2023 00:26:21 +0800 Subject: [PATCH 89/90] chore: leave the validation of setHeaderRoute to the plugin when plugins is not empty. (#2898) chore: leave the validation of setHeaderRoute to the plugin if plugins not empty. Signed-off-by: Liming Liu Co-authored-by: Ubuntu --- pkg/apis/rollouts/validation/validation.go | 2 +- .../rollouts/validation/validation_test.go | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/pkg/apis/rollouts/validation/validation.go b/pkg/apis/rollouts/validation/validation.go index 34c4e3cbf9..94ba58f59b 100644 --- a/pkg/apis/rollouts/validation/validation.go +++ b/pkg/apis/rollouts/validation/validation.go @@ -305,7 +305,7 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat if step.SetHeaderRoute != nil { trafficRouting := rollout.Spec.Strategy.Canary.TrafficRouting - if trafficRouting == nil || (trafficRouting.Istio == nil && trafficRouting.ALB == nil && trafficRouting.Apisix == nil) { + if trafficRouting == nil || (trafficRouting.Istio == nil && trafficRouting.ALB == nil && trafficRouting.Apisix == nil && len(trafficRouting.Plugins) == 0) { allErrs = append(allErrs, field.Invalid(stepFldPath.Child("setHeaderRoute"), step.SetHeaderRoute, InvalidSetHeaderRouteTrafficPolicy)) } else if step.SetHeaderRoute.Match != nil && len(step.SetHeaderRoute.Match) > 0 { for j, match := range step.SetHeaderRoute.Match { diff --git a/pkg/apis/rollouts/validation/validation_test.go b/pkg/apis/rollouts/validation/validation_test.go index 9722d0d093..58a4571ae7 100644 --- a/pkg/apis/rollouts/validation/validation_test.go +++ b/pkg/apis/rollouts/validation/validation_test.go @@ -1,6 +1,7 @@ package validation import ( + "encoding/json" "fmt" "testing" @@ -305,6 +306,42 @@ func TestValidateRolloutStrategyCanarySetHeaderRoute(t *testing.T) { }) } +func TestValidateRolloutStrategyCanarySetHeaderRoutePlugins(t *testing.T) { + ro := &v1alpha1.Rollout{} + ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{ + CanaryService: "canary", + StableService: "stable", + } + + t.Run("using SetHeaderRoute step with plugins", func(t *testing.T) { + invalidRo := ro.DeepCopy() + routeName := "test" + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetHeaderRoute: &v1alpha1.SetHeaderRoute{ + Name: routeName, + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + HeaderValue: &v1alpha1.StringMatch{Exact: "chrome"}, + }, + }, + }, + }} + invalidRo.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + ManagedRoutes: []v1alpha1.MangedRoutes{ + { + Name: routeName, + }, + }, + Plugins: map[string]json.RawMessage{ + "anyplugin": []byte(`{"key": "value"}`), + }, + } + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, 0, len(allErrs)) + }) +} + func TestValidateRolloutStrategyCanarySetHeaderRouteIstio(t *testing.T) { ro := &v1alpha1.Rollout{} ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{ From 594f87acf09af6a6e32dd10655b9b734ebf53158 Mon Sep 17 00:00:00 2001 From: Denys Melnyk Date: Tue, 2 Jul 2024 19:09:10 +0300 Subject: [PATCH 90/90] bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 691a5db1f8..40bdab01a0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.1-additional-logs +v1.6.1-CR-23199