From bae469c67de20acc947caed06e79ba2faa3b08f0 Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Thu, 21 Oct 2021 10:04:14 +0300 Subject: [PATCH 1/7] add POST/PUT option to WebMetric Signed-off-by: Noam Gal --- manifests/crds/analysis-run-crd.yaml | 6 + manifests/crds/analysis-template-crd.yaml | 6 + .../crds/cluster-analysis-template-crd.yaml | 6 + manifests/install.yaml | 18 +++ manifests/namespace-install.yaml | 18 +++ metricproviders/webmetric/webmetric.go | 26 ++-- nginx-sample.yaml | 112 ++++++++++++++++++ pkg/apis/rollouts/v1alpha1/analysis_types.go | 24 +++- .../v1alpha1/zz_generated.deepcopy.go | 1 + 9 files changed, 205 insertions(+), 12 deletions(-) create mode 100644 nginx-sample.yaml diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index c86adee24f..0d7611ecf4 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -2447,6 +2447,8 @@ spec: type: object web: properties: + body: + type: string headers: items: properties: @@ -2463,12 +2465,16 @@ spec: type: boolean jsonPath: type: string + method: + type: string timeoutSeconds: format: int64 type: integer url: type: string required: + - body + - method - url type: object type: object diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index 6762c935ef..c7aed17a91 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -2442,6 +2442,8 @@ spec: type: object web: properties: + body: + type: string headers: items: properties: @@ -2458,12 +2460,16 @@ spec: type: boolean jsonPath: type: string + method: + type: string timeoutSeconds: format: int64 type: integer url: type: string required: + - body + - method - url type: object type: object diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index 10f9982e08..09d619d986 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -2442,6 +2442,8 @@ spec: type: object web: properties: + body: + type: string headers: items: properties: @@ -2458,12 +2460,16 @@ spec: type: boolean jsonPath: type: string + method: + type: string timeoutSeconds: format: int64 type: integer url: type: string required: + - body + - method - url type: object type: object diff --git a/manifests/install.yaml b/manifests/install.yaml index 605ff46a94..50f9232065 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2448,6 +2448,8 @@ spec: type: object web: properties: + body: + type: string headers: items: properties: @@ -2464,12 +2466,16 @@ spec: type: boolean jsonPath: type: string + method: + type: string timeoutSeconds: format: int64 type: integer url: type: string required: + - body + - method - url type: object type: object @@ -5006,6 +5012,8 @@ spec: type: object web: properties: + body: + type: string headers: items: properties: @@ -5022,12 +5030,16 @@ spec: type: boolean jsonPath: type: string + method: + type: string timeoutSeconds: format: int64 type: integer url: type: string required: + - body + - method - url type: object type: object @@ -7491,6 +7503,8 @@ spec: type: object web: properties: + body: + type: string headers: items: properties: @@ -7507,12 +7521,16 @@ spec: type: boolean jsonPath: type: string + method: + type: string timeoutSeconds: format: int64 type: integer url: type: string required: + - body + - method - url type: object type: object diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 3bb79b320a..ac0842cc15 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -2448,6 +2448,8 @@ spec: type: object web: properties: + body: + type: string headers: items: properties: @@ -2464,12 +2466,16 @@ spec: type: boolean jsonPath: type: string + method: + type: string timeoutSeconds: format: int64 type: integer url: type: string required: + - body + - method - url type: object type: object @@ -5006,6 +5012,8 @@ spec: type: object web: properties: + body: + type: string headers: items: properties: @@ -5022,12 +5030,16 @@ spec: type: boolean jsonPath: type: string + method: + type: string timeoutSeconds: format: int64 type: integer url: type: string required: + - body + - method - url type: object type: object @@ -7491,6 +7503,8 @@ spec: type: object web: properties: + body: + type: string headers: items: properties: @@ -7507,12 +7521,16 @@ spec: type: boolean jsonPath: type: string + method: + type: string timeoutSeconds: format: int64 type: integer url: type: string required: + - body + - method - url type: object type: object diff --git a/metricproviders/webmetric/webmetric.go b/metricproviders/webmetric/webmetric.go index 82c577d57c..1def6a94b1 100644 --- a/metricproviders/webmetric/webmetric.go +++ b/metricproviders/webmetric/webmetric.go @@ -5,10 +5,11 @@ import ( "encoding/json" "errors" "fmt" + "io" "io/ioutil" "net/http" - "net/url" "reflect" + "strings" "time" metricutil "github.com/argoproj/argo-rollouts/utils/metric" @@ -46,18 +47,29 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph StartedAt: &startTime, } - // Create request - request := &http.Request{ - Method: "GET", // TODO maybe make this configurable....also implies we will need body templates + method := v1alpha1.WebMetricMethodGet + if metric.Provider.Web.Method != "" { + method = metric.Provider.Web.Method } - url, err := url.Parse(metric.Provider.Web.URL) + url := metric.Provider.Web.URL + + var body io.Reader + + if metric.Provider.Web.Body != "" { + if method == v1alpha1.WebMetricMethodGet { + return metricutil.MarkMeasurementError(measurement, fmt.Errorf("Body can only be used with POST or PUT WebMetric Method types")) + } + + body = strings.NewReader(metric.Provider.Web.Body) + } + + // Create request + request, err := http.NewRequest(string(method), url, body) if err != nil { return metricutil.MarkMeasurementError(measurement, err) } - request.URL = url - request.Header = make(http.Header) for _, header := range metric.Provider.Web.Headers { diff --git a/nginx-sample.yaml b/nginx-sample.yaml new file mode 100644 index 0000000000..19c8704e52 --- /dev/null +++ b/nginx-sample.yaml @@ -0,0 +1,112 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo +spec: + replicas: 1 + strategy: + canary: + canaryService: rollouts-demo-canary + stableService: rollouts-demo-stable + trafficRouting: + nginx: + stableIngress: rollouts-demo-stable + steps: + - setWeight: 5 + - analysis: + templates: + - templateName: success-rate + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollouts-demo + template: + metadata: + labels: + app: rollouts-demo + spec: + containers: + - name: rollouts-demo + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 32Mi + cpu: 5m + +--- +apiVersion: v1 +kind: Service +metadata: + name: rollouts-demo-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollouts-demo + # 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: rollouts-demo-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollouts-demo + # 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: rollouts-demo-stable + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: kubernetes.docker.internal + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: rollouts-demo-stable + port: + number: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: AnalysisTemplate +metadata: + name: success-rate +spec: + args: + - name: value + value: "98" + metrics: + - name: success-rate + successCondition: result >= 0.95 + provider: + web: + method: "PUT" + url: "http://kubernetes.docker.internal:3000/" + body: "{\"value\": 90}" + timeoutSeconds: 20 # defaults to 10 seconds + headers: + - key: Content-Type + value: "application/json" + jsonPath: "{$.result}" diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index a8bb968de2..86c6eb2fce 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -397,20 +397,34 @@ type ScopeDetail struct { } type WebMetric struct { + // Method is the method of the web metric (empty defaults to GET) + Method WebMetricMethod `json:"method" protobuf:"bytes,1,opt,name=method"` // URL is the address of the web metric - URL string `json:"url" protobuf:"bytes,1,opt,name=url"` + URL string `json:"url" protobuf:"bytes,2,opt,name=url"` // +patchMergeKey=key // +patchStrategy=merge // Headers are optional HTTP headers to use in the request - Headers []WebMetricHeader `json:"headers,omitempty" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,2,rep,name=headers"` + Headers []WebMetricHeader `json:"headers,omitempty" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,3,rep,name=headers"` + // Body is the body of the we metric (must be POST/PUT) + Body string `json:"body" protobuf:"bytes,4,opt,name=body"` // TimeoutSeconds is the timeout for the request in seconds (default: 10) - TimeoutSeconds int64 `json:"timeoutSeconds,omitempty" protobuf:"varint,3,opt,name=timeoutSeconds"` + TimeoutSeconds int64 `json:"timeoutSeconds,omitempty" protobuf:"varint,5,opt,name=timeoutSeconds"` // JSONPath is a JSON Path to use as the result variable (default: "{$}") - JSONPath string `json:"jsonPath,omitempty" protobuf:"bytes,4,opt,name=jsonPath"` + JSONPath string `json:"jsonPath,omitempty" protobuf:"bytes,6,opt,name=jsonPath"` // Insecure skips host TLS verification - Insecure bool `json:"insecure,omitempty" protobuf:"varint,5,opt,name=insecure"` + Insecure bool `json:"insecure,omitempty" protobuf:"varint,7,opt,name=insecure"` } +// WebMetricMethod is the available HTTP methods +type WebMetricMethod string + +// Possible HTTP method values +const ( + WebMetricMethodGet WebMetricMethod = "GET" + WebMetricMethodPost WebMetricMethod = "POST" + WebMetricMethodPut WebMetricMethod = "PUT" +) + type WebMetricHeader struct { Key string `json:"key" protobuf:"bytes,1,opt,name=key"` Value string `json:"value" protobuf:"bytes,2,opt,name=value"` diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 6df409ca55..d8234cc4d5 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* From 66e7936fbd67683fd1c25f291d34486b5d458a0e Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Thu, 21 Oct 2021 10:04:14 +0300 Subject: [PATCH 2/7] committed by mistake Signed-off-by: Noam Gal --- nginx-sample.yaml | 112 ---------------------------------------------- 1 file changed, 112 deletions(-) delete mode 100644 nginx-sample.yaml diff --git a/nginx-sample.yaml b/nginx-sample.yaml deleted file mode 100644 index 19c8704e52..0000000000 --- a/nginx-sample.yaml +++ /dev/null @@ -1,112 +0,0 @@ -apiVersion: argoproj.io/v1alpha1 -kind: Rollout -metadata: - name: rollouts-demo -spec: - replicas: 1 - strategy: - canary: - canaryService: rollouts-demo-canary - stableService: rollouts-demo-stable - trafficRouting: - nginx: - stableIngress: rollouts-demo-stable - steps: - - setWeight: 5 - - analysis: - templates: - - templateName: success-rate - revisionHistoryLimit: 2 - selector: - matchLabels: - app: rollouts-demo - template: - metadata: - labels: - app: rollouts-demo - spec: - containers: - - name: rollouts-demo - image: argoproj/rollouts-demo:blue - ports: - - name: http - containerPort: 8080 - protocol: TCP - resources: - requests: - memory: 32Mi - cpu: 5m - ---- -apiVersion: v1 -kind: Service -metadata: - name: rollouts-demo-canary -spec: - ports: - - port: 80 - targetPort: http - protocol: TCP - name: http - selector: - app: rollouts-demo - # 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: rollouts-demo-stable -spec: - ports: - - port: 80 - targetPort: http - protocol: TCP - name: http - selector: - app: rollouts-demo - # 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: rollouts-demo-stable - annotations: - kubernetes.io/ingress.class: nginx -spec: - rules: - - host: kubernetes.docker.internal - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: rollouts-demo-stable - port: - number: 80 ---- -apiVersion: argoproj.io/v1alpha1 -kind: AnalysisTemplate -metadata: - name: success-rate -spec: - args: - - name: value - value: "98" - metrics: - - name: success-rate - successCondition: result >= 0.95 - provider: - web: - method: "PUT" - url: "http://kubernetes.docker.internal:3000/" - body: "{\"value\": 90}" - timeoutSeconds: 20 # defaults to 10 seconds - headers: - - key: Content-Type - value: "application/json" - jsonPath: "{$.result}" From 57c1f76580443b168186e7d3f51118e6e2048afd Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Thu, 21 Oct 2021 10:04:14 +0300 Subject: [PATCH 3/7] added Method/Body tests Signed-off-by: Noam Gal --- metricproviders/webmetric/webmetric_test.go | 109 +++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/metricproviders/webmetric/webmetric_test.go b/metricproviders/webmetric/webmetric_test.go index 148123e9dd..a6107e9c00 100644 --- a/metricproviders/webmetric/webmetric_test.go +++ b/metricproviders/webmetric/webmetric_test.go @@ -1,6 +1,7 @@ package webmetric import ( + "bytes" "io" "net/http" "net/http/httptest" @@ -17,6 +18,8 @@ func TestRunSuite(t *testing.T) { webServerStatus int webServerResponse string metric v1alpha1.Metric + expectedMethod string + expectedBody string expectedValue string expectedPhase v1alpha1.AnalysisPhase expectedErrorMessage string @@ -433,7 +436,6 @@ func TestRunSuite(t *testing.T) { expectedPhase: v1alpha1.AnalysisPhaseError, expectedErrorMessage: "Could not find JSONPath in body", }, - // When_200Response_And_NilBody_Then_Succeed { webServerStatus: 200, @@ -477,6 +479,101 @@ func TestRunSuite(t *testing.T) { expectedPhase: v1alpha1.AnalysisPhaseError, expectedErrorMessage: "", }, + // When_methodEmpty_Then_server_gets_GET + { + webServerStatus: 200, + webServerResponse: `{"a": 1, "b": true, "c": [1, 2, 3, 4], "d": null}`, + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + }, + }, + }, + expectedMethod: "GET", + expectedValue: `{"a":1,"b":true,"c":[1,2,3,4],"d":null}`, + expectedPhase: v1alpha1.AnalysisPhaseSuccessful, + }, + // When_methodGET_Then_server_gets_GET + { + webServerStatus: 200, + webServerResponse: `{"a": 1, "b": true, "c": [1, 2, 3, 4], "d": null}`, + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + Method: v1alpha1.WebMetricMethodGet, + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + }, + }, + }, + expectedMethod: "GET", + expectedValue: `{"a":1,"b":true,"c":[1,2,3,4],"d":null}`, + expectedPhase: v1alpha1.AnalysisPhaseSuccessful, + }, + // When_methodPOST_Then_server_gets_body + { + webServerStatus: 200, + webServerResponse: `{"a": 1, "b": true, "c": [1, 2, 3, 4], "d": null}`, + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + Method: v1alpha1.WebMetricMethodPost, + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + Body: "some body", + }, + }, + }, + expectedMethod: "POST", + expectedBody: "some body", + expectedValue: `{"a":1,"b":true,"c":[1,2,3,4],"d":null}`, + expectedPhase: v1alpha1.AnalysisPhaseSuccessful, + }, + // When_methodPUT_Then_server_gets_body + { + webServerStatus: 200, + webServerResponse: `{"a": 1, "b": true, "c": [1, 2, 3, 4], "d": null}`, + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + Method: v1alpha1.WebMetricMethodPut, + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + Body: "some body", + }, + }, + }, + expectedMethod: "PUT", + expectedBody: "some body", + expectedValue: `{"a":1,"b":true,"c":[1,2,3,4],"d":null}`, + expectedPhase: v1alpha1.AnalysisPhaseSuccessful, + }, + // When_sendingBodyWithGet_Then_Failure + { + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + Body: "some body", + }, + }, + }, + expectedValue: "Body can only be used with POST or PUT WebMetric Method types", + expectedPhase: v1alpha1.AnalysisPhaseError, + }, } // Run @@ -484,6 +581,16 @@ func TestRunSuite(t *testing.T) { for _, test := range tests { // Server setup with response server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + if test.expectedMethod != "" { + assert.Equal(t, test.expectedMethod, req.Method) + } + + if test.expectedBody != "" { + buf := new(bytes.Buffer) + buf.ReadFrom(req.Body) + assert.Equal(t, test.expectedBody, buf.String()) + } + if test.webServerStatus < 200 || test.webServerStatus >= 300 { http.Error(rw, http.StatusText(test.webServerStatus), test.webServerStatus) } else { From f36c09842bd7bad540722cbee27062f58c7b7fc4 Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Thu, 21 Oct 2021 10:04:14 +0300 Subject: [PATCH 4/7] fixed codegen step Signed-off-by: Noam Gal --- pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index d8234cc4d5..6df409ca55 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1,4 +1,3 @@ -//go:build !ignore_autogenerated // +build !ignore_autogenerated /* From 5f5855a5a2d83178e1afc50df0768d109e5b5587 Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Thu, 21 Oct 2021 10:04:15 +0300 Subject: [PATCH 5/7] make method/body non-required fields Signed-off-by: Noam Gal --- manifests/crds/analysis-run-crd.yaml | 2 -- manifests/crds/analysis-template-crd.yaml | 2 -- manifests/crds/cluster-analysis-template-crd.yaml | 2 -- manifests/install.yaml | 6 ------ manifests/namespace-install.yaml | 6 ------ pkg/apis/rollouts/v1alpha1/analysis_types.go | 4 ++-- 6 files changed, 2 insertions(+), 20 deletions(-) diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index 0d7611ecf4..0f1c848527 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -2473,8 +2473,6 @@ spec: url: type: string required: - - body - - method - url type: object type: object diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index c7aed17a91..b9131eba93 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -2468,8 +2468,6 @@ spec: url: type: string required: - - body - - method - url type: object type: object diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index 09d619d986..f74108a0bf 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -2468,8 +2468,6 @@ spec: url: type: string required: - - body - - method - url type: object type: object diff --git a/manifests/install.yaml b/manifests/install.yaml index 50f9232065..b472c918fb 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2474,8 +2474,6 @@ spec: url: type: string required: - - body - - method - url type: object type: object @@ -5038,8 +5036,6 @@ spec: url: type: string required: - - body - - method - url type: object type: object @@ -7529,8 +7525,6 @@ spec: url: type: string required: - - body - - method - url type: object type: object diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index ac0842cc15..1fbc495f42 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -2474,8 +2474,6 @@ spec: url: type: string required: - - body - - method - url type: object type: object @@ -5038,8 +5036,6 @@ spec: url: type: string required: - - body - - method - url type: object type: object @@ -7529,8 +7525,6 @@ spec: url: type: string required: - - body - - method - url type: object type: object diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index 86c6eb2fce..c088f4fca1 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -398,7 +398,7 @@ type ScopeDetail struct { type WebMetric struct { // Method is the method of the web metric (empty defaults to GET) - Method WebMetricMethod `json:"method" protobuf:"bytes,1,opt,name=method"` + Method WebMetricMethod `json:"method,omitempty" protobuf:"bytes,1,opt,name=method"` // URL is the address of the web metric URL string `json:"url" protobuf:"bytes,2,opt,name=url"` // +patchMergeKey=key @@ -406,7 +406,7 @@ type WebMetric struct { // Headers are optional HTTP headers to use in the request Headers []WebMetricHeader `json:"headers,omitempty" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,3,rep,name=headers"` // Body is the body of the we metric (must be POST/PUT) - Body string `json:"body" protobuf:"bytes,4,opt,name=body"` + Body string `json:"body,omitempty" protobuf:"bytes,4,opt,name=body"` // TimeoutSeconds is the timeout for the request in seconds (default: 10) TimeoutSeconds int64 `json:"timeoutSeconds,omitempty" protobuf:"varint,5,opt,name=timeoutSeconds"` // JSONPath is a JSON Path to use as the result variable (default: "{$}") From 086ef67bd6c5eaaef8f98dd558eb272dbcde90cb Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Thu, 21 Oct 2021 10:04:15 +0300 Subject: [PATCH 6/7] bump Signed-off-by: Noam Gal From 7f412df7f5604ce856cb52926d295b6a7fbb17ba Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Thu, 21 Oct 2021 10:04:15 +0300 Subject: [PATCH 7/7] have an updated documentation for the web provider Signed-off-by: Noam Gal --- docs/analysis/web.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/analysis/web.md b/docs/analysis/web.md index 7e559b59d0..e3e133cec0 100644 --- a/docs/analysis/web.md +++ b/docs/analysis/web.md @@ -1,6 +1,6 @@ # Web Metrics -A HTTP request can be performed against some external service to obtain the measurement. This example +An HTTP request can be performed against some external service to obtain the measurement. This example makes a HTTP GET request to some URL. The webhook response must return JSON content. The result of the optional `jsonPath` expression will be assigned to the `result` variable that can be referenced in the `successCondition` and `failureCondition` expressions. If omitted, will use the entire body @@ -49,3 +49,26 @@ NOTE: if the result is a string, two convenience functions `asInt` and `asFloat` to convert a result value to a numeric type so that mathematical comparison operators can be used (e.g. >, <, >=, <=). +### Optional web methods +It is possible to use a POST or PUT requests, by specifying the `method` and `body` fields + +```yaml + metrics: + - name: webmetric + successCondition: result == true + provider: + web: + method: POST # valid values are GET|POST|PUT, defaults to GET + url: "http://my-server.com/api/v1/measurement?service={{ args.service-name }}" + timeoutSeconds: 20 # defaults to 10 seconds + headers: + - key: Authorization + value: "Bearer {{ args.api-token }}" + - key: Content-Type # if body is a json, it is recommended to set the Content-Type + value: "application/json" + body: "{\"key\": \"string value\"}" + jsonPath: "{$.data.ok}" +``` + !!! tip + In order to send in JSON, you have to encode it yourself, and send the correct Content-Type as well. + Setting a `body` field for a `GET` request will result in an error.