diff --git a/CHANGELOG.md b/CHANGELOG.md index edc25d81e4..3f538fb063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 4.10 - [#1299](https://github.com/openshift/cluster-monitoring-operator/pull/1299) Expose expose /api/v1/labels endpoint for Thanos query. + ## 4.9 - [#1312](https://github.com/openshift/cluster-monitoring-operator/pull/1312) Support label to exclude namespaces from user-workload monitoring. diff --git a/assets/thanos-querier/deployment.yaml b/assets/thanos-querier/deployment.yaml index c45428784b..dcded2c033 100644 --- a/assets/thanos-querier/deployment.yaml +++ b/assets/thanos-querier/deployment.yaml @@ -135,7 +135,7 @@ spec: - --tls-private-key-file=/etc/tls/private/tls.key - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 - --logtostderr=true - - --allow-paths="/api/v1/query,/api/v1/query_range,/api/v1/labels,/api/v1/label/*/values" + - --allow-paths=/api/v1/query,/api/v1/query_range,/api/v1/labels,/api/v1/label/*/values image: quay.io/brancz/kube-rbac-proxy:v0.11.0 name: kube-rbac-proxy ports: diff --git a/jsonnet/components/thanos-querier.libsonnet b/jsonnet/components/thanos-querier.libsonnet index 6aff1fc5cc..9c3a0c7e0e 100644 --- a/jsonnet/components/thanos-querier.libsonnet +++ b/jsonnet/components/thanos-querier.libsonnet @@ -479,7 +479,7 @@ function(params) '--tls-private-key-file=/etc/tls/private/tls.key', '--tls-cipher-suites=' + cfg.tlsCipherSuites, '--logtostderr=true', - '--allow-paths="/api/v1/query,/api/v1/query_range,/api/v1/labels,/api/v1/label/*/values"', + '--allow-paths=/api/v1/query,/api/v1/query_range,/api/v1/labels,/api/v1/label/*/values', ], terminationMessagePolicy: 'FallbackToLogsOnError', volumeMounts: [ diff --git a/test/e2e/framework/client.go b/test/e2e/framework/client.go index 5e0134f186..3b43fe04d1 100644 --- a/test/e2e/framework/client.go +++ b/test/e2e/framework/client.go @@ -211,6 +211,27 @@ func (c *PrometheusClient) PrometheusRules() ([]byte, error) { return body, nil } +// PrometheusRules runs an HTTP GET request against the Prometheus label API and returns +// the response body. +func (c *PrometheusClient) PrometheusLabel(label string) ([]byte, error) { + resp, err := c.Do("GET", fmt.Sprintf("/api/v1/label/%s/values", url.QueryEscape(label)), nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code response, want %d, got %d (%q)", http.StatusOK, resp.StatusCode, ClampMax(body)) + } + + return body, nil +} + // AlertmanagerQueryAlerts runs an HTTP GET request against the Alertmanager // /api/v2/alerts endpoint and returns the response body. func (c *PrometheusClient) AlertmanagerQueryAlerts(kvs ...string) ([]byte, error) { diff --git a/test/e2e/user_workload_monitoring_test.go b/test/e2e/user_workload_monitoring_test.go index a7fbc7a3cd..2799c1c69e 100644 --- a/test/e2e/user_workload_monitoring_test.go +++ b/test/e2e/user_workload_monitoring_test.go @@ -87,6 +87,10 @@ func TestUserWorkloadMonitoringMetrics(t *testing.T) { name: "assert tenancy model is enforced for metrics", f: assertTenancyForMetrics, }, + { + name: "assert tenancy model is enforced for labels", + f: assertTenancyForLabels, + }, { name: "assert prometheus is not deployed in user namespace", f: f.AssertStatefulsetDoesNotExist("prometheus-not-to-be-reconciled", userWorkloadTestNs), @@ -247,13 +251,13 @@ func TestUserWorkloadMonitoringWithAdditionalAlertmanagerConfigs(t *testing.T) { timeout: "30s" apiVersion: v1 tlsConfig: - key: + key: name: alertmanager-tls key: tls.key - cert: + cert: name: alertmanager-tls key: tls.crt - ca: + ca: name: alertmanager-tls key: tls.ca staticConfigs: ["127.0.0.1", "127.0.0.2"] @@ -860,6 +864,193 @@ func assertTenancyForRules(t *testing.T) { } } +func assertTenancyForLabels(t *testing.T) { + const testAccount = "test-labels" + + _, err := f.CreateServiceAccount(userWorkloadTestNs, testAccount) + if err != nil { + t.Fatal(err) + } + + // Grant enough permissions to read labels. todo: check if need create new role + _, err = f.CreateRoleBindingFromClusterRole(userWorkloadTestNs, testAccount, "admin") + if err != nil { + t.Fatal(err) + } + + var token string + err = framework.Poll(5*time.Second, 5*time.Minute, func() error { + token, err = f.GetServiceAccountToken(userWorkloadTestNs, testAccount) + if err != nil { + return err + } + return nil + }) + if err != nil { + t.Fatal(err) + } + + // The tenancy port (9092) is only exposed in-cluster so we need to use + // port forwarding to access kube-rbac-proxy. + host, cleanUp, err := f.ForwardPort(t, "thanos-querier", 9092) + if err != nil { + t.Fatal(err) + } + defer cleanUp() + + client := framework.NewPrometheusClient( + host, + token, + &framework.QueryParameterInjector{ + Name: "namespace", + Value: userWorkloadTestNs, + }, + ) + + t.Logf("Checking all labels") + + // check /api/v1/labels end point + err = framework.Poll(5*time.Second, time.Minute, func() error { + resp, err := client.Do("GET", "/api/v1/labels", nil) + if err != nil { + return err + } + defer resp.Body.Close() + + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code response, want %d, got %d (%s)", http.StatusOK, resp.StatusCode, framework.ClampMax(b)) + } + + res, err := gabs.ParseJSON(b) + if err != nil { + return err + } + + labels, err := res.Path("data").Children() + if err != nil { + return err + } + + for _, label := range labels { + t.Logf("label %q", label.Data().(string)) + } + + if len(labels) == 0 { + return errors.Errorf("expecting a label list with at least one item.") + } + + return nil + + }) + if err != nil { + t.Fatalf("failed to query labels from Thanos querier: %v", err) + } + + // check /api/v1/label/