'''Python module to work with the Zenoss JSON API ''' import ast import re import json import logging import requests log = logging.getLogger(__name__) # pylint: disable=C0103 requests.packages.urllib3.disable_warnings() ROUTERS = {'MessagingRouter': 'messaging', 'EventsRouter': 'evconsole', 'EventClassesRouter': 'Events/evclasses', 'ProcessRouter': 'process', 'ServiceRouter': 'service', 'DeviceRouter': 'device', 'ManufacturersRouter': 'manufacturers', 'NetworkRouter': 'network', 'PropertiesRouter': 'properties', 'TemplateRouter': 'template', 'DetailNavRouter': 'detailnav', 'ReportRouter': 'report', 'MibRouter': 'mib', 'TriggersRouter': 'triggers', 'ZenPackRouter': 'zenpack'} class ZenossException(Exception): '''Custom exception for Zenoss ''' pass class Zenoss(object): '''A class that represents a connection to a Zenoss server ''' def __init__(self, host, username, password, ssl_verify=True): self.__host = host self.__session = requests.Session() self.__session.auth = (username, password) self.__session.verify = ssl_verify self.__req_count = 0 def __router_request(self, router, method, data=None, uri=None): '''Internal method to make calls to the Zenoss request router ''' if router not in ROUTERS: raise ZenossException('Router "' + router + '" not available.') req_data = json.dumps([dict( action=router, method=method, data=data, type='rpc', tid=self.__req_count)]) log.debug('Making request to router %s with method %s', router, method) if not uri: uri = '%s/zport/dmd/%s_router' % (self.__host, ROUTERS[router]) headers = {'Content-type': 'application/json; charset=utf-8'} response = self.__session.post(uri, data=req_data, headers=headers) self.__req_count += 1 # The API returns a 200 response code even whe auth is bad. # With bad auth, the login page is displayed. Here I search for # an element on the login form to determine if auth failed. if re.search('name="__ac_name"', response.content.decode("utf-8")): log.error('Request failed. Bad username/password.') raise ZenossException('Request failed. Bad username/password.') if response.status_code == 200: return json.loads(response.content.decode("utf-8"))['result'] else: raise ZenossException("Unable to complete request:\n%s\nHTTP Status: %s" % ( req_data, response.status_code, )) def get_rrd_values(self, device, dsnames, start=None, end=None, function='LAST'): # pylint: disable=R0913 '''Method to abstract the details of making a request to the getRRDValue method for a device ''' if function not in ['MINIMUM', 'AVERAGE', 'MAXIMUM', 'LAST']: raise ZenossException('Invalid RRD function {0} given.'.format(function)) if len(dsnames) == 1: # Appending a junk value to dsnames because if only one value is provided Zenoss fails to return a value. dsnames.append('junk') url = '{0}/{1}/getRRDValues'.format(self.__host, self.device_uid(device)) params = {'dsnames': dsnames, 'start': start, 'end': end, 'function': function} return ast.literal_eval(self.__session.get(url, params=params).content) def get_devices(self, device_class='/zport/dmd/Devices', limit=None): '''Get a list of all devices. ''' log.info('Getting all devices') return self.__router_request('DeviceRouter', 'getDevices', data=[{'uid': device_class, 'params': {}, 'limit': limit}]) def get_components(self, device_name, **kwargs): '''Get components for a device given the name ''' uid = self.device_uid(device_name) return self.get_components_by_uid(uid=uid, **kwargs) def get_components_by_uid(self, uid=None, meta_type=None, keys=None, start=0, limit=50, page=0, sort='name', dir='ASC', name=None): '''Get components for a device given the uid ''' data = dict(uid=uid, meta_type=meta_type, keys=keys, start=start, limit=limit, page=page, sort=sort, dir=dir, name=name) return self.__router_request('DeviceRouter', 'getComponents', [data]) def find_device(self, device_name): '''Find a device by name. ''' log.info('Finding device %s', device_name) all_devices = self.get_devices() try: device = [d for d in all_devices['devices'] if d['name'] == device_name][0] # We need to save the has for later operations device['hash'] = all_devices['hash'] log.info('%s found', device_name) return device except IndexError: log.error('Cannot locate device %s', device_name) raise Exception('Cannot locate device %s' % device_name) def device_uid(self, device): '''Helper method to retrieve the device UID for a given device name ''' return self.find_device(device)['uid'] def add_device(self, device_name, device_class, collector='localhost'): '''Add a device. ''' log.info('Adding %s', device_name) data = dict(deviceName=device_name, deviceClass=device_class, model=True, collector=collector) return self.__router_request('DeviceRouter', 'addDevice', [data]) def remove_device(self, device_name): '''Remove a device. ''' log.info('Removing %s', device_name) device = self.find_device(device_name) data = dict(uids=[device['uid']], hashcheck=device['hash'], action='delete') return self.__router_request('DeviceRouter', 'removeDevices', [data]) def move_device(self, device_name, organizer): '''Move the device the organizer specified. ''' log.info('Moving %s to %s', device_name, organizer) device = self.find_device(device_name) data = dict(uids=[device['uid']], hashcheck=device['hash'], target=organizer) return self.__router_request('DeviceRouter', 'moveDevices', [data]) def set_prod_state(self, device_name, prod_state): '''Set the production state of a device. ''' log.info('Setting prodState on %s to %s', device_name, prod_state) device = self.find_device(device_name) data = dict(uids=[device['uid']], prodState=prod_state, hashcheck=device['hash']) return self.__router_request('DeviceRouter', 'setProductionState', [data]) def set_maintenance(self, device_name): '''Helper method to set prodState for device so that it does not alert. ''' return self.set_prod_state(device_name, 300) def set_production(self, device_name): '''Helper method to set prodState for device so that it is back in production and alerting. ''' return self.set_prod_state(device_name, 1000) def set_product_info(self, device_name, hw_manufacturer, hw_product_name, os_manufacturer, os_product_name): # pylint: disable=R0913 '''Set ProductInfo on a device. ''' log.info('Setting ProductInfo on %s', device_name) device = self.find_device(device_name) data = dict(uid=device['uid'], hwManufacturer=hw_manufacturer, hwProductName=hw_product_name, osManufacturer=os_manufacturer, osProductName=os_product_name) return self.__router_request('DeviceRouter', 'setProductInfo', [data]) def set_rhel_release(self, device_name, release): '''Sets the proper release of RedHat Enterprise Linux.''' if type(release) is not float: log.error("RHEL release must be a float") return {u'success': False} log.info('Setting RHEL release on %s to %s', device_name, release) device = self.find_device(device_name) return self.set_product_info(device_name, device['hwManufacturer']['name'], device['hwModel']['name'], 'RedHat', 'RHEL {}'.format(release)) def set_device_info(self, device_name, data): '''Set attributes on a device or device organizer. This method accepts any keyword argument for the property that you wish to set. ''' data['uid'] = self.find_device(device_name)['uid'] return self.__router_request('DeviceRouter', 'setInfo', [data]) def remodel_device(self, device_name): '''Submit a job to have a device remodeled. ''' return self.__router_request('DeviceRouter', 'remodel', [dict(uid=self.find_device(device_name)['uid'])]) def set_collector(self, device_name, collector): '''Set collector for device. ''' device = self.find_device(device_name) data = dict(uids=[device['uid']], hashcheck=device['hash'], collector=collector) return self.__router_request('DeviceRouter', 'setCollector', [data]) def rename_device(self, device_name, new_name): '''Rename a device. ''' data = dict(uid=self.find_device(device_name)['uid'], newId=new_name) return self.__router_request('DeviceRouter', 'renameDevice', [data]) def reset_ip(self, device_name, ip_address=''): '''Reset IP address(es) of device to the results of a DNS lookup or a manually set address. ''' device = self.find_device(device_name) data = dict(uids=[device['uid']], hashcheck=device['hash'], ip=ip_address) return self.__router_request('DeviceRouter', 'resetIp', [data]) def get_events(self, device=None, limit=100, component=None, severity=None, event_class=None, start=0, event_state=None, sort='severity', direction='DESC'): '''Find current events. Returns a list of dicts containing event details. By default they are sorted in descending order of severity. By default, severity {5, 4, 3, 2} and state {0, 1} are the only events that will appear. ''' if severity is None: severity = [5, 4, 3, 2] if event_state is None: event_state = [0, 1] data = dict(start=start, limit=limit, dir=direction, sort=sort) data['params'] = dict(severity=severity, eventState=event_state) if device is not None: data['params']['device'] = device if component is not None: data['params']['component'] = component if event_class is not None: data['params']['eventClass'] = event_class log.info('Getting events for %s', data) return self.__router_request( 'EventsRouter', 'query', [data])['events'] def get_event_detail(self, event_id): '''Find specific event details ''' data = dict(evid=event_id) return self.__router_request('EventsRouter', 'detail', [data]) def write_log(self, event_id, message): '''Write a message to the event's log ''' data = dict(evid=event_id, message=message) return self.__router_request('EventsRouter', 'write_log', [data]) def change_event_state(self, event_id, state): '''Change the state of an event. ''' log.info('Changing eventState on %s to %s', event_id, state) return self.__router_request('EventsRouter', state, [{'evids': [event_id]}]) def ack_event(self, event_id): '''Helper method to set the event state to acknowledged. ''' return self.change_event_state(event_id, 'acknowledge') def close_event(self, event_id): '''Helper method to set the event state to closed. ''' return self.change_event_state(event_id, 'close') def create_event_on_device(self, device_name, severity, summary, component='', evclasskey='', evclass=''): '''Manually create a new event for the device specified. ''' log.info('Creating new event for %s with severity %s', device_name, severity) if severity not in ('Critical', 'Error', 'Warning', 'Info', 'Debug', 'Clear'): raise Exception('Severity %s is not valid.' % severity) data = dict(device=device_name, summary=summary, severity=severity, component=component, evclasskey=evclasskey, evclass=evclass) return self.__router_request('EventsRouter', 'add_event', [data]) def get_load_average(self, device): '''Returns the current 1, 5 and 15 minute load averages for a device. ''' dsnames = ('laLoadInt1_laLoadInt1', 'laLoadInt5_laLoadInt5', 'laLoadInt15_laLoadInt15') result = self.get_rrd_values(device=device, dsnames=dsnames) def normalize_load(load): '''Convert raw RRD load average to something reasonable so that it matches output from /proc/loadavg''' return round(float(load) / 100.0, 2) return [normalize_load(l) for l in result.values()] def add_device_class(self, name, description="", path=""): ''' create a new device class in zenoss zen.add_device_class("Arista", path="/Network") :param name: name of new device class :type name: string :param description: description of new device class :type description: string :return: dict showing the status of the command :rtype: dict usage:: >>> zen.add_device_class("Testing", path="/HTTP") {u'msg': u'Device Class Added', u'nodeConfig': { u'children': [], u'hasNoGlobalRoles': False, u'hidden': False, u'iconCls': u'tree-severity-icon-small-clear', u'id': u'.zport.dmd.Devices.HTTP.Testing', u'leaf': False, u'path': u'Devices/HTTP/Testing', u'text': {u'count': 0, u'description': u'devices', u'text': u'Testing'}, u'uid': u'/zport/dmd/Devices/HTTP/Testing', u'uuid': u'...', u'zPythonClass': u''}, u'success': True} ''' base_org = "/zport/dmd/Devices%s" % path data = dict(contextUid=base_org, id=name, description=description, type="organizer") return self.__router_request('DeviceRouter', 'addDeviceClassNode', [data]) def add_event_class(self, name, description="", path=""): ''' create a new event class :param name: the endpoint name of the event class :type name: string :param description: description the new event class :type description: string :param path: path to where to put new event class :type path: string :return: zenoss success dict, with nodeConfig key showing the new event class details :rtype: dict usage:: >>> zen.add_event_class("Test", path="/Net", description="Testing") {u'nodeConfig': {u'children': [], u'count': 0, u'hidden': False, u'iconCls': u'tree-severity-icon-small-clear', u'id': u'.zport.dmd.Events.Net.Testing', u'leaf': True, u'path': u'Events/Net/Test', u'text': {u'count': 0, u'description': u'Testing', u'hasTransform': False, u'text': u'Testing'}, u'uid': u'/zport/dmd/Events/Net/Testing', u'uuid': u'...'}, u'success': True} ''' base_org = "/zport/dmd/Events%s" % path data = dict(contextUid=base_org, id=name, description=description, type="organizer") return self.__router_request('EventClassesRouter', 'addNode', [data]) def add_group(self, group, description="", path=""): ''' add group :param group: name of group to be added :type group: string :param description: description for the group :type description: string :param path: path to the group, if group is to be placed in suborganizers :type path: string :return: zenoss success dict :rtype: dict usage:: >>> zen.add_group("MyGroup") {u'nodeConfig': {u'children': [], u'hasNoGlobalRoles': False, u'hidden': False, u'iconCls': u'tree-severity-icon-small-clear', u'id': u'.zport.dmd.Groups.MyGroup', u'leaf': False, u'path': u'Groups/MyGroup', u'text': {u'count': 0, u'description': u'devices', u'text': u'MyGroup'}, u'uid': u'/zport/dmd/Groups/MyGroup', u'uuid': u'...', u'zPythonClass': None}, u'success': True ''' log.info('Adding Group %s', group) base_org = "/zport/dmd/Groups/%s" % path data = dict(type='organizer', contextUid=base_org, id=group, description=description) return self.__router_request('DeviceRouter', 'addNode', [data]) def add_hardware_product(self, product_name, manufacturer, product_type, part_number="", product_keys="", description=""): ''' Add Hardware ''' log.info('Adding Hardware Product %s', product_name) tmp = dict(prodname=product_name, uid="/zport/dmd/Manufacturers/%s" % manufacturer, type=product_type, description=description, partno=part_number, prodkeys=product_keys) data = dict(params=tmp) return self.__router_request('ManufacturersRouter', 'addNewProduct', [data]) def add_location(self, location_name, path="", description="", address=""): ''' Add Location path key word denotes the path under /Locations that should be added and should be formatted like this sub/sub1 :param location_name: name of location :type location_name: string :param path: path to location organizer :type path: string :param description: description of location :type description: string :param address: address of location :type address: string :return: zenoss success dict :rtype: dict usage:: >>> zen.add_location("Springfield", address="742 evergreen terrace") {u'msg': u'Location added', u'nodeConfig': {u'children': [], u'hasNoGlobalRoles': False, u'hidden': False, u'iconCls': u'tree-severity-icon-small-clear', u'id': u'.zport.dmd.Locations.Springfield', u'leaf': False, u'path': u'Locations/Springfield', u'text': {u'count': 0, u'description': u'devices', u'text': u'Springfield'}, u'uid': u'/zport/dmd/Locations/Springfield', u'uuid': u'...', u'zPythonClass': None}, u'success': True} ''' log.info('Adding Location %s', location_name) base_org = "/zport/dmd/Locations%s" % path data = dict(type='organizer', contextUid=base_org, id=location_name, description=description, address=address) return self.__router_request('DeviceRouter', 'addLocationNode', [data]) def add_notification(self, name, action): ''' add a new notification :param name: name of the notification :type name: string :param action: the notifications action :type action: string :return: zenoss success dict where the data key holds the whole notifications config details :rtype: dict usage:: >>> zen.add_notification("Testing", "email") {u'data': {u'action': u'email', u'content': {...}, ... }, u'success': True} ''' data = dict(newId=name, action=action) return self.__router_request('TriggersRouter', 'addNotification', [data]) def add_trigger(self, name, rules=None, users=None, enabled=True, global_manage=False, global_read=False, global_write=False): ''' add a new trigger :param name: name of new trigger :type name: string :param rule: event rule string :type rule: string :param users: list of dicts for user setting definitions :type rule: list :param enabled: is the trigger enabled :type enabled: boolean :param global_manage: is the trigger manageable by all, can it be deleted :type global_manage: boolean :param global_read: is the trigger readable by all, can it be seen :type gloabl_read: boolean :param global_write: is the trigger writable by all, can it be updated :type global_write: boolean :return: zenoss success dict :rtype: dict usage:: >>> zen.add_trigger('TEST') {u'data': u'b0be2cf8-6182-4cc5-8b5c-545765869612', u'success': True} ''' result = self.__router_request('TriggersRouter', 'addTrigger', [dict(newId=name)]) if not result['success']: raise ZenossException("Unable to add trigger %s Reason: %s" % (name, result['msg'])) if rules: update_result = self.update_trigger_rules(name, rules, users=users, enabled=enabled, global_manage=global_manage, global_read=global_read, global_write=global_write) if not update_result['success']: raise ZenossException("Unable to update rules for trigger %s" % name) return result def get_locations(self, location='/zport/dmd/Locations', limit=None): ''' given a location endpoint return the details of the location object :return: dict of dict, with locations key holding a list of dicts :rtype: dict :: >> zen.get_locations() { u'locations': [ {u'name': u'/DataCenter1'}, ], u'success': True, u'totalCount': 1 } ''' return self.__router_request('DeviceRouter', 'getLocations', data=[{'uid': location, 'params': {}, 'limit': limit}]) def get_groups(self, groups='/zport/dmd/Groups', limit=None): ''' get details of infrastructure group ''' return self.__router_request('DeviceRouter', 'getGroups', data=[{'uid': groups, 'params': {}, 'limit': limit}]) def get_device_classes(self, path): ''' given a device class path return all the sub classes :param path: path to device classes :type path: string :return: list of dicts where each dict describes the sub device class :rtype: list uasge:: >>> zen.get_device_classes("/Network") [{ u'hidden': False, u'iconCls': u'tree-severity-icon-small-clear', u'id': u'.zport.dmd.Devices.Network.Router', u'leaf': False, u'path': u'Devices/Network/Router', u'text': {u'count': 0, u'description': u'devices', u'text': u'Router'}, u'uid': u'/zport/dmd/Devices/Network/Router' }] ''' base_org = "/zport/dmd/Devices%s" % path return self.__router_request('DeviceRouter', 'asyncGetTree', [base_org]) def get_device_class_template(self, path): ''' gather the templates for a device class :param path: Path to the device class, the root is /Devices :type path: string :return: list of device class templates :rtype: list usage:: >>> zen.get_device_class_template("/Network") [{u'id': u'/zport/dmd/Devices/rrdTemplates/Device', u'leaf': True, u'path': u'/', u'text': u'Device (/)', u'uid': u'/zport/dmd/Devices/rrdTemplates/Device'}] ''' base_org = "/zport/dmd/Devices%s" % path return self.__router_request('DeviceRouter', 'getTemplates', [base_org]) def get_ec_instance_details(self, name, path="", is_uid=False): ''' get the details of an event class :param name: instance name :type name: string :param path: path to event class transform :type path: string :param is_uid: flag to check if name is uid :type is_uid: boolean :return: zenoss success dict, with data key holding all the instance details :rtype: dict usage:: >>> zen.get_ec_instance_details("bgpBackwardTransNotification", path="/Net/BGP") {u'data': [{u'evaluation': u'', u'eventClass': u'BGP', u'eventClassKey': u'bgpNotification.2', u'example': u'snmp trap bgpNotification.2', u'id': u'bgpBackwardTransNotification', u'regex': u'', u'resolution': u'', u'rule': u'', u'sequence': 8, u'transform': u'\'\'\'\nevent transform for bgpBackwardTransition\n\'\'\'\n u'uid': u'/zport/dmd/Events/Net/BGP/instances/bgpBackwardTransNotification'}], u'success': True} ''' if is_uid: data = dict(uid=name) else: data = dict(uid="/zport/dmd/Events%s/instances/%s" % (path, name)) return self.__router_request('EventClassesRouter', 'getInstanceData', [data]) def get_event_classes_instances(self, path=""): ''' get all the event class instances :params path: limit the instances to event classes in this path :type path: string :return: zenoss success dict, with data key holding all the event classes :rtype: dict usage:: >>> zen.get_event_classes(path="/Net/Time") {u'data': [{ u'eval': u'The time provider NtpServer...', u'eventClassKey': u'W32Time_22', u'hasTransform': False, u'id': u'W32Time_22', u'uid': u'/zport/dmd/Events/Net/Time/instances/W32Time_22'}], u'success': True} ''' base_org = "/zport/dmd/Events%s" % path data = dict(params={}, uid=base_org) return self.__router_request('EventClassesRouter', 'getInstances', [data]) def get_ec_instance_transform(self, name, path="", is_uid=False): ''' get the event transform off an event class instance :param name: instance name :type name: string :param path: path to event class transform :type path: string :param is_uid: flag to check if name is uid :type is_uid: boolean :return: zenoss success dict :rtype: dict usage:: >>> zen.get_ec_instance_transform("bgpBackwardTransNotif", path="/Net/BGP") { u'data': u'\'\'\'\nevent transform for bgpBackwardTransNotif\n\'\'\'\n...', u'success': True } ''' if is_uid: data = dict(uid=name) else: base_org = "/zport/dmd/Events%s" % path data = dict(uid="%s/instances/%s" % (base_org, name)) return self.__router_request('EventClassesRouter', 'getTransform', [data]) def get_location_details(self, name, path=""): ''' given a location return all the info about said location :param name: location name :type name: string :param path: path to location :return: dict of dict where data key has all the location details :rtype: dict :: >>> zen.get_location_details("DataCenter1") {u'data': {u'address': u'742 Evergreen Terrace', u'description': u'', u'events': {u'clear': {u'acknowledged_count': 0, u'count': 0}, u'critical': {u'acknowledged_count': 0, u'count': 1}, u'debug': {u'acknowledged_count': 0, u'count': 0}, u'error': {u'acknowledged_count': 1, u'count': 7}, u'info': {u'acknowledged_count': 0, u'count': 82}, u'warning': {u'acknowledged_count': 0, u'count': 8}}, u'id': u'Europe', u'inspector_type': u'Location', u'meta_type': u'Location', u'name': u'/DataCenter1', u'severity': u'critical', u'uid': u'/zport/dmd/Locations/DataCenter1', u'uuid': u'...'}, u'disabled': False, u'success': True} ''' uid = "/zport/dmd/Locations%s/%s" % (path, name) return self.__router_request('DeviceRouter', 'getInfo', data=[dict(uid=uid)]) def get_notifications(self): ''' return all the notifications :return: dict :rtype: dict usage:: >>> zen.get_device_classes("/Network") { 'success': True, 'data': [{ u'action': u'email', u'content': {...}, ... }] } ''' return self.__router_request('TriggersRouter', 'getNotifications', [{}]) def get_triggers(self): ''' gather all the triggers :return: zenoss success dict, where all the triggers are under the data key :rtype: dict usage:: >>> zen.get_triggers() {u'data': [{ u'enabled': True, u'globalManage': True, u'globalRead': True, u'globalWrite': True, u'name': u'RuleName', u'rule': { u'api_version': 1, u'source': u'(dev.production_state == 1000) and (evt.severity >= 4)', u'type': 1}, u'subscriptions': [ { u'delay_seconds': 0, u'repeat_seconds': 0, u'send_initial_occurrence': True, u'subscriber_uuid': u'...', u'trigger_uuid': u'...', u'uuid': u'...'}, { u'delay_seconds': 1, u'repeat_seconds': 60, u'send_initial_occurrence': True, u'subscriber_uuid': u'...', u'trigger_uuid': u'...', u'uuid': u'...'} ], u'userManage': True, u'userRead': True, u'userWrite': True, u'users': [], u'uuid': u'...'}], u'success': True} ''' return self.__router_request('TriggersRouter', 'getTriggers', [{}]) def get_zproperties(self, uid): ''' take any uid to a zenoss object and return the zproperties for the object :param uid: Specify the zenoss uid for object to inspect :type uid: string :return: zenoss response dict where data key holds all the properties :rtype: dict usage:: >>> zen.get_zproperties("/zport/dmd/Devices/Network") {u'data': [ { u'category': u'Modeler Controls', u'description': u'Allows you to set the timeout time of the collector client in seconds', u'id': u'zCollectorClientTimeout', u'islocal': 0, u'label': u'Collector Client Timeout (seconds)', u'options': [], u'path': u'/', u'type': u'int', u'value': 180, u'valueAsString': 180}, ... ] u'success': True, u'totalCount': 81 } ''' return self.__router_request('PropertiesRouter', 'getZenProperties', uri="%s%s/properties_router" % (self.__host, uid), data=[dict(uid=uid)]) def remove_device_class(self, name, path=""): ''' remove a given device class from zenoss :param name: name of device class to be removed :type name: string :param path: path to device class endpoint :type path: string :return: dict showing the status of the command :rtype: dict usage:: >>> zen.remove_device_class("Switch", path="/Network") {u'msg': u"Deleted node '/zport/dmd/Devices/HTTP/Test'", u'success': True} ''' base_org = "/zport/dmd/Devices%s" % path data = dict(uid="%s/%s" % (base_org, name)) return self.__router_request('DeviceRouter', 'deleteNode', [data]) def remove_event_class(self, name, path=""): ''' remove an event class :param name: the endpoint name of the event class to be removed :type name: string :param path: path to where the event class is located :type path: string :return: zenoss success dict :rtype: dict usage:: >>> zen.remove_event_class("Testing", path="/Net") {u'success': True} ''' base_org = "/zport/dmd/Events%s" % path data = dict(uid="%s/%s" % (base_org, name)) return self.__router_request('EventClassesRouter', 'deleteEventClass', [data]) def remove_group(self, group, path=""): ''' Deletes a Group organizer :param group: name of group to be deleted :type group: string :param path: path to organizer holding group :type path: string :return: zenoss success dict :rtype: dict usage:: >>> zen.remove_group("MyGroup") {u'msg': u"Deleted node '/zport/dmd/Groups/MyGroup'", u'success': True} ''' base_org = "/zport/dmd/Groups%s" % path log.info('Removing Group %s', group) data = dict(uid="%s/%s" % (base_org, group)) return self.__router_request('DeviceRouter', 'deleteNode', [data]) def remove_locations(self, location, path=""): ''' Deletes a Location organizer :param location: name of the location to be remove :type location: string :param path: path to the location organizer :type path: string :return: zenoss success dict :rtype: dict usage:: >>> zen.remove_locations("Springfield") {u'msg': u"Deleted node '/zport/dmd/Locations/Springfield'", u'success': True} ''' base_org = "/zport/dmd/Locations%s" % path log.info('Removing Location %s', location) data = dict(uid="%s/%s" % (base_org, location)) return self.__router_request('DeviceRouter', 'deleteNode', [data]) def remove_trigger(self, name): ''' delete a trigger :param name: name of trigger to be removed :type name: string usage:: >>> zen.remove_trigger('TEST') {u'data': None, u'msg': u'Trigger removed successfully. 0 notifications were updated.', u'success': True} ''' all_triggers = dict() for _ in self.get_triggers()['data']: all_triggers[_['name']] = _ if name not in all_triggers: raise ZenossException("Unable to find trigger %s" % (name)) uuid = all_triggers[name]['uuid'] return self.__router_request('TriggersRouter', 'removeTrigger', [dict(uuid=uuid)]) def set_ec_instance_details(self, name, transform, path="", is_uid=False): ''' modify an event class details :param name: name of the event class :type name: string :param transform: transform code :type transform: string :param path: path to even class :type path: string :param is_uid: is the name provided a uid, saves on look ups :type is_uid: boolean :return: zenoss success dict :rtype: dict usage:: ''' if is_uid: data = dict(uid=name, transform=transform) else: base_org = "/zport/dmd/Events%s" % path data = dict(uid="%s/instances/%s" % (base_org, name)) return self.__router_request('EventClassesRouter', 'setTransform', [data]) def update_notifiication_sub(self, name, subscriptions, by_name=False): ''' update the notification subscription :param name: name of the notification :type name: string :param subscription: list of uids for this notification to subscribe to :type subscription: list :param by_name: flag to send a list of trigger names, not uuids of triggers :type by_name: boolean usage:: >>> zen.update_notification_sub('Test', ['f1f9eb4b-090b-4021-8e26-e535b29077c5']) {u'data': None, u'msg': u'Notification updated successfully.', u'success': True} ''' all_notifications = dict() for _ in self.get_notifications()['data']: all_notifications[_['name']] = _ if name not in all_notifications: raise ZenossException("Unable to find notification %s" % name) if by_name: all_triggers = dict() for _ in self.get_triggers()['data']: all_triggers[_['name']] = _ tmp = list() for _ in subscriptions: if _ in all_triggers: tmp.append(all_triggers[_]['uuid']) else: raise ZenossException("Unable to map trigger %s to notification %s" % ( _, name )) subscriptions = tmp else: diff = set(subscriptions).difference( set([_['uuid'] for _ in self.get_triggers()['data']])) if diff: raise ZenossException("Passed trigger subscription uuid that doesn't exist %s" % diff) data = all_notifications[name] data['subscriptions'] = subscriptions return self.__router_request('TriggersRouter', 'updateNotification', [data]) def update_trigger_rules(self, name, rule=None, users=None, enabled=True, global_manage=False, global_read=False, global_write=False): ''' modify an existing trigger NOTE: is the request isn't properly formatted zenoss might just accept it, and return success. :param name: name of the trigger :type name: string :param rule: event rule string :type rule: string :param users: list of dicts for user setting definitions :type rule: list :param enabled: is the trigger enabled :type enabled: boolean :param global_manage: is the trigger manageable by all, can it be deleted :type global_manage: boolean :param global_read: is the trigger readable by all, can it be seen :type gloabl_read: boolean :param global_write: is the trigger writable by all, can it be updated :type global_write: boolean :return: zenoss success dict :rtype: dict usage:: >>> zen.update_trigger_rules("dc1_bgp", enabled=False) {u'data': u'', u'msg': u'Trigger updated successfully.', u'success': True} ''' all_triggers = dict() for _ in self.get_triggers()['data']: all_triggers[_['name']] = _ if name not in all_triggers: raise ZenossException("Unable to find trigger %s" % (name)) if not rule: rule = all_triggers[name]['rule']['source'] uuid = all_triggers[name]['uuid'] data = dict( enabled=enabled, globalManage=global_manage, globalRead=global_read, globalWrite=global_write, name=name, uuid=uuid, rule=dict(source=rule) ) if users: data['users'] = users return self.__router_request('TriggersRouter', 'updateTrigger', [data])