From ad1bc9c6496cba16e8c6ea5db77ede70ff7c0aeb Mon Sep 17 00:00:00 2001 From: Travis Perdue Date: Tue, 18 Oct 2022 09:18:40 -0500 Subject: [PATCH] V1.3.0 rallyhealth pr (#6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add support for influxdb as a metrics provider (#1839) * feat: add InfluxDB metric provider implementation Signed-off-by: Jayme Bird * feat: add influx to metric provider util count, add missing graphite Signed-off-by: Jayme Bird * feat: add protobuf definitions for InfluxdbMetric Signed-off-by: Jayme Bird * feat: add docs for the Influxdb metrics provider Signed-off-by: Jayme Bird * feat: add tests for influxdb metrics provider Signed-off-by: Jayme Bird * feat: add go mod replace for version of moq due to security issue Signed-off-by: Jayme Bird * feat: update error message to distinguish failed cases - review feedback Signed-off-by: Jayme Bird * feat: update tests to simplify mocking of QueryTableResult An upstream change to the influx go client makes it easier to mock QueryTableResult in tests. This removes a lot of boilerplate duplication in the tests. Signed-off-by: Jayme Bird * feat: re-run codegen Signed-off-by: Jayme Bird * feat: Adds support for Istio traffic mirroring (#2074) * feat: Add support for istio traffic mirroring steps Signed-off-by: zachaller * bump e2e timeout Signed-off-by: zachaller * Remove unintended change Signed-off-by: zachaller * Cleaner events Signed-off-by: zachaller * Add docs for mirror and fix up header routing Signed-off-by: zachaller * small doc changes Signed-off-by: zachaller * Add example Signed-off-by: zachaller * Fix types and change example Signed-off-by: zachaller * Remove unused type Signed-off-by: zachaller * Docs change Signed-off-by: zachaller * Fix PR comments Signed-off-by: zachaller * Check for >= Signed-off-by: zachaller * Remove unused function Signed-off-by: zachaller * codegen Signed-off-by: zachaller * Add better error logging Signed-off-by: zachaller * a few more error msgs Signed-off-by: zachaller * fix comments Signed-off-by: zachaller * typo Signed-off-by: zachaller * fix logic error Signed-off-by: zachaller * redo header logic Signed-off-by: zachaller * cleanup Signed-off-by: zachaller * Fix issue with keeping route weight updated when no routes are defined in spec.strategy.canary.trafficRouting.istio.virtualService.routes requiring only a single route Signed-off-by: zachaller * cleanup routes when promiting with last step being a pause Signed-off-by: zachaller * fix bug with promote and last step is a pause Signed-off-by: zachaller * Fix tests Signed-off-by: zachaller * fix typo Signed-off-by: zachaller * chore: improve openapi schema (#2081) * feat: include all CRDs to the OpenAPI schema Signed-off-by: Mário Bezerra * feat: use kube-openapi naming convention in the OpenAPI schema Signed-off-by: Mário Bezerra * chore: generate OpenAPI schema Signed-off-by: Mário Bezerra * feat(grafana): Allow selecting datasource for grafana dashboard (#1988) Signed-off-by: Jesse Antoszyk <22500761+jcantosz@users.noreply.github.com> * feat: support /rollouts/:namespace?q=... and /rollout/:namespace/:name (#1902) Signed-off-by: Simon Ninon * chore: Add e2e and unit test comment reports (#2123) Signed-off-by: zachaller * chore: upgrade deps (#2136) Signed-off-by: zachaller * fixes #2141 Added list and watch to clusterrole (#2145) Signed-off-by: Martin Adler <1208749+EagleIJoe@users.noreply.github.com> * fix: Update ro.Status.ALB when first creating rollout object (#1986) * fix: make sure we update rollout.Status.ALB when first create Rollout object This fixes the case when we first create a rollout the status.ALB field does not get updated with valid information form the elb. Signed-off-by: zachaller * Refactor check for if we should verify alb. This creates a new rolloututil function ShouldVerifyWeight that verifies that we should call aws because the rollout is in the middle of some update. The reason I feel this should move into the ingress implmentation function VerifyWeight is becuase in the future other ingresses might also need to verify weights and adding ingress specific status checks in trafficrouting.go like a leak details where it should be up to the ingress provider to determin if it should be careful of rate limiting do to say it being a cloud provider call. Signed-off-by: zachaller * lint Signed-off-by: zachaller * Fix tests Signed-off-by: zachaller * Add new test for ShouldVerifyWeight Signed-off-by: zachaller * Fix logic Signed-off-by: zachaller * Add test for where we do not need to verify weight and its already set Signed-off-by: zachaller * fix up review comments Signed-off-by: zachaller * fix tests Signed-off-by: zachaller * fix bad merge Signed-off-by: zachaller * Fix test Signed-off-by: zachaller * Fix test Signed-off-by: zachaller * Clearer function name Signed-off-by: zachaller * Clean up if logic Signed-off-by: zachaller * fix: remove metrics when objects are removed from cluster to prevent build up (#2115) * fix: remove metrics on resource removal Signed-off-by: zachaller * Add test Signed-off-by: zachaller * More tests Signed-off-by: zachaller * back off deps updates Signed-off-by: zachaller * Fix dep change Signed-off-by: zachaller * upgrade prom deps for new features Signed-off-by: zachaller * fix deps Signed-off-by: zachaller * chore: use controler-gen for cluster analysis template scope (#2148) Signed-off-by: zachaller * fix(analysis): Fix Analysis Terminal Decision For Dry-Run Metrics (#2131) Signed-off-by: Rohit Agrawal * docs: update release doc with brew formula details (#2165) Signed-off-by: Leonardo Luz Almeida * fix(docs) Graphite metrics provider linked in docs sidebar. Fixes #2102. (#2094) * Graphite metrics provider linked in docs sidebar This fixes an issue wherein the Graphite metrics provider has no sidebar link in the docs hosted at https://argoproj.github.io/argo-rollouts/. As a bonus, this also removes various trailing whitespace from analysis docs. Signed-off-by: Mike Ball * build trigger Signed-off-by: Mike Ball * feat: emit rollout delete event (#1893) Signed-off-by: Hui Kang Co-authored-by: Hui Kang * chore: Upgrade golang (#2160) * Upgrade golang Signed-off-by: zachaller * upgrade golang to 1.18 for e2e Signed-off-by: zachaller * Fix deps Signed-off-by: zachaller * Update build action Signed-off-by: zachaller * Upgrade push action Signed-off-by: zachaller * Update docker file Signed-off-by: zachaller * Bump golang lint to match Signed-off-by: zachaller * fix go.mod Signed-off-by: zachaller * fix: Failed to process: Object 'Kind' is missing in Errors with rollouts notification (#2150) * fix: update rolloutobject with gvk before writing to rollout informer Signed-off-by: Ravi Hari * fix: controller schema linting Signed-off-by: Ravi Hari * docs: comment the details on the change Signed-off-by: Ravi Hari * docs: comment the details on the change Signed-off-by: Ravi Hari * fix: rootPath support so that it uses the embedded files system (#2198) * fix: rootPath support so that it uses the embeded files system Signed-off-by: zachaller * Catch edge cases and make sure we always server index.html on not found Signed-off-by: zachaller * turn path.Clean into var Signed-off-by: zachaller Signed-off-by: zachaller * fix: change completed condition so it only triggers on pod hash changes also adds an event for when it does changes. (#2203) * feat: add healthy event/condition and fix completed event/condition Signed-off-by: zachaller * fix unit tests Signed-off-by: zachaller * rename vars to make more sense and remove healthy event becase it will never be consistent Signed-off-by: zachaller * fix unit tests Signed-off-by: zachaller * possible fix for e2e Signed-off-by: zachaller * fix e2e Signed-off-by: zachaller * unit test for complete function Signed-off-by: zachaller * small cleanup and changes to not check generation Signed-off-by: zachaller * fix unit test and proper behavior Signed-off-by: zachaller * Fix e2e Signed-off-by: zachaller * rename and fix one unit test Signed-off-by: zachaller * fix unit tests Signed-off-by: zachaller * fix unit test Signed-off-by: zachaller * add seperate test for TestRolloutComplete Signed-off-by: zachaller * renames Signed-off-by: zachaller * fix e2e Signed-off-by: zachaller * Set Completed to false Signed-off-by: zachaller * Add event Signed-off-by: zachaller * fix e2e Signed-off-by: zachaller * refactor Signed-off-by: zachaller * Fix all but one unit test Signed-off-by: zachaller * fix last unit test Signed-off-by: zachaller * lint Signed-off-by: zachaller * cleanup Signed-off-by: zachaller * Rename Signed-off-by: zachaller * More renames Signed-off-by: zachaller * small comment change Signed-off-by: zachaller Signed-off-by: zachaller * feat: Add support for spec.ingressClassName (#2178) This change adds support for `spec.ingressClassName` while still supporting `kubernetes.io/ingress.class` annotation for backwards compatibility. Fixes #1277 Signed-off-by: Siavash Safi Signed-off-by: Siavash Safi * fix: enable notifications without when condition (#2231) * fix: enable notifications without when condition Signed-off-by: Ravi Hari * fix: use trigger action item from the list Signed-off-by: Ravi Hari * fix: add emptycondition logic to make notifications work with/without conditions Signed-off-by: Ravi Hari * fix: linting Signed-off-by: Ravi Hari Signed-off-by: Ravi Hari * Use standard cli format for dashboard root path (#2244) Signed-off-by: zachaller Signed-off-by: zachaller * merge conflict broke tests Signed-off-by: Travis Perdue Signed-off-by: Jayme Bird Signed-off-by: zachaller Signed-off-by: Mário Bezerra Signed-off-by: Jesse Antoszyk <22500761+jcantosz@users.noreply.github.com> Signed-off-by: Simon Ninon Signed-off-by: Martin Adler <1208749+EagleIJoe@users.noreply.github.com> Signed-off-by: Rohit Agrawal Signed-off-by: Leonardo Luz Almeida Signed-off-by: Mike Ball Signed-off-by: Ravi Hari Signed-off-by: Siavash Safi Signed-off-by: Travis Perdue Co-authored-by: jaymebrd Co-authored-by: Zach Aller Co-authored-by: Mário Bezerra Co-authored-by: Jesse Antoszyk <22500761+jcantosz@users.noreply.github.com> Co-authored-by: Simon Ninon Co-authored-by: Martin Adler <1208749+EagleIJoe@users.noreply.github.com> Co-authored-by: Rohit Agrawal Co-authored-by: Leonardo Luz Almeida Co-authored-by: Mike Ball Co-authored-by: cskh Co-authored-by: Hui Kang Co-authored-by: RaviHari Co-authored-by: Siavash Safi Signed-off-by: Travis Perdue --- analysis/analysis_test.go | 8 +- examples/traffic-routing/istio-mirror.yaml | 117 +++++++++++++++++++++ ingress/ingress_test.go | 71 +++++++++++++ rollout/trafficrouting/nginx/nginx_test.go | 39 +++++++ server/server.go | 31 ++++++ ui/src/models/rollout/generated/api.ts | 13 +++ utils/analysis/helpers.go | 4 +- 7 files changed, 278 insertions(+), 5 deletions(-) create mode 100644 examples/traffic-routing/istio-mirror.yaml diff --git a/analysis/analysis_test.go b/analysis/analysis_test.go index ed12da2dca..71949b2084 100644 --- a/analysis/analysis_test.go +++ b/analysis/analysis_test.go @@ -1500,7 +1500,7 @@ func TestAssessRunStatusErrorMessageAnalysisPhaseFail(t *testing.T) { func TestAssessRunStatusErrorMessageAnalysisPhaseFailInDryRunMode(t *testing.T) { status, message, dryRunSummary := StartAssessRunStatusErrorMessageAnalysisPhaseFail(t, true) - assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, status) + assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) expectedDryRunSummary := v1alpha1.RunSummary{ Count: 2, @@ -1545,7 +1545,7 @@ func TestAssessRunStatusErrorMessageFromProvider(t *testing.T) { func TestAssessRunStatusErrorMessageFromProviderInDryRunMode(t *testing.T) { providerMessage := "Provider Error" status, message, dryRunSummary := StartAssessRunStatusErrorMessageFromProvider(t, providerMessage, true) - assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, status) + assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) expectedDryRunSummary := v1alpha1.RunSummary{ Count: 2, @@ -1587,7 +1587,7 @@ func TestAssessRunStatusMultipleFailures(t *testing.T) { func TestAssessRunStatusMultipleFailuresInDryRunMode(t *testing.T) { status, message, dryRunSummary := StartAssessRunStatusMultipleFailures(t, true) - assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, status) + assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) expectedDryRunSummary := v1alpha1.RunSummary{ Count: 2, @@ -1732,7 +1732,7 @@ func TestAssessRunStatusWorstMessageInReconcileAnalysisRun(t *testing.T) { func TestAssessRunStatusWorstMessageInReconcileAnalysisRunInDryRunMode(t *testing.T) { newRun := StartAssessRunStatusWorstMessageInReconcileAnalysisRun(t, true) - assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, newRun.Status.Phase) + assert.Equal(t, v1alpha1.AnalysisPhaseRunning, newRun.Status.Phase) assert.Equal(t, "", newRun.Status.Message) expectedDryRunSummary := v1alpha1.RunSummary{ Count: 2, diff --git a/examples/traffic-routing/istio-mirror.yaml b/examples/traffic-routing/istio-mirror.yaml new file mode 100644 index 0000000000..d56c36add4 --- /dev/null +++ b/examples/traffic-routing/istio-mirror.yaml @@ -0,0 +1,117 @@ +## This examples sets up istio mirroring if running locally using docker for destkop you can add +## istio-host-split.com to your /etc/hosts and point it to 127.0.0.1 to view demo. +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.com + gateways: + - istio-host-split-gateway + 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: 4 + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + managedRoutes: + - name: mirror-route + istio: + virtualService: + name: istio-host-split-vsvc + routes: + - primary + steps: + - setCanaryScale: + weight: 50 + - setMirrorRoute: + name: mirror-route + percentage: 50 + match: + - method: + exact: POST + path: + prefix: /color + - pause: {} + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: argoproj/rollouts-demo:green + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + +--- + +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-host-split-gateway +spec: + selector: + istio: ingressgateway # use istio default controller + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "istio-host-split.com" + diff --git a/ingress/ingress_test.go b/ingress/ingress_test.go index 358c62927c..f2d1a35e19 100644 --- a/ingress/ingress_test.go +++ b/ingress/ingress_test.go @@ -245,6 +245,77 @@ func TestSyncIngressReferencedByRollout(t *testing.T) { assert.Equal(t, 1, enqueuedObjects["default/rollout"]) } +func TestSkipIngressWithNoClass(t *testing.T) { + ing := newNginxIngressWithAnnotation("test-stable-ingress", 80, "stable-service") + ing.Annotations = nil + rollout := &v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollout", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + StableService: "stable-service", + CanaryService: "canary-service", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Nginx: &v1alpha1.NginxTrafficRouting{ + StableIngress: "test-stable-ingress", + }, + }, + }, + }, + }, + } + + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) + + err := ctrl.syncIngress("default/test-stable-ingress") + assert.NoError(t, err) + actions := kubeclient.Actions() + assert.Len(t, actions, 0) + assert.Len(t, enqueuedObjects, 0) +} + +func TestSkipIngressWithNoClassMultiIngress(t *testing.T) { + ings := []*extensionsv1beta1.Ingress{ + newNginxIngressWithAnnotation("test-stable-ingress", 80, "stable-service"), + newNginxIngressWithAnnotation("test-stable-ingress-additional", 80, "stable-service"), + } + for _, i := range ings { + i.Annotations = nil + } + + rollout := &v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollout", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + StableService: "stable-service", + CanaryService: "canary-service", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Nginx: &v1alpha1.NginxTrafficRouting{ + StableIngress: "test-stable-ingress", + AdditionalStableIngresses: []string{"test-stable-ingress-additional"}, + }, + }, + }, + }, + }, + } + + ctrl, kubeclient, enqueuedObjects := newFakeIngressControllerMultiIngress(t, ings, rollout) + + err := ctrl.syncIngress("default/test-stable-ingress") + assert.NoError(t, err) + actions := kubeclient.Actions() + assert.Len(t, actions, 0) + assert.Len(t, enqueuedObjects, 0) +} + func TestSyncIngressReferencedByRolloutMultiIngress(t *testing.T) { ings := []*extensionsv1beta1.Ingress{ newNginxIngress("test-stable-ingress", 80, "stable-service"), diff --git a/rollout/trafficrouting/nginx/nginx_test.go b/rollout/trafficrouting/nginx/nginx_test.go index d0037574c9..7aca48c9d5 100644 --- a/rollout/trafficrouting/nginx/nginx_test.go +++ b/rollout/trafficrouting/nginx/nginx_test.go @@ -1194,6 +1194,45 @@ func TestReconcileCanaryCreateErrorAlreadyExistsPatch(t *testing.T) { } } +func TestSetHeaderRoute(t *testing.T) { + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRollout("stable-service", "canary-service", "stable-ingress"), + }, + } + err := r.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ + Name: "set-header", + Match: []v1alpha1.HeaderRoutingMatch{{ + HeaderName: "header-name", + HeaderValue: &v1alpha1.StringMatch{ + Exact: "value", + }, + }}, + }) + assert.Nil(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) +} + +func TestSetMirrorRoute(t *testing.T) { + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRollout("stable-service", "canary-service", "stable-ingress"), + }, + } + err := r.SetMirrorRoute(&v1alpha1.SetMirrorRoute{ + Name: "mirror-route", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{Exact: "GET"}, + }}, + }) + assert.Nil(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) +} + func TestReconcileCanaryCreateErrorAlreadyExistsPatchMultiIngress(t *testing.T) { rollout := fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress") stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") diff --git a/server/server.go b/server/server.go index a69d90d5f0..787ab5a100 100644 --- a/server/server.go +++ b/server/server.go @@ -3,6 +3,7 @@ package server import ( "context" "fmt" + "io/fs" "net" "net/http" "strings" @@ -110,6 +111,36 @@ func (s *ArgoRolloutsServer) newHTTPServer(ctx context.Context, port int) *http. return &httpS } +func (s *ArgoRolloutsServer) readIndexHtml() ([]byte, error) { + file, err := static.Open("static/index.html") + if err != nil { + log.Errorf("Failed to open file %s: %v", "static/index.html", err) + return nil, err + } + defer func() { + if file != nil { + if err := file.Close(); err != nil { + log.Errorf("Error closing file: %v", err) + } + } + }() + + stat, err := file.Stat() + if err != nil { + log.Errorf("Failed to stat file or dir %s: %v", "static/index.html", err) + return nil, err + } + + fileBytes := make([]byte, stat.Size()) + _, err = file.Read(fileBytes) + if err != nil { + log.Errorf("Failed to read file %s: %v", "static/index.html", err) + return nil, err + } + + return withRootPath(fileBytes, s.Options.RootPath), nil +} + func (s *ArgoRolloutsServer) newGRPCServer() *grpc.Server { grpcS := grpc.NewServer() var rolloutsServer rollout.RolloutServiceServer = NewServer(s.Options) diff --git a/ui/src/models/rollout/generated/api.ts b/ui/src/models/rollout/generated/api.ts index 7344e5fb5f..fc6f1d6548 100755 --- a/ui/src/models/rollout/generated/api.ts +++ b/ui/src/models/rollout/generated/api.ts @@ -811,6 +811,19 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoute */ name?: string; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes + */ + name?: string; +} /** * MeasurementRetention defines the settings for retaining the number of measurements during the analysis. * @export diff --git a/utils/analysis/helpers.go b/utils/analysis/helpers.go index caedeb472c..4ee47de08f 100644 --- a/utils/analysis/helpers.go +++ b/utils/analysis/helpers.go @@ -93,7 +93,9 @@ func IsTerminating(run *v1alpha1.AnalysisRun) bool { switch res.Phase { case v1alpha1.AnalysisPhaseFailed, v1alpha1.AnalysisPhaseError, v1alpha1.AnalysisPhaseInconclusive: - return true + // If this metric is running in the dryRun mode then we don't care about the failures and hence the terminal + // decision shouldn't be affected. + return !res.DryRun } } return false