diff --git a/observabilityclient/rbac.py b/observabilityclient/rbac.py index 39741c4..a1e9887 100644 --- a/observabilityclient/rbac.py +++ b/observabilityclient/rbac.py @@ -18,10 +18,24 @@ from observabilityclient.utils.metric_utils import format_labels class PromQLRbac(object): - def __init__(self, prom_api_client, project_id): + def __init__(self, prom_api_client, project_id, project_label='project'): self.client = prom_api_client + + # NOTE(jwysogla): Since Prometheus 3, metric and label names can + # utilize all unicode characters. But the syntax is a little different + # and some parts of the queries need to be quoted or escaped. The + # rest of this module doesn't support that right now, so use a + # Prometheus 2 regex and raise an exception when it doesn't match. + # See https://prometheus.io/docs/concepts/data_model/ + label_name_regex = "[a-zA-Z_][a-zA-Z0-9_]*" + if not re.fullmatch(label_name_regex, project_label): + raise ValueError( + f"Project label {project_label} doesn't match the " + f"label name regex: {label_name_regex}" + ) + self.labels = { - "project": project_id + project_label: project_id } def _find_label_value_end(self, query, start, quote_char): diff --git a/observabilityclient/tests/unit/test_rbac.py b/observabilityclient/tests/unit/test_rbac.py index a5fb9e0..e6fb21f 100644 --- a/observabilityclient/tests/unit/test_rbac.py +++ b/observabilityclient/tests/unit/test_rbac.py @@ -192,3 +192,38 @@ class PromQLRbacTest(testtools.TestCase): expected = f"{query}{{project='{self.project_id}'}}" ret = self.rbac.append_rbac_labels(query) self.assertEqual(expected, ret) + + def test_setting_different_project_label_name(self): + query = 'test_query' + project_label = 'different_name' + project_value = 'some_project' + + rbac_instance = rbac.PromQLRbac( + mock.Mock(), project_value, project_label=project_label + ) + rbac_instance.client.label_values = lambda label: [ + query, + ] + + expected = f"{query}{{{project_label}='{project_value}'}}" + + ret = rbac_instance.modify_query(query) + + self.assertEqual(expected, ret) + + def test_setting_illegal_project_label_name(self): + # Try setting a label name with a white space character inside + project_label = 'different name' + project_value = 'some_project' + + args = (mock.Mock(), project_value) + kwargs = {'project_label': project_label} + + self.assertRaises(ValueError, rbac.PromQLRbac, *args, **kwargs) + + # Try setting an empty label name + project_label = '' + + kwargs = {'project_label': project_label} + + self.assertRaises(ValueError, rbac.PromQLRbac, *args, **kwargs) diff --git a/releasenotes/notes/allow-for-specifying-rbac-label-name-f99084757cde5f19.yaml b/releasenotes/notes/allow-for-specifying-rbac-label-name-f99084757cde5f19.yaml new file mode 100644 index 0000000..1bce416 --- /dev/null +++ b/releasenotes/notes/allow-for-specifying-rbac-label-name-f99084757cde5f19.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Allow for specifying project label name when creating an instance + of PromQLRbac. The change is backwards compatible, the same label + name 'project' is still being used as a default.