Skip to content

Commit 88d3455

Browse files
committed
feat: Add the DatasourceLabelBasedAccessControl support
* docs: Add coverage badge
1 parent 8da72c1 commit 88d3455

File tree

4 files changed

+221
-1
lines changed

4 files changed

+221
-1
lines changed

docs/content/grafana_api/datasource.md

Lines changed: 80 additions & 0 deletions
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/datasource.py

Lines changed: 79 additions & 0 deletions
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

setup.py

Lines changed: 1 addition & 1 deletion
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/unittests/test_datasource.py

Lines changed: 61 additions & 0 deletions
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,63 @@ 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+
class DatasourceLabelBasedAccessControlTestCase(TestCase):
1028+
@patch("grafana_api.api.Api.call_the_api")
1029+
def test_get_lbac_rules_for_datasource(self, call_the_api_mock):
1030+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1031+
datasource: DatasourceLabelBasedAccessControl = DatasourceLabelBasedAccessControl(grafana_api_model=model)
1032+
1033+
call_the_api_mock.return_value = list([{"id": 1}])
1034+
1035+
self.assertEqual([{"id": 1}], datasource.get_lbac_rules_for_datasource("test"))
1036+
1037+
@patch("grafana_api.api.Api.call_the_api")
1038+
def test_get_lbac_rules_for_datasource_no_uid(self, call_the_api_mock):
1039+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1040+
datasource: DatasourceLabelBasedAccessControl = DatasourceLabelBasedAccessControl(grafana_api_model=model)
1041+
1042+
call_the_api_mock.return_value = None
1043+
1044+
with self.assertRaises(ValueError):
1045+
datasource.get_lbac_rules_for_datasource("")
1046+
1047+
@patch("grafana_api.api.Api.call_the_api")
1048+
def test_get_lbac_rules_for_datasource_no_valid_rules(self, call_the_api_mock):
1049+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1050+
datasource: DatasourceLabelBasedAccessControl = DatasourceLabelBasedAccessControl(grafana_api_model=model)
1051+
1052+
call_the_api_mock.return_value = None
1053+
1054+
with self.assertRaises(Exception):
1055+
datasource.get_lbac_rules_for_datasource("test")
1056+
1057+
@patch("grafana_api.api.Api.call_the_api")
1058+
def test_update_lbac_rules_for_datasource(self, call_the_api_mock):
1059+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1060+
datasource: DatasourceLabelBasedAccessControl = DatasourceLabelBasedAccessControl(grafana_api_model=model)
1061+
1062+
call_the_api_mock.return_value = dict({"dataSourceID": 1})
1063+
1064+
self.assertEqual({"dataSourceID": 1}, datasource.update_lbac_rules_for_datasource("test"))
1065+
1066+
@patch("grafana_api.api.Api.call_the_api")
1067+
def test_update_lbac_rules_for_datasource_no_uid(self, call_the_api_mock):
1068+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1069+
datasource: DatasourceLabelBasedAccessControl = DatasourceLabelBasedAccessControl(grafana_api_model=model)
1070+
1071+
call_the_api_mock.return_value = None
1072+
1073+
with self.assertRaises(ValueError):
1074+
datasource.update_lbac_rules_for_datasource("")
1075+
1076+
@patch("grafana_api.api.Api.call_the_api")
1077+
def test_update_lbac_rules_for_datasource_no_update_possible(self, call_the_api_mock):
1078+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
1079+
datasource: DatasourceLabelBasedAccessControl = DatasourceLabelBasedAccessControl(grafana_api_model=model)
1080+
1081+
call_the_api_mock.return_value = dict()
1082+
1083+
with self.assertRaises(Exception):
1084+
datasource.update_lbac_rules_for_datasource("test")
1085+

0 commit comments

Comments
 (0)