Package ZenPacks :: Package zenoss :: Package Impact :: Module routers
[frames] | no frames]

Source Code for Module ZenPacks.zenoss.Impact.routers

  1  ###################################################################### 
  2  # 
  3  # Copyright 2010 Zenoss, Inc.  All Rights Reserved. 
  4  # 
  5  ###################################################################### 
  6  """ 
  7  Operations for Impact and Dynamic Services. 
  8   
  9  Available at:  /zport/dmd/enterpriseservices_router 
 10  """ 
 11   
 12  import logging 
 13  import json 
 14  import time 
 15  import itertools 
 16   
 17  from zope.component import getUtility, subscribers 
 18  from Products import Zuul 
 19  from itertools import islice 
 20  from Products.Zuul.routers import TreeRouter 
 21  from Products.Zuul.interfaces import IInfo 
 22  from Products.Zuul.decorators import require 
 23  from Products.ZenUtils.Ext import DirectResponse 
 24  from Products.Zuul.form.interfaces import IFormBuilder 
 25  from Products.Zuul.decorators import contextRequire, decorator 
 26  from Products.Zuul.facades.zepfacade import InvalidQueryParameterException 
 27  from Products.Zuul.routers.zep import EventsRouter 
 28  from Products.Zuul import getFacade 
 29  from zenoss.protocols.services.zep import ZepConnectionError 
 30  from ZenPacks.zenoss.Impact.DynamicService import DynamicService 
 31  from ZenPacks.zenoss.Impact.DynamicServiceOrganizer import DynamicServiceOrganizer 
 32  from Products.ZenModel.ZenossSecurity import ZEN_DELETE, ZEN_ADD, ZEN_MANAGE_DMD 
 33  from ZenPacks.zenoss.Impact.impactd import objectBelongsInImpactGraph 
 34  from Products.ZCatalog.CatalogBrains import AbstractCatalogBrain 
 35  from Products.Zuul.interfaces.tree import ICatalogTool 
 36  from Products.ZenMessaging.audit import audit 
 37  from Products.ZenUtils.Utils import getDisplayType 
 38  from zenoss.protocols.protobufs.zep_pb2 import STATUS_NEW, STATUS_ACKNOWLEDGED 
 39  from .exceptions import IMPACT_NEEDS_RESET 
 40  from .exceptions import ImpactServerConnectionError, ImpactServerException 
 41  from .interfaces import IRootCauseScoreAdjustment 
 42   
 43  log = logging.getLogger("zen.ImpactRelatedEvents") 
