diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..42cc2d9 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 8b2f5ef..734eeab 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ dist docs/_build docs/README.rst .idea/ +venv/ \ No newline at end of file diff --git a/README.rst b/README.rst index 3725223..0050281 100644 --- a/README.rst +++ b/README.rst @@ -162,6 +162,15 @@ Look for an existing alert and delete it so that we can recreate it logging.info("Deleting existing alert with name: %s id: %s", alert_name, alertobj.argus_id) argus.alerts.delete(alertobj.argus_id) +Update and create groups and give permissions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + logging.info("Looking up existing group with groupID %s", groupID) + groupObj = + + Finally, create alert with a trigger and a notification ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/argusclient/__init__.py b/argusclient/__init__.py index 2cabd66..4ff223d 100644 --- a/argusclient/__init__.py +++ b/argusclient/__init__.py @@ -6,5 +6,5 @@ # For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause # -from .client import ArgusServiceClient, ArgusException, ArgusAuthException, ArgusObjectNotFoundException, MetricQuery, AnnotationQuery -from .model import Namespace, Metric, Annotation, Dashboard, Alert, Trigger, Notification, User, AddListResult +from .client import ArgusServiceClient, GroupPermissionsServiceClient, ArgusException, ArgusAuthException, ArgusObjectNotFoundException, MetricQuery, AnnotationQuery +from .model import Namespace, Metric, Annotation, GroupPermission, Dashboard, Alert, Trigger, Notification, User, AddListResult diff --git a/argusclient/client.py b/argusclient/client.py index e939f62..b2e3212 100644 --- a/argusclient/client.py +++ b/argusclient/client.py @@ -4,20 +4,20 @@ and `web service reference `__. """ +import json +import logging +import os # # Copyright (c) 2016, salesforce.com, inc. # All rights reserved. -# Licensed under the BSD 3-Clause license. +# Licensed under the BSD 3-Clause license. # For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause # -import unicodedata from collections import Mapping +from lib2to3.pytree import convert import requests -import json -import os -import logging -import collections + try: import http.client as httplib # Python 3 except ImportError: @@ -25,31 +25,51 @@ from functools import wraps from .model import Namespace, Metric, Annotation, Dashboard, Alert, Trigger, Notification, JsonEncoder, JsonDecoder, \ - Permission + Permission, GroupPermission REQ_METHOD = "req_method" REQ_PATH = "req_path" REQ_PARAMS = "req_params" REQ_BODY = "req_body" + + +def convert(input): + if isinstance(input, Mapping): + return {convert(key): convert(value) for key, value in input.items()} + elif isinstance(input, list): + return [convert(element) for element in input] + elif isinstance(input, basestring): + ret = str(input) + if ret.isdigit(): + ret = int(ret) + return ret + else: + return input + + + class ArgusException(Exception): """ An exception type that is thrown for Argus service errors. """ pass + class ArgusAuthException(ArgusException): """ An exception type that is thrown for Argus authentication errors. """ pass + class ArgusObjectNotFoundException(ArgusException): """ An exception type that is thrown for Argus object not found errors. """ pass + class BaseQuery(object): def __init__(self, baseExpr, *tailParams, **kwargs): self.baseExpr = baseExpr @@ -80,9 +100,11 @@ class MetricQuery(BaseQuery): >>> print str(mquery) -1d:-0d:test.scope:test.metric{test.tag=test.value}:sum:test.namespace """ - def __init__(self, scope, metric, aggregator, tags=None, namespace=None, downsampler=None, stTimeSpec=None, enTimeSpec=None): + + def __init__(self, scope, metric, aggregator, tags=None, namespace=None, downsampler=None, stTimeSpec=None,enTimeSpec=None): # NOTE: Namespace no longer goes into the metric expression, so we pass it down as a tail parameter. - super(MetricQuery, self).__init__(str(Metric(scope, metric, tags=tags)), aggregator, downsampler, namespace, stTimeSpec=stTimeSpec, enTimeSpec=enTimeSpec) + super(MetricQuery, self).__init__(str(Metric(scope, metric, tags=tags)), aggregator, downsampler, namespace, + stTimeSpec=stTimeSpec, enTimeSpec=enTimeSpec) class AnnotationQuery(BaseQuery): @@ -94,8 +116,9 @@ class AnnotationQuery(BaseQuery): >>> print str(mquery) -1d:-0d:test.scope:test.metric{test.tag=test.value}:test.source """ + def __init__(self, scope, metric, source, tags=None, stTimeSpec=None, enTimeSpec=None): - super(AnnotationQuery, self).__init__(str(Annotation(source, scope, metric, None, None, None, tags=tags)), stTimeSpec=stTimeSpec, enTimeSpec=enTimeSpec) + super(AnnotationQuery, self).__init__(str(Annotation(source, scope, metric, None, None, None, tags=tags)),stTimeSpec=stTimeSpec, enTimeSpec=enTimeSpec) class BaseCollectionServiceClient(object): @@ -131,6 +154,7 @@ class MetricCollectionServiceClient(BaseCollectionServiceClient): There is no need to instantiate this directly, as it is available as :attr:`argusclient.client.ArgusServiceClient.metrics` attribute. """ + def __init__(self, argus): super(MetricCollectionServiceClient, self).__init__(MetricQuery, Metric, argus, "metrics", "collection/metrics") @@ -141,8 +165,9 @@ class AnnotationCollectionServiceClient(BaseCollectionServiceClient): There is no need to instantiate this directly, as it is available as :attr:`argusclient.client.ArgusServiceClient.annotations` attribute. """ + def __init__(self, argus): - super(AnnotationCollectionServiceClient, self).__init__(AnnotationQuery, Annotation, argus, "annotations", "collection/annotations") + super(AnnotationCollectionServiceClient, self).__init__(AnnotationQuery, Annotation, argus, "annotations","collection/annotations") class BaseModelServiceClient(object): @@ -163,9 +188,11 @@ def _init_all(self, coll=None): if not self._retrieved_all: self._coll = dict((obj.argus_id, self._fill(obj)) for obj in (coll or self.argus._request(self.get_all_req_opts.get(REQ_METHOD, "get"), - self.get_all_req_opts.get(REQ_PATH, None), - params=self.get_all_req_opts.get(REQ_PARAMS, None), - dataObj=self.get_all_req_opts.get(REQ_BODY, None)))) + self.get_all_req_opts.get(REQ_PATH, None), + params=self.get_all_req_opts.get(REQ_PARAMS, + None), + dataObj=self.get_all_req_opts.get(REQ_BODY, + None)))) self._retrieved_all = True def _fill(self, obj): @@ -246,6 +273,7 @@ class UsersServiceClient(BaseModelServiceClient): There is no need to instantiate this directly, as it is available as :attr:`argusclient.client.ArgusServiceClient.users` attribute. """ + def __init__(self, argus): super(UsersServiceClient, self).__init__(argus) self._coll_by_name = {} @@ -276,6 +304,7 @@ class NamespacesServiceClient(BaseModelServiceClient): There is no need to instantiate this directly, as it is available as :attr:`argusclient.client.ArgusServiceClient.namespaces` attribute. """ + def __init__(self, argus): super(NamespacesServiceClient, self).__init__(argus, get_all_req_opts={REQ_PATH: "namespace"}) @@ -363,6 +392,7 @@ class DashboardsServiceClient(BaseUpdatableModelServiceClient): There is no need to instantiate this directly, as it is available as :attr:`argusclient.client.ArgusServiceClient.dashboards` attribute. """ + def __init__(self, argus, get_all_req_opts=None): """ :param get_all_req_opts: See BaseModelServiceClient.__init__() for description. @@ -410,12 +440,80 @@ def get_user_dashboards(self, ownerName=None, shared=True, limit=None, version=N return self.argus._request("get", "dashboards", params=dict(owner=ownerName, shared=shared, limit=limit, version=version)) + +class GroupPermissionsServiceClient(BaseUpdatableModelServiceClient): + """ + Service class that interfaces with the Argus grouppermissions endpoint. + + There is no need to instantiate this directly, as it is available as :attr:`argusclient.client.ArgusServiceClient.grouppermissions` attribute. + """ + + def __init__(self, argus, get_all_req_opts=None): + """ + :param get_all_req_opts: See BaseModelServiceClient.__init__() for description. + """ + if not get_all_req_opts: + get_all_req_opts = {} + get_all_req_opts.setdefault(REQ_PATH, "grouppermission") + print("init happening") + super(GroupPermissionsServiceClient, self).__init__(Permission, argus, id_path="grouppermission/", + get_all_req_opts=get_all_req_opts) + + def _init_all(self, coll=None): + if not self.get_all_req_opts.get(REQ_PATH): + raise TypeError("Unsupported operation on: %s" % type(self)) + if not self._retrieved_all: + resp = convert(self.argus._request(self.get_all_req_opts.get(REQ_METHOD, "get"), + self.get_all_req_opts.get(REQ_PATH, None), + params=self.get_all_req_opts.get(REQ_PARAMS, None), + dataObj=self.get_all_req_opts.get(REQ_BODY, None))) + for group_id, perms in resp.items(): + self._coll[group_id] = perms + self._retrieved_all = True + + + def get_permissions_for_group(self, groupId): + resp = convert(self.argus._request("get", "grouppermission", params=list(groupId))) + if resp: + for group_id, perms in resp.items(): + self._coll[group_id] = perms + return self._coll + + def add_permissions_for_group(self, grouppermission): + """ + Updates permissions in groups + :return: a list of :class:`argusclient.model.GroupPermission` objects with all fields populated. + """ + if not isinstance(grouppermission, GroupPermission): + raise TypeError("Need a GroupPermission object, got: %s" % type(grouppermission)) + + updatedGroup = convert(self.argus._request("post", "grouppermission", dataObj=grouppermission)) + self._coll[updatedGroup.groupId] = updatedGroup.permissionIds + return updatedGroup + + def delete_permissions_for_group(self, grouppermission): + deleted_permission = None + if not isinstance(grouppermission, Permission): + raise TypeError("Need a Permission object, got: %s" % type(grouppermission)) + perms_to_delete = grouppermission.permissionIds + if perms_to_delete == []: + raise ValueError("Permission is not already assigned and hence cant be deleted") + if tuple(perms_to_delete) in self._coll: + deleted_permission = convert(self.argus._request("delete", "grouppermission", dataObj=grouppermission)) + if deleted_permission: + return True + return False + + + + class PermissionsServiceClient(BaseUpdatableModelServiceClient): """ Service class that interfaces with the Argus permissions endpoint. There is no need to instantiate this directly, as it is available as :attr:`argusclient.client.ArgusServiceClient.permissions` attribute. """ + def __init__(self, argus, get_all_req_opts=None): """ :param get_all_req_opts: See BaseModelServiceClient.__init__() for description. @@ -432,9 +530,9 @@ def _init_all(self, coll=None): raise TypeError("Unsupported operation on: %s" % type(self)) if not self._retrieved_all: resp = convert(self.argus._request(self.get_all_req_opts.get(REQ_METHOD, "get"), - self.get_all_req_opts.get(REQ_PATH, None), - params=self.get_all_req_opts.get(REQ_PARAMS, None), - dataObj=self.get_all_req_opts.get(REQ_BODY, None))) + self.get_all_req_opts.get(REQ_PATH, None), + params=self.get_all_req_opts.get(REQ_PARAMS, None), + dataObj=self.get_all_req_opts.get(REQ_BODY, None))) for id, perms in resp.items(): self._coll[id] = perms self._retrieved_all = True @@ -446,7 +544,9 @@ def get_permissions_for_entities(self, entity_ids): :return: a dict of entity id's mapped to a list of :class:`argusclient.model.Permission` objects """ entityIds = [] + # Filter out entity id's for which the permissions have already been queried + for entity_id in entity_ids: if entity_id not in self._coll: entityIds.append(entity_id) @@ -479,24 +579,14 @@ def delete(self, entity_id, permission): if not isinstance(permission, Permission): raise TypeError("Need a Permission object, got: %s" % type(permission)) if permission.type == "user" and permission.permissionIds == []: + raise ValueError("Deleting a user permission requires the permission that needs to be revoked") + updated_permission = self.argus._request("delete", "permission/%s" % entity_id, dataObj=permission) if updated_permission.entityId in self._coll: del self._coll[updated_permission.entityId] -def convert(input): - if isinstance(input, Mapping): - return {convert(key): convert(value) for key, value in input.iteritems()} - elif isinstance(input, list): - return [convert(element) for element in input] - elif isinstance(input, basestring): - ret = str(input) - if ret.isdigit(): - ret = int(ret) - return ret - else: - return input class AlertsServiceClient(BaseUpdatableModelServiceClient): @@ -518,6 +608,7 @@ class AlertsServiceClient(BaseUpdatableModelServiceClient): Interfaces with the Argus alert notifications endpoint. """ + def __init__(self, argus, get_all_req_opts=None): """ :param get_all_req_opts: See BaseModelServiceClient.__init__() for description. @@ -581,7 +672,8 @@ def get_notification_trigger(self, alertid, notificationid, triggerid): if not notificationid: raise ValueError("Need to specify a notificationid") if not triggerid: raise ValueError("Need to specify a triggerid") # TODO: Update self._coll - return self.argus._request("get", "alerts/%s/notifications/%s/triggers/%s" % (alertid, notificationid, triggerid)) + return self.argus._request("get", + "alerts/%s/notifications/%s/triggers/%s" % (alertid, notificationid, triggerid)) def add_notification_trigger(self, alertid, notificationid, triggerid): """ @@ -593,7 +685,8 @@ def add_notification_trigger(self, alertid, notificationid, triggerid): if not notificationid: raise ValueError("Need to specify a notificationid") if not triggerid: raise ValueError("Need to specify a triggerid") # TODO: Update self._coll - return self.argus._request("post", "alerts/%s/notifications/%s/triggers/%s" % (alertid, notificationid, triggerid)) + return self.argus._request("post", + "alerts/%s/notifications/%s/triggers/%s" % (alertid, notificationid, triggerid)) def delete_notification_trigger(self, alertid, notificationid, triggerid): """ @@ -613,7 +706,8 @@ def get_user_alert(self, ownerName, alertName, shared=True): """ assert alertName, "Expected an alert name" assert ownerName, "Expected a owner name" - alerts = self.argus._request("get", "alerts/meta", params=dict(alertname=alertName, ownername=ownerName, shared=shared)) + alerts = self.argus._request("get", "alerts/meta", + params=dict(alertname=alertName, ownername=ownerName, shared=shared)) if not alerts: return None else: @@ -628,7 +722,9 @@ def get_alerts_allinfo(self, ownerName=None, alertNameContains=None, shared=Fals :return: the list of :class:`argusclient.model.Alert` objects, with all fields populated, including triggers and notifications """ - return self.argus._request("get", "alerts/allinfo", params=dict(ownername=ownerName, alertNameContains=alertNameContains, shared=shared, limit=limit)) + return self.argus._request("get", "alerts/allinfo", + params=dict(ownername=ownerName, alertNameContains=alertNameContains, shared=shared, + limit=limit)) ''' Functions to enable support for composite alerts @@ -648,7 +744,7 @@ def get_composite_alert_children(self, comp_alert_id): uri_path = "alerts/{}/children".format(comp_alert_id) child_alerts = self.argus._request("get", uri_path) child_alerts = [self._fill(child_alert) for child_alert in child_alerts] - return child_alerts + return child_alerts def get_composite_alert_children_info(self, comp_alert_id): """ @@ -665,7 +761,6 @@ def get_composite_alert_children_info(self, comp_alert_id): uri_path = "alerts/{}/children/info".format(comp_alert_id) return self.argus._request("get", uri_path) - def add_child_alert_to_composite_alert(self, comp_alert_id, alert): """ Add child alert to a composite alert @@ -688,7 +783,6 @@ def add_child_alert_to_composite_alert(self, comp_alert_id, alert): self._coll[alert_obj.id] = alert_obj return alert_obj - def delete_child_alert_from_composite_alert(self, comp_alert_id, child_alert_id): """ Delete a child alert from a composite alert @@ -701,7 +795,8 @@ def delete_child_alert_from_composite_alert(self, comp_alert_id, child_alert_id) """ if not comp_alert_id: raise ValueError("Need to specify a composite alert id") if not child_alert_id: raise ValueError("Need to specify a child alert id") - if not isinstance(comp_alert_id, int): raise TypeError("Need a composite Alert ID, got: %s" % type(comp_alert_id)) + if not isinstance(comp_alert_id, int): raise TypeError( + "Need a composite Alert ID, got: %s" % type(comp_alert_id)) if not isinstance(child_alert_id, int): raise TypeError("Need an Alert ID, got: %s" % type(child_alert_id)) uri_path = "alerts/{}/children/{}".format(comp_alert_id, child_alert_id) @@ -740,7 +835,8 @@ def add(self, trigger): try: return next(t for t in triggers if t.name == trigger.name) except StopIteration: - raise ArgusException("This is unexpected... trigger: %s not found after successfully adding it" % trigger.name) + raise ArgusException( + "This is unexpected... trigger: %s not found after successfully adding it" % trigger.name) def delete(self, id): super(AlertTriggersServiceClient, self).delete(id) @@ -753,11 +849,14 @@ class AlertNotificationsServiceClient(BaseUpdatableModelServiceClient): There is no need to instantiate this directly, as it is available as :attr:`argusclient.client.AlertsServiceClient.notifications` attribute. """ + def __init__(self, argus, alert): assert alert, "Expected an alert at this point" assert alert.id, "Alert expected to have an id at this point" - super(AlertNotificationsServiceClient, self).__init__(Notification, argus, id_path="alerts/%s/notifications/%%s" % alert.id, - get_all_req_opts={REQ_PATH: "alerts/%s/notifications" % alert.id}) + super(AlertNotificationsServiceClient, self).__init__(Notification, argus, + id_path="alerts/%s/notifications/%%s" % alert.id, + get_all_req_opts={ + REQ_PATH: "alerts/%s/notifications" % alert.id}) self.alert = alert if alert.notifications: self._init_all(alert.notifications) @@ -768,7 +867,8 @@ def add(self, notification): :return: the added :class:`argusclient.model.Notification` with all fields populated. """ - if not isinstance(notification, Notification): raise TypeError("Need a Notification object, got: %s" % type(notification)) + if not isinstance(notification, Notification): raise TypeError( + "Need a Notification object, got: %s" % type(notification)) if notification.argus_id: raise ValueError("A new Notification can't have an id") notifications = self.argus._request("post", "alerts/%s/notifications" % self.alert.id, dataObj=notification) self._init_all(notifications) @@ -776,7 +876,8 @@ def add(self, notification): try: return next(n for n in notifications if n.name == notification.name) except StopIteration: - raise ArgusException("This is unexpected... notification: %s not found after successfully adding it" % notification.name) + raise ArgusException( + "This is unexpected... notification: %s not found after successfully adding it" % notification.name) def delete(self, id): super(AlertNotificationsServiceClient, self).delete(id) @@ -807,8 +908,8 @@ def with_auth_token(*args, **kwargs): if not argus.accessToken and argus.refreshToken: try: res = argus._request_no_auth("post", - "v2/auth/token/refresh", - dataObj=dict(refreshToken=argus.refreshToken)) + "v2/auth/token/refresh", + dataObj=dict(refreshToken=argus.refreshToken)) argus.accessToken = res["accessToken"] except ArgusAuthException: if argus.password: @@ -818,8 +919,8 @@ def with_auth_token(*args, **kwargs): if not argus.accessToken and argus.password: argus.refreshToken = None res = argus._request_no_auth("post", - "v2/auth/login", - dataObj=dict(username=argus.user, password=argus.password)) + "v2/auth/login", + dataObj=dict(username=argus.user, password=argus.password)) argus.refreshToken, argus.accessToken = res["refreshToken"], res["accessToken"] try: @@ -861,6 +962,12 @@ class ArgusServiceClient(object): Interfaces with the Argus permissions endpoint. + ..attribute:: grouppermissions + + :class: `argusclient.client.GroupPermissionsServiceClient` + + Interfaces with the argus group permissions endpoint + .. attribute:: users :class:`argusclient.client.UsersServiceClient` @@ -898,6 +1005,7 @@ def __init__(self, user, password, endpoint, timeout=(10, 120), refreshToken=Non :param accessToken: A token that can be used to authenticate with Argus. If a ``refreshToken`` or ``password`` is specified, the ``accessToken`` will be refreshed as and when it is needed. :type refreshToken: str """ + if not user: raise ValueError("A valid user must be specified") if not any((password, refreshToken, accessToken)): @@ -918,6 +1026,7 @@ def __init__(self, user, password, endpoint, timeout=(10, 120), refreshToken=Non self.permissions = PermissionsServiceClient(self) self.users = UsersServiceClient(self) self.namespaces = NamespacesServiceClient(self) + self.grouppermissions = GroupPermissionsServiceClient(self) self.alerts = AlertsServiceClient(self) self.conn = requests.Session() @@ -936,7 +1045,7 @@ def logout(self): Logs out of the Argus service and destroys the session. """ # The new V2 auth doesn't support a logout, so just clear the tokens. - #self._request("get", "auth/logout") + # self._request("get", "auth/logout") self.refreshToken = self.accessToken = None @retry_auth @@ -964,15 +1073,19 @@ def _request_no_auth(self, method, path, params=None, dataObj=None, encCls=JsonE url = os.path.join(self.endpoint, path) req_method = getattr(self.conn, method) data = dataObj and json.dumps(dataObj, cls=encCls) or None - logging.debug("%s request with params: %s data length %s on: %s", method.upper(), params, data and len(data) or 0, url) # Mainly for the sake of data length + logging.debug("%s request with params: %s data length %s on: %s", method.upper(), params, + data and len(data) or 0, url) # Mainly for the sake of data length # Argus seems to recognized "Accept" header for "application/json" and "application/ms-excel", but the former is the default. headers = {"Content-Type": "application/json"} if self.accessToken: + headers["Authorization"] = "Bearer "+self.accessToken + resp = req_method(url, data=data, params=params, headers=headers, timeout=self.timeout) + print("This is response",resp) res = check_success(resp, decCls) return res diff --git a/argusclient/model.py b/argusclient/model.py index db7d4e9..589faec 100644 --- a/argusclient/model.py +++ b/argusclient/model.py @@ -265,10 +265,29 @@ class Permission(BaseEncodable): id_fields = ("type",) VALID_TYPES = frozenset(("user", "group")) + def __init__(self, type, **kwargs): - assert type in Permission.VALID_TYPES, "Permission type %s is not valid" % type + assert type in Permission.VALID_TYPES, "permission type is not valid: %s" % type super(Permission, self).__init__(type=type, **kwargs) +class GroupPermission(BaseEncodable): + """ + Represents a Group permission object in Argus + + :param groupId : the id of the group to be given permissions to + :type groupId: str + :type grouppermissionIds: List of permissions that this group + has on the associated entity (id is put in the entityId field). + Permissions in this list are in the form of integers: like 0, 1, and 2. + 0, 1, and 2 correspond to "VIEW", "EDIT", and "DELETE" respectively. + """ + + id_fields = ("groupId","permissionIds") + + def __init__(self, groupId,permissionIds, **kwargs): + super(GroupPermission, self).__init__( permissionId = permissionIds, groupId=groupId,**kwargs) + + class Namespace(BaseEncodable): """ Represents a Namespace object in Argus. @@ -493,7 +512,7 @@ def __init__(self, *args, **kwargs): def from_json(self, jsonObj): if not jsonObj or not isinstance(jsonObj, dict): return jsonObj - for cls in (Metric, Dashboard, AddListResult, User, Namespace, Annotation, Alert, Trigger, Notification, Permission): + for cls in (Metric, Dashboard, AddListResult, User, Namespace, Annotation, Alert, Trigger, Notification, Permission, GroupPermission): obj = cls.from_dict(jsonObj) if obj: return obj diff --git a/tests/test_data.py b/tests/test_data.py index 5fa8763..4e35533 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -36,6 +36,7 @@ notificationName = "test.notification" groupPermissionIdentifier = "group" userPermissionIdentifier = "user" +groupID = "5eb1fc18-c985-47eb-94f9-aebce66e119a" permissionNames = ["VIEW", "EDIT", "DELETE"] permissionGroupId = '24231-52321-43523-64353-23111' username = "testuser" @@ -43,6 +44,18 @@ group_id = "c8be7819-bf5e-40aa-8535-88694d34280f" entity_id = 23590046 +username = "testuser" +permission_ids = [1,2,3] +user_type = "user" +group_type = "group" +group_id = "c8be7819-bf5e-40aa-8535-88694d34280f" +entity_id = 23590046 + +permissionGroup2ID= '24231-52321-43523-64353-23121' +permissionGroup3ID = '24231-52321-43523-64353-24121' +permissionGroupIdBad = '2423480-3843hlfw-jf' + + compAlertID = 6000 childAlertID_1 = 6003 childAlertID_2 = 6009 @@ -121,10 +134,29 @@ } groupPermission_D = { - "type": groupPermissionIdentifier, - "permissionNames": permissionNames, - "groupId": permissionGroupId + "type": "group", + "groupId": permissionGroupId, + "permissionIds": [0,1,2] } +groupPermission_E = { + "type": "group", + "groupId": permissionGroup2ID, + "permissionIds": [0,1] +} + +groupPermission_F = { + "type": "group", + "groupId": permissionGroup3ID, + "permissionIds": [0,1,2] +} + + +groupBadPermission_D = { + "groupId": groupID, + "permissionIds": [0,3] +} + + userPermission_D = { "type": userPermissionIdentifier, @@ -372,7 +404,7 @@ 'id': triggerID_1, 'threshold': 1.0, 'type': 'GREATER_THAN', - 'inertia': 0L, + 'inertia': 0, 'name': 'CompAlertTest/trigger1' } @@ -383,7 +415,7 @@ 'subscriptions': ['jdoe@example.com'], 'notifierName': 'com.salesforce.dva.argus.service.alert.notifier.EmailNotifier', 'metricsToAnnotate': [], - 'cooldownPeriod': 0L, + 'cooldownPeriod': 0, 'sractionable': False, 'customText': 'None' } \ No newline at end of file diff --git a/tests/test_group.py b/tests/test_group.py new file mode 100644 index 0000000..e26c09f --- /dev/null +++ b/tests/test_group.py @@ -0,0 +1,119 @@ +# +# Copyright (c) 2016, salesforce.com, inc. +# All rights reserved. +# Licensed under the BSD 3-Clause license. +# For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause +# +# Use the package in this repo (argusclient directory) + +from argusclient import * +from argusclient.model import Permission + +""" +LOGGING IN!~ +""" +username = "s.basu" +password = "" +argus = ArgusServiceClient(user="s.basu", + password=password, + endpoint="http://shared1-argusws1-1-prd.eng.sfdc.net:8080/argusws/") + # endpoint = "https://argus-ws.data.sfdc.net/argusws/") +print ('logging in...') +argus.login() +print ('logged in!') +""" +Set endpoint and params +""" +argus.grouppermissions = GroupPermissionsServiceClient(argus, get_all_req_opts= dict(groupID="234-567-891-667-001", type="group", + permissionsID=[0,1,2])) + +print(argus.grouppermissions) +print(type(argus.grouppermissions)) + +# argus.alerts = AlertsServiceClient(argus, get_all_req_opts={REQ_PARAMS: dict(shared=False, +# alertNameContains='TestAlert', +# limit=1), +# REQ_PATH: "allinfo"}) +# permission_group_D = { +# "id": 10, +# "createdById": 6906380, +# "createdDate": 1616098911000, +# "modifiedById": 6906380, +# "modifiedDate": 1616098911000, +# "type": "group", +# "groupId": "c8be7819-bf5e-40aa-8535-88694d34280f", +# "username": '', +# "permissionIds": [], +# "entityId": 23590046 +# } + +GroupPermission_D = { + "type": "group", + "groupId": "ebd7db70-290b-4d85-b366-b4be9d5967e4", + "permissionIds": [0,1,2], + "permissionNames": [] +} +GroupPermission_R ={ + "type": "group", + "groupId": "ebd7db70-290b-4d85-b366-b4be9d5967e4", + "permissionIds": [1], + "permissionNames": [] +} +groupID1 = "ebd7db70-290b-4d85-b366-b4be9d5967e4" +grouppermission = GroupPermission.from_dict(GroupPermission_D) +perm = Permission.from_dict(GroupPermission_R) +#groupPerm = argus.grouppermissions.get_permissions_for_group(groupID1) +#print("groupPerms are "+ str(groupPerm)) +#grouppermission = GroupPermission(GroupPermission_D.get("groupId"),[0,1,2]) +groupPerm1 = argus.grouppermissions.add_permissions_for_group(grouppermission) +print("groupPerms are "+ str(groupPerm1)) + +deletedPerm = argus.grouppermissions.delete_permissions_for_group(perm) #this is not working as adding group_permission returns a permission object instead of groupPermission object ? +print("removed groupPerms are "+ str(deletedPerm)) + +#argus.permissions = PermissionsServiceClient(argus) +#group_perm = Permission.from_dict(permission_group_D) +# delattr(group_perm, "id") +# deleted_perm = argus.permissions.delete(23590046, group_perm) +# +# print "updating perm" +# updated_perm = argus.permissions.add(23590046, group_perm) +# print "updated permission is "+ str(updated_perm) +#print ("making call to get perms for entities") +#all_perms = argus.permissions.get_permissions_for_entities([26947204]) +#print (all_perms) +#print (type(group_perm)) +#for id, val group_perm.items(): + #print (id) + # print (type(val)) + # for perm in val: + # perm_type = perm.type + # if perm_type == 'group': + ## print (perm.groupId) + # else: + # print (perm.username) +# argus.permissions = PermissionsServiceClient(argus, get_all_req_opts={REQ_PARAMS: dict(shared=False), +# # REQ_PATH: "entityIds", +# # REQ_METHOD: "post", +# # REQ_BODY: [14796957, 14796958]}) +# argus.dashboards = DashboardsServiceClient(argus, get_all_req_opts=dict(REQ_PARAMS=dict(username="j.ma", shared=False, limit=3))) # note - limit does not work +""" +Making the call +""" +if __name__ == '__main__': + + # print 'calling items()' + # res = argus.alerts.items() + # res = argus.permissions.items() + # res = argus.dashboards.items() + print ("calling groupPerms") +# res1 = groupPerm1 + + #print ('size of result: ', len()) + #res = argus.permissions.get(16348603) + # Get notif + # alert = res[0][1] + # print 'notifs:', alert.notifications.items() + # notifs = alert.notifications.items() + # notif = notifs[0][1] + # print '\nresult: ', res diff --git a/tests/test_modelobjs.py b/tests/test_modelobjs.py index a872376..76140d7 100644 --- a/tests/test_modelobjs.py +++ b/tests/test_modelobjs.py @@ -212,7 +212,7 @@ def testEncUserPermission(self): self._testFor(userPermission_D, Permission) def testEncGroupPermission(self): - self._testFor(groupPermission_D, Permission) + self._testFor(groupPermission_D, GroupPermission) def testEncNamespace(self): self._testFor(namespace_D, Namespace) diff --git a/tests/test_service.py b/tests/test_service.py index fd6c0da..74849b8 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -9,10 +9,9 @@ import unittest from argusclient import * -from argusclient.client import JsonEncoder, JsonDecoder, check_success, AlertsServiceClient, PermissionsServiceClient, \ +from argusclient.client import JsonDecoder, check_success, AlertsServiceClient, PermissionsServiceClient, \ DashboardsServiceClient, REQ_PATH, REQ_PARAMS, REQ_METHOD, REQ_BODY from argusclient.model import Permission - from test_data import * try: @@ -198,6 +197,9 @@ def testInvalidRefreshTokenWithDirectAccessToken(self): self.assertEquals((os.path.join(endpoint, "namespace"), os.path.join(endpoint, "namespace"), os.path.join(endpoint, "namespace"),), called_endpoints(mockConn.get)) self.assertEquals(3, mockConn.get.call_count) + + + def testInvalidPasswordWithDirectRefreshToken(self): """Test inability to refresh refresh token as there is no password""" self.argus.refreshToken = "refresh" @@ -390,6 +392,29 @@ def testGetItems(self, mockGet): self.assertIn((os.path.join(endpoint, "dashboards"),), tuple(mockGet.call_args)) self.assertEquals(len(mockGet.call_args_list), 1) +class TestGroupPermissions(TestServiceBase): + @mock.patch('requests.Session.get', return_value=MockResponse(json.dumps(groupPermission_D), 200)) + def testGroupPermissionsID(self, mockGet): + res = self.argus.grouppermissions.get_permissions_for_group(permissionGroupId) + self.assertEquals(res.get("permissionIds"), [0, 1, 2]) + self.assertIn((os.path.join(endpoint, "grouppermission"),), tuple(mockGet.call_args)) + + @mock.patch('requests.Session.post', return_value=MockResponse(json.dumps(groupPermission_E), 200)) + def testGroupPermissionsIDAdd(self, mockPost): + ggroupId = permissionGroup2ID + gperms = GroupPermission(ggroupId, [1]) + res = self.argus.grouppermissions.add_permissions_for_group(gperms) + self.assertEquals(res.permissionIds, [0, 1]) + self.assertIn((os.path.join(endpoint, "grouppermission"),), tuple(mockPost.call_args)) + + + @mock.patch('requests.Session.delete', return_value=MockResponse(json.dumps(groupPermission_F), 200)) + def testDeletePermission(self, mockDelete): + gpermission = Permission.from_dict(groupPermission_F) # group with new permissions + res = self.argus.grouppermissions.delete_permissions_for_group(gpermission) + self.assertEquals(res, False) #self._colls is empty + self.assertIn((os.path.join(endpoint, "grouppermission"),), tuple(mockDelete.call_args)) + class TestPermission(TestServiceBase): @mock.patch('requests.Session.post', return_value=MockResponse({}, 200)) @@ -402,6 +427,7 @@ def testGetPermissionsBadId(self, mockPost): testId2: [userPermission_D], testId3: []}), 200)) def testGetItems(self, mockPost): + # Check self.assertEquals(len(mockPost.call_args_list), 0) @@ -440,7 +466,7 @@ def testGetItems(self, mockPost): @mock.patch('requests.Session.post', return_value=MockResponse(json.dumps({testId: [groupPermission_D, groupPermission_D], testId2: [userPermission_D], testId3: []}), 200)) - def testGetPermissions(self, mockPost): + def testGetPermissions(self, mockPost): #test is broken in master as well resp = self.argus.permissions.get_permissions_for_entities([testId, testId2, testId3]) for id, perms in resp.items(): for p in perms: