Skip to content

Commit c4124f8

Browse files
authored
Issue 118 (#121)
* feat: Add the DatasourceLabelBasedAccessControl support
1 parent 8da72c1 commit c4124f8

File tree

7 files changed

+248
-7
lines changed

7 files changed

+248
-7
lines changed

docs/content/grafana_api/datasource.md

+80
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
* [disable\_datasource\_cache](#datasource.DatasourceQueryResourceCaching.disable_datasource_cache)
3131
* [clean\_datasource\_cache](#datasource.DatasourceQueryResourceCaching.clean_datasource_cache)
3232
* [update\_datasource\_cache](#datasource.DatasourceQueryResourceCaching.update_datasource_cache)
33+
* [DatasourceLabelBasedAccessControl](#datasource.DatasourceLabelBasedAccessControl)
34+
* [get\_lbac\_rules\_for\_datasource](#datasource.DatasourceLabelBasedAccessControl.get_lbac_rules_for_datasource)
35+
* [update\_lbac\_rules\_for\_datasource](#datasource.DatasourceLabelBasedAccessControl.update_lbac_rules_for_datasource)
3336

3437
<a id="datasource"></a>
3538

@@ -852,3 +855,80 @@ The method includes a functionality to update the datasource cache specified by
852855

853856
- `api_call` _dict_ - Returns a datasource
854857

858+
<a id="datasource.DatasourceLabelBasedAccessControl"></a>
859+
860+
## DatasourceLabelBasedAccessControl Objects
861+
862+
```python
863+
class DatasourceLabelBasedAccessControl()
864+
```
865+
866+
The class includes all necessary methods to access the Grafana datasource label based access control for teams API endpoints. It's required that the API token got the corresponding datasource access rights. Please check the used methods docstring for the necessary access rights. The functionality is a Grafana Cloud feature. Only cloud Loki data sources are supported
867+
868+
**Arguments**:
869+
870+
- `grafana_api_model` _APIModel_ - Inject a Grafana API model object that includes all necessary values and information
871+
872+
873+
**Attributes**:
874+
875+
- `grafana_api_model` _APIModel_ - This is where we store the grafana_api_model
876+
877+
<a id="datasource.DatasourceLabelBasedAccessControl.get_lbac_rules_for_datasource"></a>
878+
879+
#### get\_lbac\_rules\_for\_datasource
880+
881+
```python
882+
def get_lbac_rules_for_datasource(uid: str) -> list
883+
```
884+
885+
The method includes a functionality to get all datasource label based access control rules for team specified by the datasource uid
886+
887+
**Arguments**:
888+
889+
- `uid` _str_ - Specify the uid of the datasource
890+
891+
Required Permissions:
892+
- `Action` - datasources:read
893+
- `Scope` - [datasources:*, datasources:uid:*, datasources:uid:<id>]
894+
895+
896+
**Raises**:
897+
898+
- `ValueError` - Missed specifying a necessary value
899+
- `Exception` - Unspecified error by executing the API call
900+
901+
902+
**Returns**:
903+
904+
- `api_call` _list_ - Returns all LBAC rules
905+
906+
<a id="datasource.DatasourceLabelBasedAccessControl.update_lbac_rules_for_datasource"></a>
907+
908+
#### update\_lbac\_rules\_for\_datasource
909+
910+
```python
911+
def update_lbac_rules_for_datasource(uid: str) -> dict
912+
```
913+
914+
The method includes a functionality to enable the datasource cache specified by the datasource uid
915+
916+
**Arguments**:
917+
918+
- `uid` _str_ - Specify the uid of the datasource
919+
920+
Required Permissions:
921+
- `Action` - datasources:write, datasources.permissions:write
922+
- `Scope` - [datasources:*, datasources:uid:*, datasources:uid:<id>]
923+
924+
925+
**Raises**:
926+
927+
- `ValueError` - Missed specifying a necessary value
928+
- `Exception` - Unspecified error by executing the API call
929+
930+
931+
**Returns**:
932+
933+
- `api_call` _dict_ - Returns a datasource
934+

grafana_api/alerting.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -965,9 +965,7 @@ def test_backtest_rule(self, condition: str, data_queries: list) -> dict:
965965
else:
966966
return api_call
967967
else:
968-
logging.error(
969-
"There is no condition or data_queries defined."
970-
)
968+
logging.error("There is no condition or data_queries defined.")
971969
raise ValueError
972970

973971
def delete_ngalert_organization_configuration(self):

grafana_api/datasource.py

+79
Original file line numberDiff line numberDiff line change
@@ -1059,3 +1059,82 @@ def update_datasource_cache(
10591059
"There is no uid or the right datasource_cache object defined."
10601060
)
10611061
raise ValueError
1062+
1063+
1064+
class DatasourceLabelBasedAccessControl:
1065+
"""The class includes all necessary methods to access the Grafana datasource label based access control for teams API endpoints. It's required that the API token got the corresponding datasource access rights. Please check the used methods docstring for the necessary access rights. The functionality is a Grafana Cloud feature. Only cloud Loki data sources are supported
1066+
1067+
Args:
1068+
grafana_api_model (APIModel): Inject a Grafana API model object that includes all necessary values and information
1069+
1070+
Attributes:
1071+
grafana_api_model (APIModel): This is where we store the grafana_api_model
1072+
"""
1073+
1074+
def __init__(self, grafana_api_model: APIModel):
1075+
self.grafana_api_model = grafana_api_model
1076+
1077+
def get_lbac_rules_for_datasource(self, uid: str) -> list:
1078+
"""The method includes a functionality to get all datasource label based access control rules for team specified by the datasource uid
1079+
1080+
Args:
1081+
uid (str): Specify the uid of the datasource
1082+
1083+
Required Permissions:
1084+
Action: datasources:read
1085+
Scope: [datasources:*, datasources:uid:*, datasources:uid:<id>]
1086+
1087+
Raises:
1088+
ValueError: Missed specifying a necessary value
1089+
Exception: Unspecified error by executing the API call
1090+
1091+
Returns:
1092+
api_call (list): Returns all LBAC rules
1093+
"""
1094+
1095+
if len(uid) != 0:
1096+
api_call: list = Api(self.grafana_api_model).call_the_api(
1097+
f"{APIEndpoints.DATASOURCES.value}/{uid}/lbac/teams",
1098+
)
1099+
1100+
if api_call is None:
1101+
logging.error(f"Check the error: {api_call}.")
1102+
raise Exception
1103+
else:
1104+
return api_call
1105+
else:
1106+
logging.error("There is no uid defined.")
1107+
raise ValueError
1108+
1109+
def update_lbac_rules_for_datasource(self, uid: str) -> dict:
1110+
"""The method includes a functionality to enable the datasource cache specified by the datasource uid
1111+
1112+
Args:
1113+
uid (str): Specify the uid of the datasource
1114+
1115+
Required Permissions:
1116+
Action: datasources:write, datasources.permissions:write
1117+
Scope: [datasources:*, datasources:uid:*, datasources:uid:<id>]
1118+
1119+
Raises:
1120+
ValueError: Missed specifying a necessary value
1121+
Exception: Unspecified error by executing the API call
1122+
1123+
Returns:
1124+
api_call (dict): Returns a datasource
1125+
"""
1126+
1127+
if len(uid) != 0:
1128+
api_call: dict = Api(self.grafana_api_model).call_the_api(
1129+
f"{APIEndpoints.DATASOURCES.value}/{uid}/lbac/teams",
1130+
RequestsMethods.POST,
1131+
)
1132+
1133+
if api_call == dict() or api_call.get("dataSourceID") is None:
1134+
logging.error(f"Check the error: {api_call}.")
1135+
raise Exception
1136+
else:
1137+
return api_call
1138+
else:
1139+
logging.error("There is no uid defined.")
1140+
raise ValueError

grafana_api/user.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def search_users_with_paging(
7171
results_per_page: int = 1000,
7272
page: int = 1,
7373
query: str = None,
74-
sort: str = None
74+
sort: str = None,
7575
) -> dict:
7676
"""The method includes a functionality to get all Grafana system users specified by the optional results_per_page, page, query, sort and general paging functionality
7777

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
setuptools.setup(
1010
name="grafana-api-sdk",
11-
version="0.7.2",
11+
version="0.8.0",
1212
author="Pascal Zimmermann",
1313
author_email="[email protected]",
1414
description="A Grafana API SDK",

tests/integrationtest/test_service_account.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,15 @@ def test_lifecycle_service_account(self):
6565
self.assertEqual(
6666
2, len(self.service_account.search_service_account().get("serviceAccounts"))
6767
)
68-
self.service_account.create_service_account_token_by_id(service_account.get("id"), "Test", "Viewer")
69-
self.assertEqual(1, self.service_account.search_service_account().get("serviceAccounts")[0].get("tokens"))
68+
self.service_account.create_service_account_token_by_id(
69+
service_account.get("id"), "Test", "Viewer"
70+
)
71+
self.assertEqual(
72+
1,
73+
self.service_account.search_service_account()
74+
.get("serviceAccounts")[0]
75+
.get("tokens"),
76+
)
7077

7178
self.service_account.delete_service_account(service_account.get("id"))
7279
self.assertEqual(

tests/unittests/test_datasource.py

+77
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
DatasourcePermissions,
1313
DatasourceLegacyPermissions,
1414
DatasourceQueryResourceCaching,
15+
DatasourceLabelBasedAccessControl,
1516
)
1617

1718

@@ -1022,3 +1023,79 @@ def test_update_datasource_cache_no_valid_result(self, call_the_api_mock):
10221023

10231024
with self.assertRaises(Exception):
10241025
datasource.update_datasource_cache("test", datasource_cache)
1026+
1027+
1028+
class DatasourceLabelBasedAccessControlTestCase(TestCase):
1029+
@patch("grafana_api.api.Api.call_the_api")
1030+
def test_get_lbac_rules_for_datasource(self, call_the_api_mock):
1031+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1032+
datasource: DatasourceLabelBasedAccessControl = (
1033+
DatasourceLabelBasedAccessControl(grafana_api_model=model)
1034+
)
1035+
1036+
call_the_api_mock.return_value = list([{"id": 1}])
1037+
1038+
self.assertEqual([{"id": 1}], datasource.get_lbac_rules_for_datasource("test"))
1039+
1040+
@patch("grafana_api.api.Api.call_the_api")
1041+
def test_get_lbac_rules_for_datasource_no_uid(self, call_the_api_mock):
1042+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1043+
datasource: DatasourceLabelBasedAccessControl = (
1044+
DatasourceLabelBasedAccessControl(grafana_api_model=model)
1045+
)
1046+
1047+
call_the_api_mock.return_value = None
1048+
1049+
with self.assertRaises(ValueError):
1050+
datasource.get_lbac_rules_for_datasource("")
1051+
1052+
@patch("grafana_api.api.Api.call_the_api")
1053+
def test_get_lbac_rules_for_datasource_no_valid_rules(self, call_the_api_mock):
1054+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1055+
datasource: DatasourceLabelBasedAccessControl = (
1056+
DatasourceLabelBasedAccessControl(grafana_api_model=model)
1057+
)
1058+
1059+
call_the_api_mock.return_value = None
1060+
1061+
with self.assertRaises(Exception):
1062+
datasource.get_lbac_rules_for_datasource("test")
1063+
1064+
@patch("grafana_api.api.Api.call_the_api")
1065+
def test_update_lbac_rules_for_datasource(self, call_the_api_mock):
1066+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1067+
datasource: DatasourceLabelBasedAccessControl = (
1068+
DatasourceLabelBasedAccessControl(grafana_api_model=model)
1069+
)
1070+
1071+
call_the_api_mock.return_value = dict({"dataSourceID": 1})
1072+
1073+
self.assertEqual(
1074+
{"dataSourceID": 1}, datasource.update_lbac_rules_for_datasource("test")
1075+
)
1076+
1077+
@patch("grafana_api.api.Api.call_the_api")
1078+
def test_update_lbac_rules_for_datasource_no_uid(self, call_the_api_mock):
1079+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1080+
datasource: DatasourceLabelBasedAccessControl = (
1081+
DatasourceLabelBasedAccessControl(grafana_api_model=model)
1082+
)
1083+
1084+
call_the_api_mock.return_value = None
1085+
1086+
with self.assertRaises(ValueError):
1087+
datasource.update_lbac_rules_for_datasource("")
1088+
1089+
@patch("grafana_api.api.Api.call_the_api")
1090+
def test_update_lbac_rules_for_datasource_no_update_possible(
1091+
self, call_the_api_mock
1092+
):
1093+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1094+
datasource: DatasourceLabelBasedAccessControl = (
1095+
DatasourceLabelBasedAccessControl(grafana_api_model=model)
1096+
)
1097+
1098+
call_the_api_mock.return_value = dict()
1099+
1100+
with self.assertRaises(Exception):
1101+
datasource.update_lbac_rules_for_datasource("test")

0 commit comments

Comments
 (0)