44 45 @decorator 46 -def impactServerConnectionError(func, *args, **kwargs):
47 """ 48 Decorator that catches exceptions from interactions with zenimpactserver and 49 returns a clean response. 50 51 @rtype: DirectResponse 52 @return: B{Type}: exception 53 """ 54 try: 55 return func(*args, **kwargs) 56 except ImpactServerConnectionError, e: 57 msg = 'Connection refused. Check zenimpactserver status on <a href="/zport/About/zenossInfo">Daemons</a>' 58 return DirectResponse.exception(e, msg, sticky=True)
59
60 61 -class RelatedEventsRouter(EventsRouter):
62 """ 63 Queries for events related to a service event. 64 """ 65
66 - def related_services(self, event_id, archive=False):
67 """ 68 Find services that a given event_id impacted. 69 70 @type event_id: C{string} 71 @param event_id: The event id to use when looking up impacted services 72 @type archive: C{boolean} 73 @param archive: Whether or not to search for the event in the event archive 74 75 @rtype: DirectResponse 76 @return: 77 - Properties: 78 - services: A sorted C{list} of C{dict} objects with keys: 79 - I{name} (C{string}) - The name of the service 80 - I{uuid} (C{string}) - The uuid of the service 81 """ 82 try: 83 ev_filter = self._buildFilter(None, json.dumps({'__meta__.impact.relatedevids':event_id})) 84 except InvalidQueryParameterException, e: 85 log.error("Related event detail is invalid. You may need to reinstall the " 86 "Impact ZenPack to force the details to be indexed.") 87 return DirectResponse.succeed(services=()) 88 89 this_filter = self._buildFilter(None, json.dumps({'evid':event_id})) 90 91 svcevents = self.zep.getEventSummaries(limit=100, offset=0, filter=ev_filter) 92 getEventFcn = self.zep.getEventSummariesFromArchive if archive else self.zep.getEventSummaries 93 thisevent = list(getEventFcn(limit=1, offset=0, filter=this_filter)['events']) 94 result = [] 95 uuids = set() 96 # First, get all the service uuids from the service events tagged with 97 # event_id 98 for ev in svcevents['events']: 99 actor = ev['occurrence'][0]['actor'] 100 if 'element_uuid' in actor: 101 uuids.add(actor['element_uuid']) 102 103 # Next, get all the affected service uuids directly from the event 104 # specified (will exist if it's a change event) 105 if len(thisevent) > 0: 106 for detail in thisevent[0]['occurrence'][0].get('details', ()): 107 if detail['name'] == '__meta__.impact.affectedservices': 108 uuids.update(detail['value']) 109 break 110 # Now build the list of services 111 for uuid in uuids: 112 try: 113 path = self.manager.getPath(uuid).split('/') 114 except KeyError: 115 pass 116 else: 117 # Build a name including organizers and excluding relationship 118 # e.g., /MyServices/ServiceA instead of 119 # /zport/dmd/DynamicServices/MyServices/services/ServiceA 120 name = '/' + '/'.join(path[4:-2] + path[-1:]) 121 result.append({'name':name, 122 'uuid':uuid}) 123 result.sort(key=lambda x:x['name']) 124 return DirectResponse.succeed(services=result)
125
126 - def _apply_event_weight(self, event, confidencemap):
127 """ 128 Look up and apply event weight modifiers. 129 """ 130 score = confidencemap[event['uuid']] 131 occurrence = event['occurrence'][0] 132 for _ignored in subscribers([occurrence, score, confidencemap], IRootCauseScoreAdjustment): 133 # Functions have no return value; subscribers() will call the 134 # handlers when iterated 135 pass 136 # Don't allow negative scores 137 score['confidence'] = max(score['confidence'], 0)
138
139 - def query(self, limit=0, start=0, sort='confidence', page=None, 140 dir='desc', params=None, archive=False, uid=None):
141 """ 142 Expects params to have an 'evid' parameter specifying the service 143 event(s) for which related events should be queried. 144 145 146 @rtype: DirectResponse 147 @return: 148 - Properties: 149 - B{events} ([C{dictionary}]) - A list of dictionaries representing event data 150 - B{totalCount} (C{integer}) - The total number of events 151 - B{asof} (C{float}) - The time for which this response is valid 152 """ 153 origsort, sort = sort, 'lastTime' if sort=='confidence' else sort 154 155 unpacked = json.loads(params) if isinstance(params, basestring) else {} 156 historical = False 157 if 'historical' in unpacked: 158 historical = unpacked.get('historical') 159 del unpacked['historical'] 160 modified_params = json.dumps(unpacked) 161 filter = self._buildFilter(uid, modified_params) 162 163 # _buildFilter turns evid into uuid, if there are any. If there 164 # aren't, short-circuit 165 if not filter.get('uuid', None): 166 results = {'events': (), 'total': 0} 167 else: 168 # Get the service events selected 169 svcevents = self.zep.getEventSummaries(limit=limit, offset=start, 170 sort=((sort, dir),), 171 filter=filter) 172 173 # Parse the details to find the related events 174 fingerprints = [] 175 relatedevs = {} 176 for event in svcevents['events']: 177 for detail in event.get( 178 'occurrence', [{}])[0].get('details', ()): 179 if detail['name'].startswith('__meta__.impact.changeevent'): 180 fingerprint = detail['name'].split(':', 1)[1] 181 if fingerprint: 182 fingerprints.append(fingerprint) 183 if historical: 184 if detail['name'].startswith('__meta__.impact.cause'): 185 evid = detail['name'].split(':')[1] 186 if evid: 187 confidence, proppath = detail['value'][0].split("&") 188 relatedevs[evid] = {"confidence": float(confidence), 189 "proppath": proppath.split("|")} 190 else: 191 if detail['name'] == '__meta__.impact.relatedevents': 192 for ev in json.loads(detail['value'][0]): 193 relatedevs[ev['eventId']] = { 194 "confidence": ev['score'], 195 "proppath": ev['propagationPath'] 196 } 197 # Query for impact changed events matching the fingerprints 198 if fingerprints: 199 filter = self.zep.createEventFilter(fingerprint=fingerprints) 200 results = self.zep.getEventSummaries(limit=100, offset=0, 201 sort=((sort, dir),), 202 filter=filter) 203 for result in results['events']: 204 relatedevs[result['uuid']] = {"confidence": 0} 205 206 # Query for all events related to service events by setting the 207 # evid parameter in params to the related evids. If there are no 208 # related evids, short-circuit 209 if relatedevs: 210 unpacked['evid'] = relatedevs.keys() 211 filter = self._buildFilter(uid, json.dumps(unpacked)) 212 results = self.zep.getEventSummaries(limit=limit, offset=start, 213 sort=((sort, dir),), 214 filter=filter) 215 else: 216 results = {'events': (), 'total': 0} 217 218 processed_events = [] 219 for ev in results['events']: 220 # Apply score adjustments 221 self._apply_event_weight(ev, relatedevs) 222 # Translate to old-style event schema with confidence 223 oldevent = self._mapToOldEvent(ev, relatedevs) 224 # Push it onto processed 225 processed_events.append(oldevent) 226 227 conftotal = sum(e['confidence'] for e in processed_events) 228 for e in processed_events: 229 # Set the confidence score to percentage instead of raw score 230 e['confidence'] = e['confidence'] / conftotal if conftotal else 0 231 232 # Sort by confidence score if requested 233 if origsort == "confidence": 234 processed_events.sort(key=lambda x:x['confidence'], reverse=(dir.lower()=="desc")) 235 236 return DirectResponse.succeed( 237 events=processed_events, 238 totalCount=results['total'], 239 asof=time.time())
240
241 - def _mapToOldEvent(self, event_summary, relatedevs):
242 result = super(RelatedEventsRouter, self)._mapToOldEvent(event_summary) 243 # This path has been split to better accomodate rendering templates. 244 propagation_path = relatedevs.get(result['evid'], {}).get("proppath", None) 245 propagation_path = [x.split(':') for x in propagation_path] 246 result['propagation_path'] = propagation_path 247 result['confidence'] = relatedevs.get(result['evid'], {}).get("confidence", None) 248 return result
249
250 251 -class ImpactRouter(TreeRouter):
252 """ 253 Router for Zenoss Impact 254 """ 255
256 - def _getFacade(self):
257 return Zuul.getFacade('enterpriseservices', self.context)
258 259 @impactServerConnectionError
260 - def getTree(self, id=None):
261 """ 262 Returns the dynamic services tree 263 264 @type id: String 265 @param id: The root UID for which to generate a tree. 266 267 @rtype: dictionary 268 @return: Tree designed to be used by ExtJs. This does not return a 269 DirectResponse because this method is intended to be used only by 270 ExtJs and will return format that an ExtJs direct proxy can consume. 271 """ 272 facade = self._getFacade() 273 data = Zuul.marshal(facade.getTree(id)) 274 return [data]
275 276 @impactServerConnectionError 277 @contextRequire(ZEN_MANAGE_DMD, 'uid')
278 - def setInfo(self, uid, **data):
279 """ 280 Set variables on a Dynamic Service 281 282 @type uid: string 283 @param uid: UID of the dynamic service to update 284 @type data: dictionary 285 @param data: Properties to update 286 287 @rtype: DirectResponse 288 @return: 289 - Properties: 290 - B{C{data}} (C{DynamicServiceInfo}) - The info object 291 """ 292 facade = self._getFacade() 293 node = facade._getObject(uid) 294 info = facade.setInfo(uid, data) 295 audit('UI.%s.Edit' % getDisplayType(node), uid) 296 return DirectResponse.succeed(data=Zuul.marshal(info))
297 298 @impactServerConnectionError
299 - def getInfo(self, uid, keys=None):
300 """ 301 Retrieve information about a dynamic service 302 303 @type uid: string 304 @param uid: UID of the dynamic service to query 305 306 @rtype: DirectResponse 307 @return: 308 - Properties: 309 - B{C{data}} (C{DynamicServiceInfo}) - An Info object for the service 310 - B{C{form}} (C{dictionary}) - A dictionary containing the ExtJs form 311 data for this object 312 """ 313 facade = self._getFacade() 314 info = facade.getInfo(uid) 315 form = IFormBuilder(info).render(fieldsets=True) 316 return DirectResponse(success=True, data=Zuul.marshal(info, keys=keys), form=form)
317 318 @require(ZEN_DELETE)
319 - def deleteNode(self, uid):
320 """ 321 Delete a Dynamic Service, Dynamic Service Organizer, or other kind of node 322 323 @type uid: string 324 @param uid: UID of the dynamic service to delete 325 """ 326 # When deleting a DynamicServiceOrganizer, audit all the sub-organizers and 327 # services that will be deleted. 328 node = self._getFacade()._getObject(uid) 329 if isinstance(node, DynamicServiceOrganizer): 330 childBrains = ICatalogTool(node).search(( 331 'ZenPacks.zenoss.Impact.DynamicServiceOrganizer.DynamicServiceOrganizer', 332 'ZenPacks.zenoss.Impact.DynamicService.DynamicService', 333 )) 334 for child in childBrains: 335 # don't audit this twice 336 if child.getPath() != uid: 337 audit(['UI', getDisplayType(child), 'Delete'], child.getPath()) 338 339 # Just delete the node and zope will notify the ModelChanged rabbit queue. 340 # Then zenimpactgraph will pick that up and make the necessary changes in Neo4J. 341 # Keeping this method around for ZEN_DELETE permissions (but not sure if still needed). 342 return super(ImpactRouter, self).deleteNode(uid)
343 344 @impactServerConnectionError
345 - def getInfoFromGuid(self, guid, contextId=None):
346 """ 347 Retrieve information about a dynamic service 348 349 @type guid: string 350 @param guid: GUID (global unique id) of the dynamic service to query 351 @type contextId: string 352 @param contextId: The uid of the parent 353 354 @rtype: DirectResponse 355 @return: 356 - Properties: 357 - B{C{data}} (C{DynamicServiceInfo}) - An Info object for the service 358 - B{C{form}} (C{dictionary}) - A dictionary containing the ExtJs form 359 data for this object 360 """ 361 facade = self._getFacade() 362 info = facade.getInfoFromGuid(guid) 363 form = IFormBuilder(info).render(fieldsets=True) 364 data = Zuul.marshal(info) 365 if contextId is not None: 366 parentInfo = facade.getInfo(contextId) 367 data['contextualState'] = facade.graphservice.getContextualState(guid, parentInfo.guid) 368 return DirectResponse(success=True, data=data, form=form)
369 370 @impactServerConnectionError 371 @require(ZEN_ADD)
372 - def addNode(self, contextUid, id):
373 """ 374 Creates a new Dynamic Service designated by the id field 375 376 @type contextUid: string 377 @param contextUid: organizer for the new service 378 @type id: string 379 @param id: Unique identifier of the new Dynamic Service 380 381 @rtype: DirectResponse 382 """ 383 facade = self._getFacade() 384 node = facade.addNode(contextUid, id) 385 audit('UI.DynamicService.Add', node.getPrimaryId()) 386 return DirectResponse.succeed()
387 388 @impactServerConnectionError 389 @require(ZEN_ADD)
390 - def addOrganizer(self, contextUid, id):
391 """ 392 Creates a new Dynamic Service Organizer 393 394 @type contextUid: string 395 @param contextUid: Not used but sent by the client 396 @type id: string 397 @param id: Unique identifier of the new Dynamic Service Organizer 398 399 @rtype: DirectResponse 400 @return: 401 - Properties: 402 - B{C{data}} (C{Info}) - The Info object for the newly 403 created service organizer 404 """ 405 facade = self._getFacade() 406 node = facade.addOrganizer(contextUid, id) 407 data = Zuul.marshal(IInfo(node)) 408 audit('UI.DynamicServiceOrganizer.Add', node.getPrimaryId()) 409 return DirectResponse.succeed(data=data)
410 411
412 - def _loadRanges(self, query, category, ranges, hashcheck, sort, dir):
413 """ 414 (Internal) 415 """ 416 uids = [] 417 results = self.getAllResults(query, category=category, 418 limit=None, 419 sort=sort, 420 dir=dir) 421 results = results['results'] 422 for start, stop in sorted(ranges): 423 uids.extend(b['url'] for b in islice(results, start, stop + 1)) 424 425 return uids
426 427 @impactServerConnectionError 428 @contextRequire(ZEN_ADD, 'targetUid')
429 - def addToDynamicService(self, targetUid, uids, 430 query=None, category=None, 431 hashcheck=None, ranges=(), 432 sort='except', dir='ASC' 433 ):
434 """ 435 Make node(s) impact a Dynamic Service. 436 437 @type targetUid: string 438 @param targetUid: Unique Identifier of a Dynamic service 439 @type uids: [string] 440 @param uids: List of uids of items we are adding 441 442 @rtype: DirectResponse 443 @return: 444 - Properties: 445 - B{C{numberAdded}} (C{integer}) - Total number of added impacts 446 """ 447 if ranges: 448 uids += self._loadRanges(query, category, ranges, hashcheck, sort, dir) 449 facade = self._getFacade() 450 facade.addToDynamicService(targetUid, uids) 451 audit('UI.DynamicService.AddImpact', targetUid, nodes=uids) 452 return DirectResponse.succeed(numberAdded=len(uids))
453 454 @impactServerConnectionError
455 - def getServices(self, uid=None, limit=None, sort=None, start=None, dir=None, keys=None, page=None):
456 """ 457 Retrieves Info objects for all services of which the object 458 represented by uid is a part. 459 460 @rtype: DirectResponse 461 @return: 462 - Properties: 463 - B{C{data}} ([C{DynamicServiceInfo}]) - List of Info objects 464 """ 465 svcs = self._getFacade().getServices(uid) 466 return DirectResponse.succeed(data=Zuul.marshal(svcs, keys=keys))
467
468 - def getServiceOrganizers(self, **data):
469 """ 470 Get a list of all Dynamic Service Organizers. 471 472 @param data: unused 473 474 @rtype: DirectResponse 475 @return: 476 - Properties: 477 - B{C{serviceOrgs}} ([C{dictionary}]) - List of service organizers 478 - B{C{totalCount}} (C{integer}) - Total number of service organizers 479 """ 480 services = self.context.dmd.DynamicServices 481 serviceOrgs = services.getOrganizerNames() 482 result = [{'name': name} for name in serviceOrgs] 483 return DirectResponse(serviceOrgs=result, totalCount=len(result))
484 485 @impactServerConnectionError
486 - def getDependencies(self, uid, query="", sort=None, dir=None, 487 limit=None, page=None, start=None):
488 """ 489 Retrieves every item currently impacting the given Dynamic Service 490 491 @type uid: string 492 @param uid: Unique identifier of a Dynamic Service 493 @param query: unused 494 @param sort: unused 495 @param dir: unused 496 @param limit: unused 497 @param page: unused 498 @param start: unused 499 500 @rtype: DirectResponse 501 @return: 502 - Properties: 503 - B{C{data}} [C{Info}] - A list of Info objects of the items in 504 the service 505 """ 506 facade = self._getFacade() 507 data = Zuul.marshal(facade.getDependencies(uid)) 508 return DirectResponse.succeed(data=data)
509 510 @impactServerConnectionError 511 @contextRequire(ZEN_DELETE, 'targetUid')
512 - def removeFromDynamicService(self, targetUid, uids):
513 """ 514 Remove impacts from a Dynamic Service. 515 516 @type targetUid: string 517 @param targetUid: Unique Identifier of a Dynamic service 518 @type uids: [string] 519 @param uids: List of uids of items to remove 520 521 @rtype: DirectResponse 522 """ 523 facade = self._getFacade() 524 facade.removeFromDynamicService(targetUid, uids) 525 audit('UI.DynamicService.RemoveImpact', targetUid, nodes=uids) 526 return DirectResponse.succeed()
527 528 @impactServerConnectionError 529 @require(ZEN_MANAGE_DMD)
530 - def moveNode(self, uids, targetUid):
531 """ 532 Move a list of nodes to another organizer. 533 534 @type uids: [string] 535 @param uids: List of uids to be moved, can be either organizers or dynamic services 536 @type targetUid: string 537 @param targetUid: Uid of a Dynamic Service Organizer 538 539 @rtype: DirectResponse 540 """ 541 facade = self._getFacade() 542 for uid in uids: 543 node = facade._getObject(uid) 544 audit('UI.%s.Move' % getDisplayType(node), uid, to=targetUid) 545 facade.moveNode(uids, targetUid) 546 return DirectResponse.succeed()
547 548 @impactServerConnectionError 549 @contextRequire(ZEN_ADD, 'permissionUid')
550 - def addStateTrigger(self, permissionUid, contextUid, uid, policyType, data):
551 """ 552 Set the state triggers for a service node 553 554 @rtype: DirectResponse 555 """ 556 facade = self._getFacade() 557 data = facade.addStateTrigger(contextUid, uid, policyType, data) 558 audit('UI.DynamicService.AddPolicy', contextUid, policyType=policyType) 559 return DirectResponse.succeed(data=Zuul.marshal(data))
560 561 @impactServerConnectionError 562 @contextRequire(ZEN_MANAGE_DMD, 'permissionUid')
563 - def setStateTrigger(self, permissionUid, contextUid, uid, policyType, guid, data):
564 """ 565 Set the state triggers for a service node 566 567 @rtype: DirectResponse 568 """ 569 facade = self._getFacade() 570 data = facade.setStateTrigger(contextUid, uid, policyType, guid, data) 571 audit('UI.DynamicService.EditPolicy', contextUid, policyType=policyType) 572 return DirectResponse.succeed(data=Zuul.marshal(data))
573 574 @impactServerConnectionError 575 @contextRequire(ZEN_DELETE, 'permissionUid')
576 - def removeStateTrigger(self, permissionUid, contextUid, uid, policyType, guid):
577 """ 578 Remove a state trigger 579 580 @rtype: DirectResponse 581 """ 582 facade = self._getFacade() 583 data = facade.removeStateTrigger(contextUid, uid, policyType, guid) 584 audit('UI.DynamicService.RemovePolicy', contextUid, policyType=policyType) 585 return DirectResponse.succeed(data=Zuul.marshal(data))
586 587 @impactServerConnectionError
588 - def getStateTriggers(self, contextUid, uid, policyType):
589 """ 590 Retrieve all the state triggers for a service node 591 592 @rtype: DirectResponse 593 @return: 594 - Properties: 595 - B{C{data}} (C{dictionary}) - The trigger data 596 """ 597 facade = self._getFacade() 598 data = facade.getStateTriggers(contextUid, uid, policyType) 599 return DirectResponse.succeed(data=Zuul.marshal(data))
600
601 - def filterByInImpactGraph(self, result):
602 """ 603 Filters the search results by what is in the impact graph. 604 Note that to do this we have to wake up every object 605 in the search results. 606 607 @type result: iterable 608 @param result: search results (events and brains) 609 610 @rtype: boolean 611 @return: Whether the object should be returned 612 """ 613 if not isinstance(result, AbstractCatalogBrain): 614 return False 615 obj = result.getObject() 616 return objectBelongsInImpactGraph(obj)
617
618 - def getCategoryCounts(self, query):
619 """ 620 Returns the search categories for the given query. 621 622 @rtype: dictionary 623 @return: 624 - Properties: 625 - B{C{results}} ([C{dictionary}]) - List of results 626 - B{C{total}} (C{integer}) - Total number of results 627 """ 628 facade = Zuul.getFacade('search', self.context) 629 results = facade.getCategoryCounts(query, filterFn=self.filterByInImpactGraph) 630 total = sum([result['count'] for result in results]) 631 return {'results': results, 632 'total': total}
633
634 - def getAllResults(self, query, **kwargs):
635 """ 636 Use the search provider but filter the search results to what is in the 637 impact graph. This is used by an ExtJs ResultsGrid. 638 639 @rtype: dictionary 640 @return: 641 - Properties: 642 - B{C{results}} ([C{dictionary}]) - List of results 643 - B{C{total}} (C{integer}) - Total number of results 644 """ 645 facade = Zuul.getFacade('search', self.context) 646 results = facade.getSearchResults(query, 647 filterFn=self.filterByInImpactGraph, 648 resultSorter=None, 649 **kwargs) 650 return {'results': Zuul.marshal(results['results']), 651 'total': results['total']}
652 653 @impactServerConnectionError
654 - def setStateProvider(self, uid, stateType, stateMap, eventClass, applyTo):
655 """ 656 Set state provider data. 657 658 @type uid: string 659 @param uid: Service UID to update 660 @type stateType: string 661 @param stateType: (optional) Type of state for which to apply update; Can 662 be one of 'availability' or 'performance'. 663 @type stateMap: dictionary 664 @param stateMap: A mapping of event severity levels to states. 665 @type eventClass: string 666 @param eventClass: The eventClass for which the state provider should be 667 applied. 668 @type applyTo: string 669 @param applyTo: The context to which the state provider should be 670 applied to. Can be one of 'NODE', 'DEVICE', 'DEVICECLASS' or 'ALL'. 671 672 @rtype: DirectResponse 673 """ 674 facade = self._getFacade() 675 facade.setStateProvider(uid, stateType, stateMap, eventClass, applyTo) 676 audit('UI.DynamicService.SetStateProvider', uid, stateType=stateType) 677 return DirectResponse.succeed()
678 679 @impactServerConnectionError
680 - def setQuiet(self, guid, quiet):
681 """ 682 Set whether or not a service should send service events. 683 684 @type guid: string 685 @param guid: The guid of the service to update 686 @type quiet: boolean 687 @param quiet: Whether or not the service should send service events 688 689 @rtype: DirectResponse 690 """ 691 facade = self._getFacade() 692 facade.setQuiet(guid, quiet) 693 info = facade.getInfoFromGuid(guid) 694 audit('UI.DynamicService.SetQuiet', info.uid, quiet=str(quiet)) 695 return DirectResponse.succeed()
696 697 @impactServerConnectionError
698 - def cloneService(self, uid, newId):
699 """ 700 Clone a service into the same organizer with the same children and 701 contextual policies. 702 703 @type uid: string 704 @param uid: Unique identifier of the Dynamic Service to clone 705 @type newId: string 706 @param newId: Identifier for the new clone 707 708 @rtype: DirectResponse 709 @return: 710 - Properties: 711 - B{C{data}} ([C{dictionary}]) - C{DynamicServiceInfo} object on the new clone 712 """ 713 facade = self._getFacade() 714 newnode = facade.cloneService(uid, newId) 715 audit('UI.DynamicService.Clone', uid, clone=newnode.uid) 716 return DirectResponse.succeed(data=Zuul.marshal(newnode, keys=['uid']))
717 718 @impactServerConnectionError
719 - def getInstances(self, uid, start=0, params=None, limit=50, sort='name', page=None, 720 stateType="availability", dir='ASC'):
721 """ 722 Get a list of DynamicServices for an organizer UID. 723 724 @type uid: string 725 @param uid: Service UID to get instances of 726 @type start: integer 727 @param start: (optional) Offset to return the results from; used in pagination 728 @param params: unused 729 @type limit: integer 730 @param limit: (optional) Number of items to return; used in pagination 731 @type sort: string 732 @param sort: (optional) Key on which to sort the return results 733 @type stateType: string 734 @param stateType: (optional) Type of state for which to get results; Can 735 be one of 'availability' or 'performance'. 736 @type dir: string 737 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 738 739 @rtype: DirectResponse 740 @return: 741 - Properties: 742 - B{C{data}} ([C{dict}]) - List of objects representing service instances. 743 - B{C{totalCount}} (C{integer}) - Total number of instances. 744 """ 745 facade = self._getFacade() 746 instances = facade.getInstances(uid, start, limit, sort, dir) 747 data = Zuul.marshal(instances['infos'], 748 keys=['uid', 'uuid', 'name', stateType] 749 ) 750 return DirectResponse.succeed(data=data, totalCount=instances['total'])
751
752 - def checkDatabaseState(self):
753 """ 754 Determines whether the impact graph needs to be reset. 755 This searches for the critical impact event generated from NotFoundException. 756 757 @rtype: DirectResponse 758 @return: 759 - Properties: 760 - B{C{needsReset}} (C{boolean}) - Whether or not the impact graph 761 state needs to be reset 762 """ 763 try: 764 zep = getFacade('zep') 765 filter = zep.createEventFilter( 766 severity=IMPACT_NEEDS_RESET['severity'], 767 event_class=IMPACT_NEEDS_RESET['event_class'], 768 element_title=IMPACT_NEEDS_RESET['resource'], 769 event_summary=IMPACT_NEEDS_RESET['msg'], 770 status=(STATUS_NEW, STATUS_ACKNOWLEDGED)) 771 events = zep.getEventSummaries(0, limit=1, filter=filter) 772 needsReset = events['total'] > 0 773 except ZepConnectionError: 774 log.warn('Unable to connect to zeneventserver') 775 # Assume everything is okay unless hear otherwise 776 needsReset = False 777 return DirectResponse.succeed(needsReset=needsReset)
778
779 - def resetImpactGraph(self):
780 """ 781 Rebuilds the entire impact graph. This may take a few minutes. 782 783 @rtype: DirectResponse 784 """ 785 facade = self._getFacade() 786 facade.resetImpactGraph() 787 return DirectResponse.succeed()
788