diff --git a/datadog/api/__init__.py b/datadog/api/__init__.py index 099fec26b..56e5bc95d 100644 --- a/datadog/api/__init__.py +++ b/datadog/api/__init__.py @@ -36,5 +36,7 @@ from datadog.api.service_checks import ServiceCheck from datadog.api.tags import Tag from datadog.api.users import User +from datadog.api.roles import Roles +from datadog.api.permissions import Permissions from datadog.api.service_level_objectives import ServiceLevelObjective from datadog.api.synthetics import Synthetics diff --git a/datadog/api/permissions.py b/datadog/api/permissions.py new file mode 100644 index 000000000..7310d769b --- /dev/null +++ b/datadog/api/permissions.py @@ -0,0 +1,11 @@ +from datadog.api.resources import ActionAPIResource, CreateableAPIResource, CustomUpdatableAPIResource, \ + DeletableAPIResource, GetableAPIResource, ListableAPIResource + + +class Permissions(ActionAPIResource, CreateableAPIResource, CustomUpdatableAPIResource, GetableAPIResource, + ListableAPIResource, DeletableAPIResource): + """ + A wrapper around Tag HTTP API. + """ + _resource_name = 'permissions' + _api_version = 'v2' diff --git a/datadog/api/resources.py b/datadog/api/resources.py index 6b4df6818..16f96aa87 100644 --- a/datadog/api/resources.py +++ b/datadog/api/resources.py @@ -123,6 +123,44 @@ def update(cls, id, params=None, **body): return APIClient.submit('PUT', path, api_version, body, **params) +class CustomUpdatableAPIResource(object): + """ + Updatable API Resource with custom HTTP Verb + """ + @classmethod + def update(cls, method=None, id=None, params=None, **body): + """ + Update an API resource object + + :param method: HTTP method, defaults to PUT + :type params: string + + :param params: updatable resource id + :type params: string + + :param params: updated resource object source + :type params: dictionary + + :param body: updated resource object attributes + :type body: dictionary + + :returns: Dictionary representing the API's JSON response + """ + + if method is None: + method = 'PUT' + if params is None: + params = {} + + path = '{resource_name}/{resource_id}'.format( + resource_name=cls._resource_name, + resource_id=id + ) + api_version = getattr(cls, '_api_version', None) + + return APIClient.submit(method, path, api_version, body, **params) + + class DeletableAPIResource(object): """ Deletable API Resource diff --git a/datadog/api/roles.py b/datadog/api/roles.py new file mode 100644 index 000000000..98cc3446b --- /dev/null +++ b/datadog/api/roles.py @@ -0,0 +1,61 @@ +from datadog.api.resources import ActionAPIResource, CreateableAPIResource, CustomUpdatableAPIResource,\ + DeletableAPIResource, GetableAPIResource, ListableAPIResource + +from datadog.api.api_client import APIClient + + +class Roles(ActionAPIResource, CreateableAPIResource, CustomUpdatableAPIResource, GetableAPIResource, + ListableAPIResource, DeletableAPIResource): + """ + A wrapper around Tag HTTP API. + """ + _resource_name = 'roles' + _api_version = 'v2' + + @classmethod + def update(cls, id, **body): + """ + Update a role's attributes + + :param id: uuid of the role + :param body: dict with type of the input and modified attributes + :returns: Dictionary representing the API's JSON response + """ + params = {} + return super(Roles, cls).update("PATCH", id, params=params, **body) + + @classmethod + def assign_permission(cls, id, **body): + """ + Assign permission to a role + + :param id: uuid of the role to assign permission to + :param body: dict with "type": "permissions" and uuid of permission to assign + :returns: Dictionary representing the API's JSON response + """ + params = {} + path = '{resource_name}/{resource_id}/permissions'.format( + resource_name=cls._resource_name, + resource_id=id + ) + api_version = getattr(cls, '_api_version', None) + + return APIClient.submit("POST", path, api_version, body, **params) + + @classmethod + def unassign_permission(cls, id, **body): + """ + Unassign permission from a role + + :param id: uuid of the role to unassign permission from + :param body: dict with "type": "permissions" and uuid of permission to unassign + :returns: Dictionary representing the API's JSON response + """ + params = {} + path = '{resource_name}/{resource_id}/permissions'.format( + resource_name=cls._resource_name, + resource_id=id + ) + api_version = getattr(cls, '_api_version', None) + + return APIClient.submit("DELETE", path, api_version, body, **params) diff --git a/tests/integration/api/test_api.py b/tests/integration/api/test_api.py index c4d27780b..e39d89a73 100644 --- a/tests/integration/api/test_api.py +++ b/tests/integration/api/test_api.py @@ -615,3 +615,69 @@ def test_user_crud(self): u = dog.User.get_all() assert "users" in u assert len(u["users"]) >= 1 + + @pytest.mark.admin_needed + def test_roles_crud(self): + role_name = "test_role" + + data = { + "type": "roles", + "attributes": { + "name": role_name + } + } + + # test create role + role = dog.Roles.create(data=data) + assert "roles" in role["data"]["type"] + assert role["data"]["id"] is not None + assert role["data"]["attributes"]["name"] == role_name + + role_uuid = role["data"]["id"] + + # test update role + new_role_name = "test_role_2" + data = { + "type": "roles", + "attributes": { + "name": new_role_name + } + } + + role = dog.Roles.update(role_uuid, data=data) + assert "roles" in role["data"]["type"] + assert role["data"]["id"] is not None + assert role["data"]["attributes"]["name"] == new_role_name + + # test assign permission + + permissions = dog.Permissions.get_all() + assert "permissions" in permissions["data"][0]["type"] + assert len(permissions["data"]) > 0 + + permission_uuid = permissions["data"][0]["id"] + data = { + "type": "permissions", + "id": permission_uuid + } + + role = dog.Roles.assign_permission(role_uuid, data=data) + assert "permissions" in role["data"][0]["type"] + + # test unassign permission + data = { + "type": "permissions", + "id": permission_uuid + } + + role = dog.Roles.unassign_permission(role_uuid, data=data) + assert "permissions" in role["data"][0]["type"] + assert len(permissions["data"]) > 0 + + + # test delete role + dog.Roles.delete(role_uuid) + + # check if new role is deleted successfully + res = dog.Roles.get(role_uuid) + assert "errors" in res