Repository navigation
ROB-1291 Prometheus tenant from the namespace label (option B: UI + alert graphs) #2215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
7cd21ca
ROB-1291 Send the Prometheus tenant from the namespace label
RoiGlinik b595f0e
ROB-1291 Prometheus tenant from the namespace param (UI graphs only)
RoiGlinik e7ce27d
ROB-1291 Alert graphs pick the Prometheus tenant from their namespace…
RoiGlinik d31e176
ROB-1291 Gate the tenant on PROMETHEUS_TENANT_LABEL, name it get_name…
RoiGlinik 48ca03a
ROB-1291 Tenant only for graphs about a namespace; graph the alert ex…
RoiGlinik cfe73d7
ROB-1291 Test tenant label keys with dots and a DNS prefix
RoiGlinik 0cf9f60
Merge branch 'master' into rob-1291-tenant-ui-and-alert-graphs
RoiGlinik fb4ccaf
ROB-1291 Detect $namespace with Template's parser, ignoring escaped $…
RoiGlinik File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| from datetime import datetime | ||
| from unittest.mock import patch | ||
|
|
||
| import pytest | ||
|
|
||
| from robusta.core.model.base_params import PrometheusParams | ||
| from robusta.core.playbooks import prometheus_enrichment_utils | ||
| from robusta.integrations.prometheus import utils | ||
| from robusta.integrations.prometheus.utils import generate_prometheus_config | ||
|
|
||
| NAMESPACES = {"shop": {"team": "corporate"}, "billing": {"team": "retail"}, "unlabeled": {"app": "web"}} | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def tenant_label(): | ||
| def labels(namespace): | ||
| return NAMESPACES[namespace] | ||
|
|
||
| with patch.object(utils, "PROMETHEUS_TENANT_LABEL", "team"), patch.object( | ||
| utils, "get_namespace_labels", side_effect=labels | ||
| ) as get_labels: | ||
| yield get_labels | ||
|
|
||
|
|
||
| def _headers(**params): | ||
| return generate_prometheus_config(PrometheusParams(prometheus_url="http://prometheus:9090", **params)).headers | ||
|
|
||
|
|
||
| def test_tenant_from_namespace_label(tenant_label): | ||
| assert _headers(namespace="shop") == {"X-Scope-OrgID": "corporate"} | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("label_key", ["product.productline", "example.com/productline"]) | ||
| def test_tenant_label_key_with_dots_or_prefix(label_key): | ||
| # The label key is used as written: dots and a DNS prefix are just part of the key | ||
| with patch.object(utils, "PROMETHEUS_TENANT_LABEL", label_key), patch.object( | ||
| utils, "get_namespace_labels", return_value={label_key: "corporate", "productline": "other"} | ||
| ): | ||
| assert _headers(namespace="shop") == {"X-Scope-OrgID": "corporate"} | ||
|
|
||
|
|
||
| def test_tenant_replaces_configured_one_and_keeps_other_headers(tenant_label): | ||
| headers = _headers(namespace="billing", prometheus_additional_headers={"X-Scope-OrgID": "default", "X-Other": "1"}) | ||
| assert headers == {"X-Scope-OrgID": "retail", "X-Other": "1"} | ||
|
|
||
|
|
||
| def test_no_namespace_keeps_default_tenant(tenant_label): | ||
| assert _headers(prometheus_additional_headers={"X-Scope-OrgID": "default"}) == {"X-Scope-OrgID": "default"} | ||
| tenant_label.assert_not_called() | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("namespace", ["unlabeled", "missing"]) | ||
| def test_unlabeled_or_unknown_namespace_keeps_default_tenant(tenant_label, namespace): | ||
| headers = _headers(namespace=namespace, prometheus_additional_headers={"X-Scope-OrgID": "default"}) | ||
| assert headers == {"X-Scope-OrgID": "default"} | ||
|
|
||
|
|
||
| def test_feature_off_reads_nothing(tenant_label): | ||
| with patch.object(utils, "PROMETHEUS_TENANT_LABEL", None): | ||
| assert not _headers(namespace="shop") | ||
| tenant_label.assert_not_called() | ||
|
|
||
|
|
||
| POD_QUERY = 'container_memory_working_set_bytes{namespace="$namespace", pod=~"$pod"}' | ||
| NODE_QUERY = 'node_memory_MemAvailable_bytes{instance=~"$node_internal_ip:.*"}' | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "tenant_label_env, params_namespace, query, labels, expected", | ||
| [ | ||
| ("team", None, POD_QUERY, {"namespace": "shop", "pod": "web"}, "shop"), # pod graph: its namespace | ||
| ("team", None, 'up{namespace="${namespace}"}', {"namespace": "shop"}, "shop"), # braced placeholder | ||
| ("team", None, 'up{label="$$namespace"}', {"namespace": "shop"}, None), # escaped: a literal "$namespace" | ||
| ("team", "billing", POD_QUERY, {"namespace": "shop"}, "billing"), # an explicit namespace wins | ||
| # node graph on a node alert that carries the exporter's namespace: not about it, default tenant | ||
| ("team", None, NODE_QUERY, {"namespace": "monitoring", "node_internal_ip": "10.0.0.1"}, None), | ||
| (None, None, POD_QUERY, {"namespace": "shop"}, None), # feature off: params untouched | ||
| ], | ||
| ) | ||
| def test_graph_enrichment_namespace(tenant_label_env, params_namespace, query, labels, expected): | ||
| params = PrometheusParams(namespace=params_namespace) | ||
| with patch.object(prometheus_enrichment_utils, "PROMETHEUS_TENANT_LABEL", tenant_label_env), patch.object( | ||
| prometheus_enrichment_utils, "create_chart_from_prometheus_query" | ||
| ) as create_chart: | ||
| create_chart.side_effect = Exception("stop") | ||
| with pytest.raises(Exception, match="stop"): | ||
| prometheus_enrichment_utils.create_graph_enrichment( | ||
| datetime.now(), labels, query, params, 60, None, None | ||
| ) | ||
| assert create_chart.call_args.args[0].namespace == expected | ||
| assert params.namespace == params_namespace | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "tenant_label_env, params_namespace, namespace, expected", | ||
| [ | ||
| ("team", None, "shop", "shop"), # e.g. graph_enricher with the alert's namespace | ||
| ("team", "billing", "shop", "billing"), | ||
| ("team", None, None, None), | ||
| (None, None, "shop", None), | ||
| ], | ||
| ) | ||
| def test_with_namespace_tenant(tenant_label_env, params_namespace, namespace, expected): | ||
| params = PrometheusParams(namespace=params_namespace) | ||
| with patch.object(prometheus_enrichment_utils, "PROMETHEUS_TENANT_LABEL", tenant_label_env): | ||
| result = prometheus_enrichment_utils.with_namespace_tenant(params, namespace) | ||
| assert result.namespace == expected | ||
| assert params.namespace == params_namespace | ||
|
|
||
|
|
||
| def test_configured_headers_are_not_changed(tenant_label): | ||
| configured = {"X-Scope-OrgID": "default"} | ||
| _headers(namespace="shop", prometheus_additional_headers=configured) | ||
| assert configured == {"X-Scope-OrgID": "default"} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.