Package Products :: Package Zuul :: Package routers :: Module device
[hide private]
[frames] | no frames]

Source Code for Module Products.Zuul.routers.device

   1  ############################################################################## 
   2  #  
   3  # Copyright (C) Zenoss, Inc. 2009, all rights reserved. 
   4  #  
   5  # This content is made available according to terms specified in 
   6  # License.zenoss under the directory where your Zenoss product is installed. 
   7  #  
   8  ############################################################################## 
   9   
  10   
  11  """ 
  12  Operations for Device Organizers and Devices. 
  13   
  14  Available at:  /zport/dmd/device_router 
  15  """ 
  16   
  17  import logging 
  18  from itertools import islice 
  19  from AccessControl import Unauthorized 
  20  from Products.ZenUtils.Ext import DirectResponse 
  21  from Products.ZenUtils.Utils import getDisplayType 
  22  from Products.ZenUtils.jsonutils import unjson 
  23  from Products import Zuul 
  24  from Products.ZenModel.Device import Device 
  25  from Products.ZenModel.ZenossSecurity import ZEN_CHANGE_DEVICE_PRODSTATE, ZEN_MANAGE_DMD, \ 
  26      ZEN_ADMIN_DEVICE, ZEN_MANAGE_DEVICE, ZEN_ZPROPERTIES_EDIT, ZEN_DELETE_DEVICE 
  27  from Products.Zuul import filterUidsByPermission 
  28  from Products.Zuul.routers import TreeRouter 
  29  from Products.Zuul.interfaces import IInfo 
  30  from Products.Zuul.catalog.events import IndexingEvent 
  31  from Products.Zuul.form.interfaces import IFormBuilder 
  32  from Products.Zuul.decorators import require, contextRequire, serviceConnectionError 
  33  from Products.ZenUtils.guid.interfaces import IGlobalIdentifier 
  34  from Products.ZenMessaging.audit import audit 
  35  from zope.event import notify 
  36   
  37   
  38  log = logging.getLogger('zen.Zuul') 
39 40 41 -class DeviceRouter(TreeRouter):
42 """ 43 A JSON/ExtDirect interface to operations on devices 44 """ 45 46 @serviceConnectionError 47 @require('Manage DMD')
48 - def addLocationNode(self, type, contextUid, id, 49 description=None, address=None):
50 """ 51 Adds a new location organizer specified by the parameter id to 52 the parent organizer specified by contextUid. 53 54 contextUid must be a path to a Location. 55 56 @type type: string 57 @param type: Node type (always 'organizer' in this case) 58 @type contextUid: string 59 @param contextUid: Path to the location organizer that will 60 be the new node's parent (ex. /zport/dmd/Devices/Locations) 61 @type id: string 62 @param id: The identifier of the new node 63 @type description: string 64 @param description: (optional) Describes the new location 65 @type address: string 66 @param address: (optional) Physical address of the new location 67 @rtype: dictionary 68 @return: B{Properties}: 69 - success: (bool) Success of node creation 70 - nodeConfig: (dictionary) The new location's properties 71 """ 72 facade = self._getFacade() 73 organizer = facade.addLocationOrganizer(contextUid, 74 id, 75 description, 76 address) 77 uid = organizer.uid 78 79 treeNode = facade.getTree(uid) 80 audit('UI.Location.Add', uid, description=description, address=address) 81 return DirectResponse.succeed("Location added", nodeConfig=Zuul.marshal(treeNode))
82
83 - def _getFacade(self):
84 return Zuul.getFacade('device', self.context)
85 86 @serviceConnectionError
87 - def getTree(self, id):
88 """ 89 Returns the tree structure of an organizer hierarchy where 90 the root node is the organizer identified by the id parameter. 91 92 @type id: string 93 @param id: Id of the root node of the tree to be returned 94 @rtype: [dictionary] 95 @return: Object representing the tree 96 """ 97 facade = self._getFacade() 98 tree = facade.getTree(id) 99 data = Zuul.marshal(tree) 100 return [data]
101
102 - def _filterComponents(self, comps, keys, query):
103 """ 104 Returns a list of components where one of the attributes in keys contains 105 the query (case-insensitive). 106 107 @type comps: SearchResults 108 @param comps: All the Components for this query 109 @type keys: List 110 @param keys: List of strings of fields that we are filtering on 111 @type query: String 112 @param query: Search Term 113 @rtype: List 114 @return: List of Component Info objects that match the query 115 """ 116 results = [] 117 for comp in comps: 118 keep = False 119 for key in keys: 120 # non searchable fields 121 if key in ('uid', 'uuid', 'events', 'status', 'severity'): 122 continue 123 val = getattr(comp, key, None) 124 if not val: 125 continue 126 if callable(val): 127 val = val() 128 if IInfo.providedBy(val): 129 val = val.name 130 if query.lower() in str(val).lower(): 131 keep = True 132 break 133 if keep: 134 results.append(comp) 135 return results
136 137 @serviceConnectionError
138 - def getComponents(self, uid=None, meta_type=None, keys=None, start=0, 139 limit=50, page=0, sort='name', dir='ASC', name=None):
140 """ 141 Retrieves all of the components at a given UID. This method 142 allows for pagination. 143 144 @type uid: string 145 @param uid: Unique identifier of the device whose components are 146 being retrieved 147 @type meta_type: string 148 @param meta_type: (optional) The meta type of the components to be 149 retrieved (default: None) 150 @type keys: list 151 @param keys: (optional) List of keys to include in the returned 152 dictionary. If None then all keys will be returned 153 (default: None) 154 @type start: integer 155 @param start: (optional) Offset to return the results from; used in 156 pagination (default: 0) 157 @type limit: integer 158 @param limit: (optional) Number of items to return; used in pagination 159 (default: 50) 160 @type sort: string 161 @param sort: (optional) Key on which to sort the return results; 162 (default: 'name') 163 @type dir: string 164 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 165 (default: 'ASC') 166 @type name: regex 167 @param name: (optional) Used to filter the results (default: None) 168 @rtype: DirectResponse 169 @return: B{Properties}: 170 - data: (dictionary) The components returned 171 - totalCount: (integer) Number of items returned 172 - hash: (string) Hashcheck of the current component state (to check 173 whether components have changed since last query) 174 """ 175 facade = self._getFacade() 176 if name: 177 # Load every component if we have a filter 178 limit = None 179 comps = facade.getComponents(uid, meta_type=meta_type, start=start, 180 limit=limit, sort=sort, dir=dir) 181 total = comps.total 182 hash = comps.hash_ 183 if name: 184 comps = self._filterComponents(comps, keys, name) 185 total = len(comps) 186 187 data = Zuul.marshal(comps, keys=keys) 188 return DirectResponse(data=data, totalCount=total, 189 hash=hash)
190
191 - def getComponentTree(self, uid=None, id=None):
192 """ 193 Retrieves all of the components set up to be used in a 194 tree. 195 196 @type uid: string 197 @param uid: Unique identifier of the root of the tree to retrieve 198 @type id: string 199 @param id: not used 200 @rtype: [dictionary] 201 @return: Component properties in tree form 202 """ 203 if id: 204 uid = id 205 facade = self._getFacade() 206 data = facade.getComponentTree(uid) 207 sevs = [c[0].lower() for c in 208 self.context.ZenEventManager.severityConversions] 209 data.sort(cmp=lambda a, b: cmp(sevs.index(a['severity']), 210 sevs.index(b['severity']))) 211 result = [] 212 for datum in data: 213 result.append(dict( 214 id=datum['type'], 215 path='Components/%s' % datum['type'], 216 text={ 217 'text': datum['type'], 218 'count': datum['count'], 219 'description': 'components'}, 220 iconCls='tree-severity-icon-small-' + datum['severity'], 221 leaf=True)) 222 return result
223
224 - def findComponentIndex(self, componentUid, uid=None, meta_type=None, 225 sort='name', dir='ASC', name=None, **kwargs):
226 """ 227 Given a component uid and the component search criteria, this retrieves 228 the position of the component in the results. 229 230 @type componentUid: string 231 @param componentUid: Unique identifier of the component whose index 232 to return 233 @type uid: string 234 @param uid: Unique identifier of the device queried for components 235 @type meta_type: string 236 @param meta_type: (optional) The meta type of the components to retrieve 237 (default: None) 238 @type sort: string 239 @param sort: (optional) Key on which to sort the return results (default: 240 'name') 241 @type dir: string 242 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 243 (default: 'ASC') 244 @type name: regex 245 @param name: (optional) Used to filter the results (default: None) 246 @rtype: DirectResponse 247 @return: B{Properties}: 248 - index: (integer) Index of the component 249 """ 250 facade = self._getFacade() 251 i = facade.findComponentIndex(componentUid, uid, 252 meta_type, sort, dir, name) 253 return DirectResponse(index=i)
254 255 @serviceConnectionError
256 - def getForm(self, uid):
257 """ 258 Given an object identifier, this returns all of the editable fields 259 on that object as well as their ExtJs xtype that one would 260 use on a client side form. 261 262 @type uid: string 263 @param uid: Unique identifier of an object 264 @rtype: DirectResponse 265 @return: B{Properties} 266 - form: (dictionary) form fields for the object 267 """ 268 info = self._getFacade().getInfo(uid) 269 form = IFormBuilder(info).render(fieldsets=False) 270 form = Zuul.marshal(form) 271 return DirectResponse(form=form)
272 273 @serviceConnectionError
274 - def getInfo(self, uid, keys=None):
275 """ 276 Get the properties of a device or device organizer 277 278 @type uid: string 279 @param uid: Unique identifier of an object 280 @type keys: list 281 @param keys: (optional) List of keys to include in the returned 282 dictionary. If None then all keys will be returned 283 (default: None) 284 @rtype: DirectResponse 285 @return: B{Properties} 286 - data: (dictionary) Object properties 287 - disabled: (bool) If current user doesn't have permission to use setInfo 288 """ 289 facade = self._getFacade() 290 process = facade.getInfo(uid) 291 data = Zuul.marshal(process, keys) 292 disabled = not Zuul.checkPermission('Manage DMD', self.context) 293 return DirectResponse(data=data, disabled=disabled)
294 295 @serviceConnectionError
296 - def setInfo(self, **data):
297 """ 298 Set attributes on a device or device organizer. 299 This method accepts any keyword argument for the property that you wish 300 to set. The only required property is "uid". 301 302 @type uid: string 303 @keyword uid: Unique identifier of an object 304 @rtype: DirectResponse 305 """ 306 facade = self._getFacade() 307 if not Zuul.checkPermission('Manage DMD', self.context): 308 raise Exception('You do not have permission to save changes.') 309 the_uid = data['uid'] # gets deleted 310 process = facade.getInfo(the_uid) 311 oldData = self._getInfoData(process, data.keys()) 312 Zuul.unmarshal(data, process) 313 newData = self._getInfoData(process, data.keys()) 314 # reindex the object if necessary 315 if hasattr(process._object, 'index_object'): 316 process._object.index_object() 317 318 # Ex: ('UI.Device.Edit', uid, data_={'ProductionState': 'High'}) 319 # Ex: ('UI.Location.Edit', uid, description='Blah', old_description='Foo') 320 if 'name' in oldData: 321 oldData['device_name'] = oldData['name'] # we call it this now 322 del oldData['name'] 323 if 'name' in newData: 324 del newData['name'] # it gets printed automatically 325 audit(['UI', getDisplayType(process._object), 'Edit'], the_uid, 326 data_=newData, oldData_=oldData, skipFields_='uid') 327 return DirectResponse.succeed()
328
329 - def _getInfoData(self, info, keys):
330 # TODO: generalize this code for all object types, if possible. 331 values = {} 332 for key in keys: 333 val = getattr(info, key, None) 334 if val is not None: 335 values[key] = str(val) # unmutable copy 336 return values
337 338 @require('Manage Device')
339 - def setProductInfo(self, uid, **data):
340 """ 341 Sets the ProductInfo on a device. This method has the following valid 342 keyword arguments: 343 344 @type uid: string 345 @keyword uid: Unique identifier of a device 346 @type hwManufacturer: string 347 @keyword hwManufacturer: Hardware manufacturer 348 @type hwProductName: string 349 @keyword hwProductName: Hardware product name 350 @type osManufacturer: string 351 @keyword osManufacturer: Operating system manufacturer 352 @type osProductName: string 353 @keyword osProductName: Operating system product name 354 @rtype: DirectResponse 355 """ 356 facade = self._getFacade() 357 facade.setProductInfo(uid, **data) 358 audit('UI.Device.Edit', uid, data_=data) 359 return DirectResponse()
360
361 - def getDeviceUuidsByName(self, query="", start=0, limit=25, page=1):
362 """ 363 Retrieves a list of device uuids. For use in combos. 364 """ 365 facade = self._getFacade() 366 devices = facade.getDevices(params={'name':query}) 367 result = [] 368 for dev in devices: 369 result.append({'name':dev.name, 370 'uuid':IGlobalIdentifier(dev._object).getGUID()}) 371 return DirectResponse.succeed(data=result)
372
373 - def getDeviceUids(self, uid):
374 """ 375 Return a list of device uids underneath an organizer. This includes 376 all the devices belonging to an child organizers. 377 378 @type uid: string 379 @param uid: Unique identifier of the organizer to get devices from 380 @rtype: DirectResponse 381 @return: B{Properties}: 382 - devices: (list) device uids 383 """ 384 facade = self._getFacade() 385 uids = facade.getDeviceUids(uid) 386 return DirectResponse.succeed(devices=uids)
387 388 @serviceConnectionError
389 - def getDevices(self, uid=None, start=0, params=None, limit=50, sort='titleOrId', 390 page=None, 391 dir='ASC', keys=None):
392 """ 393 Retrieves a list of devices. This method supports pagination. 394 395 @type uid: string 396 @param uid: Unique identifier of the organizer to get devices from 397 @type start: integer 398 @param start: (optional) Offset to return the results from; used in 399 pagination (default: 0) 400 @type params: dictionary 401 @param params: (optional) Key-value pair of filters for this search. 402 Can be one of the following: name, ipAddress, 403 deviceClass, or productionState (default: None) 404 @type limit: integer 405 @param limit: (optional) Number of items to return; used in pagination 406 (default: 50) 407 @type sort: string 408 @param sort: (optional) Key on which to sort the return results (default: 409 'name') 410 @type dir: string 411 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 412 (default: 'ASC') 413 @rtype: DirectResponse 414 @return: B{Properties}: 415 - devices: (list) Dictionaries of device properties 416 - totalCount: (integer) Number of devices returned 417 - hash: (string) Hashcheck of the current device state (to check 418 whether devices have changed since last query) 419 """ 420 facade = self._getFacade() 421 if isinstance(params, basestring): 422 params = unjson(params) 423 424 devices = facade.getDevices(uid, start, limit, sort, dir, params) 425 allKeys = ['name', 'ipAddress', 'productionState', 'events', 426 'ipAddressString', 'serialNumber', 'tagNumber', 427 'hwManufacturer', 'hwModel', 'osModel', 'osManufacturer', 428 'collector', 'priority', 'systems', 'groups', 'location', 429 'pythonClass', 'tagNumber', 'serialNumber', 430 'hwModel', 'hwManufacturer', 431 'osModel', 'osManufacturer', 432 'groups', 'systems', 'location'] 433 usedKeys = keys or allKeys 434 if not 'uid' in usedKeys: 435 usedKeys.append('uid') 436 437 data = Zuul.marshal(devices.results, usedKeys) 438 439 return DirectResponse(devices=data, totalCount=devices.total, 440 hash=devices.hash_)
441
442 - def renameDevice(self, uid, newId):
443 """ 444 Set the device specified by the uid,"uid" to have the 445 the id "newId" 446 This will raise an exception if it fails. 447 448 @type uid: string 449 @param uid: The unique id of the device we are renaming 450 @type newId: string 451 @param newId: string of the new id 452 """ 453 facade = self._getFacade() 454 newUid = facade.renameDevice(uid, newId) 455 return DirectResponse.succeed(uid=newUid)
456
457 - def moveDevices(self, uids, target, hashcheck=None, ranges=(), uid=None, 458 params=None, sort='name', dir='ASC', asynchronous=True):
459 """ 460 Moves the devices specified by uids to the organizer specified by 'target'. 461 462 @type uids: [string] 463 @param uids: List of device uids to move 464 @type target: string 465 @param target: Uid of the organizer to move the devices to 466 @type hashcheck: string 467 @param hashcheck: Hashcheck for the devices (from getDevices()) 468 @type ranges: [integer] 469 @param ranges: (optional) List of two integers that are the min/max 470 values of a range of uids to include (default: None) 471 @type uid: string 472 @param uid: (optional) Organizer to use when using ranges to get 473 additional uids (default: None) 474 @type params: dictionary 475 @param params: (optional) Key-value pair of filters for this search. 476 Can be one of the following: name, ipAddress, 477 deviceClass, or productionState (default: None) 478 @type sort: string 479 @param sort: (optional) Key on which to sort the return result (default: 480 'name') 481 @type dir: string 482 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 483 (default: 'ASC') 484 @rtype: DirectResponse 485 @return: B{Properties}: 486 - tree: ([dictionary]) Object representing the new device tree 487 - exports: (integer) Number of devices moved 488 """ 489 if ranges: 490 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 491 492 facade = self._getFacade() 493 494 # In order to display the device name and old location/device class, 495 # we must audit first. This means it's possible we can audit a change 496 # then the command fails, unfortunately. 497 # example: audit('UI.Device.ChangeLocation', uid, location=..., old_location=...) 498 targetType = getDisplayType(facade._getObject(target)) 499 autoRemovalTypes = ('DeviceClass', 'Location') 500 action = ('Change' if targetType in autoRemovalTypes else 'AddTo') + targetType 501 for uid in uids: 502 oldData = {} 503 if targetType == 'Location': # get old location 504 location = facade._getObject(uid).location() 505 locationPath = location.getPrimaryId() if location else '' 506 oldData[targetType] = locationPath 507 elif targetType == 'DeviceClass': 508 deviceClass = facade._getObject(uid).deviceClass() 509 deviceClassPath = deviceClass.getPrimaryId() if deviceClass else '' 510 oldData[targetType] = deviceClassPath 511 audit(['UI.Device', action], uid, 512 data_={targetType:target}, oldData_=oldData) 513 try: 514 result = facade.moveDevices(uids, target, asynchronous=asynchronous) 515 except Exception, e: 516 log.exception("Failed to move devices") 517 return DirectResponse.exception(e, 'Failed to move devices.') 518 if asynchronous: 519 return DirectResponse.succeed(new_jobs=Zuul.marshal([result], 520 keys=('uuid', 'description', 'started'))) 521 else: 522 return DirectResponse.succeed(exports=result)
523 524 @require('Manage Device')
525 - def pushChanges(self, uids, hashcheck, ranges=(), uid=None, params=None, 526 sort='name', dir='ASC'):
527 """ 528 Push changes on device(s) configuration to collectors. 529 530 @type uids: [string] 531 @param uids: List of device uids to push changes 532 @type hashcheck: string 533 @param hashcheck: Hashcheck for the devices (from getDevices()) 534 @type ranges: [integer] 535 @param ranges: (optional) List of two integers that are the min/max 536 values of a range of uids to include (default: None) 537 @type uid: string 538 @param uid: (optional) Organizer to use when using ranges to get 539 additional uids (default: None) 540 @type params: dictionary 541 @param params: (optional) Key-value pair of filters for this search. 542 Can be one of the following: name, ipAddress, 543 deviceClass, or productionState (default: None) 544 @type sort: string 545 @param sort: (optional) Key on which to sort the return result (default: 546 'name') 547 @type dir: string 548 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 549 (default: 'ASC') 550 @rtype: DirectResponse 551 @return: Success message 552 """ 553 if ranges: 554 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 555 556 facade = self._getFacade() 557 facade.pushChanges(uids) 558 for uid in uids: 559 audit('UI.Device.PushChanges', uid) 560 return DirectResponse.succeed('Changes pushed to collectors.')
561
562 - def lockDevices(self, uids, hashcheck, ranges=(), updates=False, 563 deletion=False, sendEvent=False, uid=None, params=None, 564 sort='name', dir='ASC'):
565 """ 566 Lock device(s) from changes. 567 568 @type uids: [string] 569 @param uids: List of device uids to lock 570 @type hashcheck: string 571 @param hashcheck: Hashcheck for the devices (from getDevices()) 572 @type ranges: [integer] 573 @param ranges: (optional) List of two integers that are the min/max 574 values of a range of uids to include (default: None) 575 @type updates: boolean 576 @param updates: (optional) True to lock device from updates (default: False) 577 @type deletion: boolean 578 @param deletion: (optional) True to lock device from deletion 579 (default: False) 580 @type sendEvent: boolean 581 @param sendEvent: (optional) True to send an event when an action is 582 blocked by locking (default: False) 583 @type uid: string 584 @param uid: (optional) Organizer to use when using ranges to get 585 additional uids (default: None) 586 @type params: dictionary 587 @param params: (optional) Key-value pair of filters for this search. 588 Can be one of the following: name, ipAddress, 589 deviceClass, or productionState (default: None) 590 @type sort: string 591 @param sort: (optional) Key on which to sort the return result (default: 592 'name') 593 @type dir: string 594 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 595 (default: 'ASC') 596 @rtype: DirectResponse 597 @return: Success or failure message 598 """ 599 if ranges: 600 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 601 facade = self._getFacade() 602 uids = filterUidsByPermission(self.context.dmd, ZEN_MANAGE_DMD, uids) 603 try: 604 facade.setLockState(uids, deletion=deletion, updates=updates, 605 sendEvent=sendEvent) 606 if not deletion and not updates: 607 message = "Unlocked %s devices." % len(uids) 608 else: 609 actions = [] 610 if deletion: 611 actions.append('deletion') 612 if updates: 613 actions.append('updates') 614 message = "Locked %s devices from %s." % (len(uids), 615 ' and '.join(actions)) 616 for uid in uids: 617 audit('UI.Device.EditLocks', uid, 618 deletion=deletion, updates=updates, sendEvent=sendEvent) 619 return DirectResponse.succeed(message) 620 except Exception, e: 621 log.exception(e) 622 return DirectResponse.exception(e, 'Failed to lock devices.')
623 624
625 - def resetIp(self, uids, hashcheck, uid=None, ranges=(), params=None, 626 sort='name', dir='ASC', ip=''):
627 """ 628 Reset IP address(es) of device(s) to the results of a DNS lookup or 629 a manually set address 630 631 @type uids: [string] 632 @param uids: List of device uids with IP's to reset 633 @type hashcheck: string 634 @param hashcheck: Hashcheck for the devices (from getDevices()) 635 @type uid: string 636 @param uid: (optional) Organizer to use when using ranges to get 637 additional uids (default: None) 638 @type ranges: [integer] 639 @param ranges: (optional) List of two integers that are the min/max 640 values of a range of uids to include (default: None) 641 @type params: dictionary 642 @param params: (optional) Key-value pair of filters for this search. 643 Can be one of the following: name, ipAddress, 644 deviceClass, or productionState (default: None) 645 @type sort: string 646 @param sort: (optional) Key on which to sort the return result (default: 647 'name') 648 @type dir: string 649 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 650 (default: 'ASC') 651 @type ip: string 652 @param ip: (optional) IP to set device to. Empty string causes DNS 653 lookup (default: '') 654 @rtype: DirectResponse 655 @return: Success or failure message 656 """ 657 if ranges: 658 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 659 facade = self._getFacade() 660 uids = filterUidsByPermission(self.context.dmd, ZEN_ADMIN_DEVICE, uids) 661 try: 662 for uid in uids: 663 info = facade.getInfo(uid) 664 info.ipAddress = ip # Set to empty causes DNS lookup 665 audit('UI.Device.ResetIP', uid, ip=ip) 666 return DirectResponse('Reset %s IP addresses.' % len(uids)) 667 except Exception, e: 668 log.exception(e) 669 return DirectResponse.exception(e, 'Failed to reset IP addresses.')
670 671 @require('Manage Device')
672 - def resetCommunity(self, uids, hashcheck, uid=None, ranges=(), params=None, 673 sort='name', dir='ASC'):
674 """ 675 Reset SNMP community string(s) on device(s) 676 677 @type uids: [string] 678 @param uids: List of device uids to reset 679 @type hashcheck: string 680 @param hashcheck: Hashcheck for the devices (from getDevices()) 681 @type uid: string 682 @param uid: (optional) Organizer to use when using ranges to get 683 additional uids (default: None) 684 @type ranges: [integer] 685 @param ranges: (optional) List of two integers that are the min/max 686 values of a range of uids to include (default: None) 687 @type params: dictionary 688 @param params: (optional) Key-value pair of filters for this search. 689 Can be one of the following: name, ipAddress, 690 deviceClass, or productionState (default: None) 691 @type sort: string 692 @param sort: (optional) Key on which to sort the return result (default: 693 'name') 694 @type dir: string 695 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 696 (default: 'ASC') 697 @rtype: DirectResponse 698 @return: Success or failure message 699 """ 700 if ranges: 701 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 702 facade = self._getFacade() 703 try: 704 for uid in uids: 705 facade.resetCommunityString(uid) 706 audit('UI.Device.ResetCommunity', uid) 707 return DirectResponse('Reset %s community strings.' % len(uids)) 708 except Exception, e: 709 log.exception(e) 710 return DirectResponse.exception(e, 'Failed to reset community strings.')
711
712 - def setProductionState(self, uids, prodState, hashcheck, uid=None, 713 ranges=(), params=None, sort='name', dir='ASC'):
714 """ 715 Set the production state of device(s). 716 717 @type uids: [string] 718 @param uids: List of device uids to set 719 @type prodState: integer 720 @param prodState: Production state to set device(s) to. 721 @type hashcheck: string 722 @param hashcheck: Hashcheck for the devices (from getDevices()) 723 @type uid: string 724 @param uid: (optional) Organizer to use when using ranges to get 725 additional uids (default: None) 726 @type ranges: [integer] 727 @param ranges: (optional) List of two integers that are the min/max 728 values of a range of uids to include (default: None) 729 @type params: dictionary 730 @param params: (optional) Key-value pair of filters for this search. 731 Can be one of the following: name, ipAddress, 732 deviceClass, or productionState (default: None) 733 @type sort: string 734 @param sort: (optional) Key on which to sort the return result (default: 735 'name') 736 @type dir: string 737 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 738 (default: 'ASC') 739 @rtype: DirectResponse 740 @return: Success or failure message 741 """ 742 if ranges: 743 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 744 facade = self._getFacade() 745 uids = filterUidsByPermission(self.context.dmd, ZEN_CHANGE_DEVICE_PRODSTATE, 746 uids) 747 try: 748 oldStates = {} 749 uids = (uids,) if isinstance(uids, basestring) else uids 750 for uid in uids: 751 device = facade._getObject(uid) 752 if isinstance(device, Device): 753 oldStates[uid] = self.context.convertProdState(device.productionState) 754 755 facade.setProductionState(uids, prodState) 756 prodStateName = self.context.convertProdState(prodState) 757 758 auditData = {'productionState': prodStateName} 759 for uid in uids: 760 oldAuditData = {'productionState': oldStates[uid]} 761 audit('UI.Device.Edit', uid, oldData_=oldAuditData, data_=auditData) 762 return DirectResponse('Set %s devices to %s.' % ( 763 len(uids), prodStateName)) 764 except Exception, e: 765 log.exception(e) 766 return DirectResponse.exception(e, 'Failed to change production state.')
767
768 - def setPriority(self, uids, priority, hashcheck, uid=None, ranges=(), 769 params=None, sort='name', dir='ASC'):
770 """ 771 Set device(s) priority. 772 773 @type uids: [string] 774 @param uids: List of device uids to set 775 @type priority: integer 776 @param priority: Priority to set device(s) to. 777 @type hashcheck: string 778 @param hashcheck: Hashcheck for the devices (from getDevices()) 779 @type uid: string 780 @param uid: (optional) Organizer to use when using ranges to get 781 additional uids (default: None) 782 @type ranges: [integer] 783 @param ranges: (optional) List of two integers that are the min/max 784 values of a range of uids to include (default: None) 785 @type params: dictionary 786 @param params: (optional) Key-value pair of filters for this search. 787 Can be one of the following: name, ipAddress, 788 deviceClass, or productionState (default: None) 789 @type sort: string 790 @param sort: (optional) Key on which to sort the return result (default: 791 'name') 792 @type dir: string 793 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 794 (default: 'ASC') 795 @rtype: DirectResponse 796 @return: Success or failure message 797 """ 798 if ranges: 799 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 800 facade = self._getFacade() 801 uids = filterUidsByPermission(self.context.dmd, ZEN_MANAGE_DEVICE, uids) 802 try: 803 for uid in uids: 804 info = facade.getInfo(uid) 805 oldPriorityLabel = info.priorityLabel 806 info.priority = priority 807 notify(IndexingEvent(info._object)) 808 audit('UI.Device.Edit', uid, 809 priority=info.priorityLabel, 810 oldData_={'priority':oldPriorityLabel}) 811 return DirectResponse('Set %s devices to %s priority.' % ( 812 len(uids), info.priorityLabel)) 813 except Exception, e: 814 log.exception(e) 815 return DirectResponse.exception(e, 'Failed to change priority.')
816
817 - def setCollector(self, uids, collector, hashcheck, uid=None, ranges=(), 818 params=None, sort='name', dir='ASC', moveData=False, 819 asynchronous=True):
820 """ 821 Set device(s) collector. 822 823 @type uids: [string] 824 @param uids: List of device uids to set 825 @type collector: string 826 @param collector: Collector to set devices to 827 @type hashcheck: string 828 @param hashcheck: Hashcheck for the devices (from getDevices()) 829 @type uid: string 830 @param uid: (optional) Organizer to use when using ranges to get 831 additional uids (default: None) 832 @type ranges: [integer] 833 @param ranges: (optional) List of two integers that are the min/max 834 values of a range of uids to include (default: None) 835 @type params: dictionary 836 @param params: (optional) Key-value pair of filters for this search. 837 Can be one of the following: name, ipAddress, 838 deviceClass, or productionState (default: None) 839 @type sort: string 840 @param sort: (optional) Key on which to sort the return result (default: 841 'name') 842 @type dir: string 843 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 844 (default: 'ASC') 845 @rtype: DirectResponse 846 @return: Success or failure message 847 """ 848 if ranges: 849 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 850 facade = self._getFacade() 851 uids = filterUidsByPermission(self.context.dmd, ZEN_ADMIN_DEVICE, uids) 852 try: 853 # iterate through uids so that logging works as expected 854 result = facade.setCollector(uids, collector, moveData, asynchronous) 855 for devUid in uids: 856 audit('UI.Device.ChangeCollector', devUid, collector=collector) 857 if asynchronous and result: 858 return DirectResponse.succeed(new_jobs=Zuul.marshal(result, 859 keys=('uuid', 'description', 'started'))) 860 else: 861 return DirectResponse.succeed('Changed collector to %s for %s devices.' % 862 (collector, len(uids))) 863 except Exception, e: 864 log.exception(e) 865 return DirectResponse.exception(e, 'Failed to change the collector.')
866
867 - def setComponentsMonitored(self, uids, hashcheck, monitor=False, uid=None, 868 ranges=(), meta_type=None, keys=None, 869 start=0, limit=50, sort='name', dir='ASC', 870 name=None):
871 """ 872 Set the monitoring flag for component(s) 873 874 @type uids: [string] 875 @param uids: List of component uids to set 876 @type hashcheck: string 877 @param hashcheck: Hashcheck for the components (from getComponents()) 878 @type monitor: boolean 879 @param monitor: (optional) True to monitor component (default: False) 880 @type uid: string 881 @param uid: (optional) Device to use when using ranges to get 882 additional uids (default: None) 883 @type ranges: [integer] 884 @param ranges: (optional) List of two integers that are the min/max 885 values of a range of uids to include (default: None) 886 @type meta_type: string 887 @param meta_type: (optional) The meta type of the components to retrieve 888 (default: None) 889 @type keys: [string] 890 @param keys: not used 891 @type start: integer 892 @param start: (optional) Offset to return the results from; used in 893 pagination (default: 0) 894 @type limit: integer 895 @param limit: (optional) Number of items to return; used in pagination 896 (default: 50) 897 @type sort: string 898 @param sort: (optional) Key on which to sort the return result (default: 899 'name') 900 @type dir: string 901 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 902 (default: 'ASC') 903 @type name: string 904 @param name: (optional) Component name to search for when loading ranges 905 (default: None) 906 @rtype: DirectResponse 907 @return: Success or failure message 908 """ 909 if ranges: 910 uids += self.loadComponentRanges(ranges, hashcheck, uid, (), 911 meta_type, start, limit, sort, 912 dir, name) 913 facade = self._getFacade() 914 facade.setMonitor(uids, monitor) 915 action = 'SetMonitored' if monitor else 'SetUnmonitored' 916 for uid in uids: 917 audit(['UI.Component', action], uid) 918 return DirectResponse.succeed(('Set monitoring to %s for %s' 919 ' components.') % (monitor, len(uids)))
920
921 - def lockComponents(self, uids, hashcheck, uid=None, ranges=(), 922 updates=False, deletion=False, sendEvent=False, 923 meta_type=None, keys=None, start=0, limit=50, 924 sort='name', dir='ASC', name=None):
925 """ 926 Lock component(s) from changes. 927 928 @type uids: [string] 929 @param uids: List of component uids to lock 930 @type hashcheck: string 931 @param hashcheck: Hashcheck for the components (from getComponents()) 932 @type uid: string 933 @param uid: (optional) Device to use when using ranges to get 934 additional uids (default: None) 935 @type ranges: [integer] 936 @param ranges: (optional) List of two integers that are the min/max 937 values of a range of uids to include (default: None) 938 @type updates: boolean 939 @param updates: (optional) True to lock component from updates (default: False) 940 @type deletion: boolean 941 @param deletion: (optional) True to lock component from deletion 942 (default: False) 943 @type sendEvent: boolean 944 @param sendEvent: (optional) True to send an event when an action is 945 blocked by locking (default: False) 946 @type meta_type: string 947 @param meta_type: (optional) The meta type of the components to retrieve 948 (default: None) 949 @type keys: [string] 950 @param keys: not used 951 @type start: integer 952 @param start: (optional) Offset to return the results from; used in 953 pagination (default: 0) 954 @type limit: integer 955 @param limit: (optional) Number of items to return; used in pagination 956 (default: 50) 957 @type sort: string 958 @param sort: (optional) Key on which to sort the return result (default: 959 'name') 960 @type dir: string 961 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 962 (default: 'ASC') 963 @type name: string 964 @param name: (optional) Component name to search for when loading ranges 965 (default: None) 966 @rtype: DirectResponse 967 @return: Success or failure message 968 """ 969 if ranges: 970 uids += self.loadComponentRanges(ranges, hashcheck, uid, (), 971 meta_type, start, limit, sort, 972 dir, name) 973 facade = self._getFacade() 974 try: 975 facade.setLockState(uids, deletion=deletion, updates=updates, 976 sendEvent=sendEvent) 977 if not deletion and not updates: 978 message = "Unlocked %d components." % len(uids) 979 else: 980 actions = [] 981 if deletion: 982 actions.append('deletion') 983 if updates: 984 actions.append('updates') 985 actions = ' and '.join(actions) 986 message = "Locked %d components from %s." % (len(uids), actions) 987 for uid in uids: 988 audit('UI.Component.EditLocks', uid, 989 deletion=deletion, updates=updates, sendEvents=sendEvent) 990 return DirectResponse.succeed(message) 991 except Exception, e: 992 log.exception(e) 993 return DirectResponse.exception(e, 'Failed to lock components.')
994
995 - def deleteComponents(self, uids, hashcheck, uid=None, ranges=(), 996 meta_type=None, keys=None, start=0, limit=50, 997 sort='name', dir='ASC', name=None):
998 """ 999 Delete device component(s). 1000 1001 @type uids: [string] 1002 @param uids: List of component uids to delete 1003 @type hashcheck: string 1004 @param hashcheck: Hashcheck for the components (from getComponents()) 1005 @type uid: string 1006 @param uid: (optional) Device to use when using ranges to get 1007 additional uids (default: None) 1008 @type ranges: [integer] 1009 @param ranges: (optional) List of two integers that are the min/max 1010 values of a range of uids to include (default: None) 1011 @type meta_type: string 1012 @param meta_type: (optional) The meta type of the components to retrieve 1013 (default: None) 1014 @type keys: [string] 1015 @param keys: not used 1016 @type start: integer 1017 @param start: (optional) Offset to return the results from; used in 1018 pagination (default: 0) 1019 @type limit: integer 1020 @param limit: (optional) Number of items to return; used in pagination 1021 (default: 50) 1022 @type sort: string 1023 @param sort: (optional) Key on which to sort the return result (default: 1024 'name') 1025 @type dir: string 1026 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 1027 (default: 'ASC') 1028 @type name: string 1029 @param name: (optional) Component name to search for when loading ranges 1030 (default: None) 1031 @rtype: DirectResponse 1032 @return: Success or failure message 1033 """ 1034 if ranges: 1035 uids += self.loadComponentRanges(ranges, hashcheck, uid, (), 1036 meta_type, start, limit, sort, 1037 dir, name) 1038 facade = self._getFacade() 1039 try: 1040 facade.deleteComponents(uids) 1041 for uid in uids: 1042 audit('UI.Component.Delete', uid) 1043 return DirectResponse.succeed('Components deleted.') 1044 except Exception, e: 1045 return DirectResponse.exception(e, 'Failed to delete components.')
1046
1047 - def removeDevices(self, uids, hashcheck, action="remove", uid=None, 1048 ranges=(), params=None, sort='name', dir='ASC', 1049 deleteEvents=False, deletePerf=False 1050 ):
1051 """ 1052 Remove/delete device(s). 1053 1054 @type uids: [string] 1055 @param uids: List of device uids to remove 1056 @type hashcheck: string 1057 @param hashcheck: Hashcheck for the devices (from getDevices()) 1058 @type action: string 1059 @param action: Action to take. 'remove' to remove devices from organizer 1060 uid, and 'delete' to delete the device from Zenoss. 1061 @type uid: string 1062 @param uid: (optional) Organizer to use when using ranges to get 1063 additional uids and/or to remove device (default: None) 1064 @type ranges: [integer] 1065 @param ranges: (optional) List of two integers that are the min/max 1066 values of a range of uids to include (default: None) 1067 @type params: dictionary 1068 @param params: (optional) Key-value pair of filters for this search. 1069 Can be one of the following: name, ipAddress, 1070 deviceClass, or productionState (default: None) 1071 @type sort: string 1072 @param sort: (optional) Key on which to sort the return result (default: 1073 'name') 1074 @type dir: string 1075 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 1076 (default: 'ASC') 1077 @type deleteEvents: bool 1078 @param deleteEvents: will remove all the events for the devices as well 1079 @type deletePerf: bool 1080 @param deletePerf: will remove all the perf data for the devices 1081 @rtype: DirectResponse 1082 @return: B{Properties}: 1083 - devtree: ([dictionary]) Object representing the new device tree 1084 - grptree: ([dictionary]) Object representing the new group tree 1085 - systree: ([dictionary]) Object representing the new system tree 1086 - loctree: ([dictionary]) Object representing the new location tree 1087 """ 1088 if ranges: 1089 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 1090 facade = self._getFacade() 1091 removedUids = tuple() 1092 uids = filterUidsByPermission(self.context.dmd, ZEN_DELETE_DEVICE, uids) 1093 try: 1094 if action == "remove": 1095 removed = facade.removeDevices(uids, organizer=uid) 1096 1097 # uid could be an object or string. 1098 organizer = facade._getObject(uid) if isinstance(uid, basestring) else uid 1099 organizerType = organizer.meta_type 1100 action = 'RemoveFrom' + organizerType # Ex: RemoveFromLocation 1101 removedUids = map(lambda x: x.uid, removed) 1102 for devuid in removedUids: 1103 # Ex: ('UI.Device.RemoveFromLocation', deviceUid, location=...) 1104 audit('UI.Device.%s' % action, devuid, data_={organizerType:uid}) 1105 notRemovedUids = list(set(uids) - set(removedUids)) 1106 return DirectResponse.succeed( 1107 removedUids=removedUids, 1108 notRemovedUids=notRemovedUids) 1109 elif action == "delete": 1110 for devuid in uids: 1111 audit('UI.Device.Delete', devuid, 1112 deleteEvents=deleteEvents, 1113 deletePerf=deletePerf) 1114 facade.deleteDevices(uids, 1115 deleteEvents=deleteEvents, 1116 deletePerf=deletePerf) 1117 return DirectResponse.succeed() 1118 except Exception, e: 1119 log.exception(e) 1120 return DirectResponse.exception(e, 'Failed to remove devices.')
1121 1122 @serviceConnectionError
1123 - def getGraphDefs(self, uid, drange=None):
1124 """ 1125 Returns the url and title for each graph 1126 for the object passed in. 1127 @type uid: string 1128 @param uid: unique identifier of an object 1129 """ 1130 facade = self._getFacade() 1131 data = facade.getGraphDefs(uid, drange) 1132 return DirectResponse(data=Zuul.marshal(data))
1133 1134 @serviceConnectionError 1135 @contextRequire(ZEN_ZPROPERTIES_EDIT, 'uid')
1136 - def setZenProperty(self, uid, zProperty, value):
1137 """ 1138 Sets the zProperty value 1139 """ 1140 facade = self._getFacade() 1141 1142 # get old value for auditing 1143 oldProperty = facade.getZenProperty(uid, zProperty) 1144 oldValue = oldProperty['value'] if 'value' in oldProperty else '' 1145 1146 # change it 1147 facade.setZenProperty(uid, zProperty, value) 1148 data = facade.getZenProperty(uid, zProperty) 1149 1150 # audit example: ('UI.zProperty.Edit, 'zPassword', maskFields_='value', 1151 # data_={'Device': '/zport/...'}, value='abracadabra') #gets masked 1152 value = str(value) if not value else value # show 'False', '0', etc. 1153 oldValue = str(oldValue) if not oldValue else oldValue # must match 1154 obj = facade._getObject(uid) 1155 maskFields = 'value' if obj.zenPropIsPassword(zProperty) else None 1156 audit('UI.zProperty.Edit', zProperty, maskFields_=maskFields, 1157 data_={obj.meta_type: uid, 'value': value}, 1158 oldData_={'value': oldValue}) 1159 return DirectResponse(data=Zuul.marshal(data))
1160 1161 @serviceConnectionError
1162 - def getZenProperties(self, uid, start=0, params="{}", limit=None, sort=None, 1163 page=None, dir='ASC'):
1164 """ 1165 Returns the definition and values of all 1166 the zen properties for this context 1167 @type uid: string 1168 @param uid: unique identifier of an object 1169 """ 1170 facade = self._getFacade() 1171 data = facade.getZenProperties(uid, exclusionList=('zCollectorPlugins',)) 1172 # filter 1173 if params: 1174 if isinstance(params, basestring): 1175 filters = unjson(params) 1176 else: 1177 filters = params 1178 def hasFilter(row, key, value): 1179 if row.get(key): 1180 return value.lower() in str(row.get(key)).lower()
1181 1182 for key, value in filters.iteritems(): 1183 # assume AND for sorting 1184 data = [row for row in data if hasFilter(row, key, value)] 1185 # sort 1186 if sort: 1187 reverse = False 1188 if dir != 'ASC': 1189 reverse = True 1190 data = sorted(data, key=lambda row: row[sort], reverse=reverse) 1191 1192 return DirectResponse(data=Zuul.marshal(data), totalCount=len(data))
1193 1194 @serviceConnectionError 1195 @contextRequire(ZEN_ZPROPERTIES_EDIT, 'uid')
1196 - def deleteZenProperty(self, uid, zProperty):
1197 """ 1198 Removes the local instance of the each property in properties. Note 1199 that the property will only be deleted if a hasProperty is true 1200 @type uid: String 1201 @param uid: unique identifier of an object 1202 @type properties: String 1203 @param properties: zenproperty identifier 1204 """ 1205 facade = self._getFacade() 1206 data = facade.deleteZenProperty(uid, zProperty) 1207 obj = facade._getObject(uid) 1208 audit('UI.zProperty.Delete', zProperty, data_={obj.meta_type:uid}) 1209 return DirectResponse(data=Zuul.marshal(data))
1210 1211 @serviceConnectionError
1212 - def getEvents(self, uid):
1213 """ 1214 Get events for a device. 1215 1216 @type uid: [string] 1217 @param uid: Device to get events for 1218 @rtype: DirectResponse 1219 @return: B{Properties}: 1220 - data: ([dictionary]) List of events for a device 1221 """ 1222 facade = self._getFacade() 1223 events = facade.getEvents(uid) 1224 data = Zuul.marshal(events) 1225 return DirectResponse(data=data)
1226
1227 - def loadRanges(self, ranges, hashcheck, uid=None, params=None, 1228 sort='name', dir='ASC'):
1229 """ 1230 Get a range of device uids. 1231 1232 @type ranges: [integer] 1233 @param ranges: List of two integers that are the min/max values of a 1234 range of uids 1235 @type hashcheck: string 1236 @param hashcheck: Hashcheck for the devices (from getDevices()) 1237 @type uid: string 1238 @param uid: (optional) Organizer to use to get uids (default: None) 1239 @type params: dictionary 1240 @param params: (optional) Key-value pair of filters for this search. 1241 Can be one of the following: name, ipAddress, 1242 deviceClass, or productionState (default: None) 1243 @type sort: string 1244 @param sort: (optional) Key on which to sort the return result (default: 1245 'name') 1246 @type dir: string 1247 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 1248 (default: 'ASC') 1249 @rtype: [string] 1250 @return: A list of device uids 1251 """ 1252 facade = self._getFacade() 1253 if isinstance(params, basestring): 1254 params = unjson(params) 1255 devs = facade.getDeviceBrains(uid, limit=None, sort=sort, dir=dir, 1256 params=params, hashcheck=hashcheck) 1257 uids = [] 1258 for start, stop in sorted(ranges): 1259 uids.extend(b.getPath() for b in islice(devs, start, stop + 1)) 1260 return uids
1261
1262 - def loadComponentRanges(self, ranges, hashcheck, uid=None, types=(), 1263 meta_type=(), start=0, limit=None, sort='name', 1264 dir='ASC', name=None):
1265 """ 1266 Get a range of component uids. 1267 1268 @type ranges: [integer] 1269 @param ranges: List of two integers that are the min/max values of a 1270 range of uids 1271 @type hashcheck: string 1272 @param hashcheck: not used 1273 @type uid: string 1274 @param uid: (optional) Device to use to get uids (default: None) 1275 @type types: [string] 1276 @param types: (optional) The types of components to retrieve (default: None) 1277 @type meta_type: string 1278 @param meta_type: (optional) The meta type of the components to retrieve 1279 (default: None) 1280 @type start: integer 1281 @param start: (optional) Offset to return the results from; used in 1282 pagination (default: 0) 1283 @type limit: integer 1284 @param limit: (optional) Number of items to return; used in pagination 1285 (default: None) 1286 @type sort: string 1287 @param sort: (optional) Key on which to sort the return result (default: 1288 'name') 1289 @type dir: string 1290 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 1291 (default: 'ASC') 1292 @type name: string 1293 @param name: (optional) Component name to search for when loading ranges 1294 (default: None) 1295 @rtype: [string] 1296 @return: A list of component uids 1297 """ 1298 facade = self._getFacade() 1299 comps = facade.getComponents(uid, types, meta_type, start, limit, sort, 1300 dir, name) 1301 uids = [] 1302 for start, stop in sorted(ranges): 1303 uids.extend(b.uid for b in islice(comps, start, stop)) 1304 return uids
1305 1306 @serviceConnectionError
1307 - def getUserCommands(self, uid):
1308 """ 1309 Get a list of user commands for a device uid. 1310 1311 @type uid: string 1312 @param uid: Device to use to get user commands 1313 @rtype: [dictionary] 1314 @return: List of objects representing user commands 1315 """ 1316 facade = self._getFacade() 1317 cmds = facade.getUserCommands(uid) 1318 return Zuul.marshal(cmds, ['id', 'description'])
1319
1320 - def getProductionStates(self, **kwargs):
1321 """ 1322 Get a list of available production states. 1323 1324 @rtype: [dictionary] 1325 @return: List of name/value pairs of available production states 1326 """ 1327 return DirectResponse(data=[dict(name=s.split(':')[0], 1328 value=int(s.split(':')[1])) for s in 1329 self.context.dmd.prodStateConversions])
1330
1331 - def getPriorities(self, **kwargs):
1332 """ 1333 Get a list of available device priorities. 1334 1335 @rtype: [dictionary] 1336 @return: List of name/value pairs of available device priorities 1337 """ 1338 return DirectResponse(data=[dict(name=s.split(':')[0], 1339 value=int(s.split(':')[1])) for s in 1340 self.context.dmd.priorityConversions])
1341
1342 - def getCollectors(self):
1343 """ 1344 Get a list of available collectors. 1345 1346 @rtype: [string] 1347 @return: List of collectors 1348 """ 1349 return self.context.dmd.Monitors.getPerformanceMonitorNames()
1350
1351 - def getDeviceClasses(self, **data):
1352 """ 1353 Get a list of all device classes. 1354 1355 @rtype: DirectResponse 1356 @return: B{Properties}: 1357 - deviceClasses: ([dictionary]) List of device classes 1358 - totalCount: (integer) Total number of device classes 1359 """ 1360 devices = self.context.dmd.Devices 1361 deviceClasses = devices.getOrganizerNames(addblank=True) 1362 result = [{'name': name} for name in deviceClasses] 1363 return DirectResponse(deviceClasses=result, totalCount=len(result))
1364
1365 - def getSystems(self, **data):
1366 """ 1367 Get a list of all systems. 1368 1369 @rtype: DirectResponse 1370 @return: B{Properties}: 1371 - systems: ([dictionary]) List of systems 1372 - totalCount: (integer) Total number of systems 1373 """ 1374 systems = self.context.dmd.Systems.getOrganizerNames() 1375 result = [{'name': name} for name in systems if name != '/'] 1376 return DirectResponse(systems=result, totalCount=len(result))
1377
1378 - def getGroups(self, **data):
1379 """ 1380 Get a list of all groups. 1381 1382 @rtype: DirectResponse 1383 @return: B{Properties}: 1384 - systems: ([dictionary]) List of groups 1385 - totalCount: (integer) Total number of groups 1386 """ 1387 groups = self.context.dmd.Groups.getOrganizerNames() 1388 result = [{'name': name} for name in groups if name != '/'] 1389 return DirectResponse(groups=result, totalCount=len(result))
1390
1391 - def getLocations(self, **data):
1392 """ 1393 Get a list of all locations. 1394 1395 @rtype: DirectResponse 1396 @return: B{Properties}: 1397 - systems: ([dictionary]) List of locations 1398 - totalCount: (integer) Total number of locations 1399 """ 1400 locations = self.context.dmd.Locations.getOrganizerNames() 1401 result = [{'name': name} for name in locations if name != '/'] 1402 return DirectResponse(locations=result, totalCount=len(result))
1403
1404 - def getManufacturerNames(self, **data):
1405 """ 1406 Get a list of all manufacturer names. 1407 1408 @rtype: DirectResponse 1409 @return: B{Properties}: 1410 - manufacturers: ([dictionary]) List of manufacturer names 1411 - totalCount: (integer) Total number of manufacturer names 1412 """ 1413 names = self.context.dmd.Manufacturers.getManufacturerNames() 1414 result = [{'name': name} for name in names] 1415 return DirectResponse(manufacturers=result, totalCount=len(result))
1416
1417 - def getHardwareProductNames(self, manufacturer='', **data):
1418 """ 1419 Get a list of all hardware product names from a manufacturer. 1420 1421 @type manufacturer: string 1422 @param manufacturer: Manufacturer name 1423 @rtype: DirectResponse 1424 @return: B{Properties}: 1425 - productNames: ([dictionary]) List of hardware product names 1426 - totalCount: (integer) Total number of hardware product names 1427 """ 1428 manufacturers = self.context.dmd.Manufacturers 1429 names = manufacturers.getProductNames(manufacturer, 'HardwareClass') 1430 result = [{'name': name} for name in names] 1431 return DirectResponse(productNames=result, totalCount=len(result))
1432
1433 - def getOSProductNames(self, manufacturer='', **data):
1434 """ 1435 Get a list of all OS product names from a manufacturer. 1436 1437 @type manufacturer: string 1438 @param manufacturer: Manufacturer name 1439 @rtype: DirectResponse 1440 @return: B{Properties}: 1441 - productNames: ([dictionary]) List of OS product names 1442 - totalCount: (integer) Total number of OS product names 1443 """ 1444 manufacturers = self.context.dmd.Manufacturers 1445 names = manufacturers.getProductNames(manufacturer, 'OS') 1446 result = [{'name': name} for name in names] 1447 return DirectResponse(productNames=result, totalCount=len(result))
1448
1449 - def addDevice(self, deviceName, deviceClass, title=None, 1450 snmpCommunity="", snmpPort=161, manageIp="", 1451 model=False, collector='localhost', rackSlot=0, 1452 locationPath="", systemPaths=[], groupPaths=[], 1453 productionState=1000, comments="", hwManufacturer="", 1454 hwProductName="", osManufacturer="", osProductName="", 1455 priority=3, tag="", serialNumber="", zProperties={}):
1456 """ 1457 Add a device. 1458 1459 @type deviceName: string 1460 @param deviceName: Name or IP of the new device 1461 @type deviceClass: string 1462 @param deviceClass: The device class to add new device to 1463 @type title: string 1464 @param title: (optional) The title of the new device (default: '') 1465 @type snmpCommunity: string 1466 @param snmpCommunity: (optional) A specific community string to use for 1467 this device. (default: '') 1468 @type snmpPort: integer 1469 @param snmpPort: (optional) SNMP port on new device (default: 161) 1470 @type manageIp: string 1471 @param manageIp: (optional) Management IP address on new device (default: 1472 empty/derive from DNS) 1473 @type locationPath: string 1474 @param locationPath: (optional) Organizer path of the location for this device 1475 @type systemPaths: List (strings) 1476 @param systemPaths: (optional) List of organizer paths for the device 1477 @type groupPaths: List (strings) 1478 @param groupPaths: (optional) List of organizer paths for the device 1479 @type model: boolean 1480 @param model: (optional) True to model device at add time (default: False) 1481 @type collector: string 1482 @param collector: (optional) Collector to use for new device (default: 1483 localhost) 1484 @type rackSlot: string 1485 @param rackSlot: (optional) Rack slot description (default: '') 1486 @type productionState: integer 1487 @param productionState: (optional) Production state of the new device 1488 (default: 1000) 1489 @type comments: string 1490 @param comments: (optional) Comments on this device (default: '') 1491 @type hwManufacturer: string 1492 @param hwManufacturer: (optional) Hardware manufacturer name (default: '') 1493 @type hwProductName: string 1494 @param hwProductName: (optional) Hardware product name (default: '') 1495 @type osManufacturer: string 1496 @param osManufacturer: (optional) OS manufacturer name (default: '') 1497 @type osProductName: string 1498 @param osProductName: (optional) OS product name (default: '') 1499 @type priority: integer 1500 @param priority: (optional) Priority of this device (default: 3) 1501 @type tag: string 1502 @param tag: (optional) Tag number of this device (default: '') 1503 @type serialNumber: string 1504 @param serialNumber: (optional) Serial number of this device (default: '') 1505 @rtype: DirectResponse 1506 @return: B{Properties}: 1507 - jobId: (string) ID of the add device job 1508 """ 1509 # check for permission in the device organizer to which we are 1510 # adding the device 1511 facade = self._getFacade() 1512 organizerUid = '/zport/dmd/Devices' + deviceClass 1513 organizer = facade._getObject(organizerUid) 1514 if not Zuul.checkPermission("Manage Device", organizer): 1515 raise Unauthorized('Calling AddDevice requires ' + 1516 'Manage Device permission on %s' % deviceClass) 1517 1518 if title is None: 1519 title = deviceName 1520 1521 # the device name is used as part of the URL, so any unicode characters 1522 # will be stripped before saving. Pre-empt this and make the device name 1523 # safe prior to the uniqueness check. 1524 safeDeviceName = organizer.prepId(deviceName) 1525 1526 device = facade.getDeviceByIpAddress(safeDeviceName, collector, manageIp) 1527 if device: 1528 return DirectResponse.fail(deviceUid=device.getPrimaryId(), 1529 msg="Device %s already exists. <a href='%s'>Go to the device</a>" % (deviceName, device.getPrimaryId())) 1530 1531 if isinstance(systemPaths, basestring): 1532 systemPaths = [systemPaths] 1533 if isinstance(groupPaths, basestring): 1534 groupPaths = [groupPaths] 1535 1536 jobrecord = self._getFacade().addDevice(deviceName, 1537 deviceClass, 1538 title, 1539 snmpCommunity, 1540 snmpPort, 1541 manageIp, 1542 model, 1543 collector, 1544 rackSlot, 1545 productionState, 1546 comments, 1547 hwManufacturer, 1548 hwProductName, 1549 osManufacturer, 1550 osProductName, 1551 priority, 1552 tag, 1553 serialNumber, 1554 locationPath, 1555 systemPaths, 1556 groupPaths, 1557 zProperties 1558 ) 1559 1560 deviceUid = '/'.join([organizerUid, 'devices', deviceName]) 1561 # Zero groups or systems sends as [''] so exclude that case. 1562 hasGroups = len(groupPaths) > 1 or (groupPaths and groupPaths[0]) 1563 hasSystems = len(systemPaths) > 1 or (systemPaths and systemPaths[0]) 1564 auditData = { 1565 'deviceClass': '/Devices' + deviceClass, 1566 'location': '/Locations' + locationPath if locationPath else None, 1567 'deviceGroups': ['/Groups' + x for x in groupPaths] if hasGroups else None, 1568 'systems': ['/Systems' + x for x in systemPaths] if hasSystems else None, 1569 'device_name': title if title else deviceName, # see Trac #30109 1570 'collector': collector, 1571 'model': str(model) # show value even if False 1572 } 1573 audit('UI.Device.Add', deviceUid, data_=auditData) 1574 return DirectResponse.succeed(new_jobs=Zuul.marshal([jobrecord], keys=('uuid', 'description')))
1575 1576 @require('Manage Device')
1577 - def remodel(self, deviceUid):
1578 """ 1579 Submit a job to have a device remodeled. 1580 1581 @type deviceUid: string 1582 @param deviceUid: Device uid to have local template 1583 @rtype: DirectResponse 1584 @return: B{Properties}: 1585 - jobId: (string) ID of the add device job 1586 """ 1587 jobStatus = self._getFacade().remodel(deviceUid) 1588 audit('UI.Device.Remodel', deviceUid) 1589 return DirectResponse.succeed(jobId=jobStatus.id)
1590 1591 @require('Edit Local Templates')
1592 - def addLocalTemplate(self, deviceUid, templateId):
1593 """ 1594 Adds a local template on a device. 1595 1596 @type deviceUid: string 1597 @param deviceUid: Device uid to have local template 1598 @type templateId: string 1599 @param templateId: Name of the new template 1600 @rtype: DirectResponse 1601 @return: Success message 1602 """ 1603 facade = self._getFacade() 1604 facade.addLocalTemplate(deviceUid, templateId) 1605 audit('UI.Device.AddLocalTemplate', deviceUid, template=templateId) 1606 return DirectResponse.succeed()
1607 1608 @require('Edit Local Templates')
1609 - def removeLocalTemplate(self, deviceUid, templateUid):
1610 """ 1611 Removes a locally defined template on a device. 1612 1613 @type deviceUid: string 1614 @param deviceUid: Device uid that has local template 1615 @type templateUid: string 1616 @param templateUid: Name of the template to remove 1617 @rtype: DirectResponse 1618 @return: Success message 1619 """ 1620 facade = self._getFacade() 1621 facade.removeLocalTemplate(deviceUid, templateUid) 1622 audit('UI.Device.RemoveLocalTemplate', deviceUid, template=templateUid) 1623 return DirectResponse.succeed()
1624
1625 - def getLocalTemplates(self, query, uid):
1626 """ 1627 Get a list of locally defined templates on a device. 1628 1629 @type query: string 1630 @param query: not used 1631 @type uid: string 1632 @param uid: Device uid to query for templates 1633 @rtype: DirectResponse 1634 @return: B{Properties}: 1635 - data: ([dictionary]) List of objects representing local templates 1636 """ 1637 facade = self._getFacade() 1638 templates = facade.getLocalTemplates(uid) 1639 data = [] 1640 for template in templates: 1641 data.append(dict(label=template['text'], uid=template['uid'])) 1642 return DirectResponse.succeed(data=data)
1643 1644 @serviceConnectionError
1645 - def getTemplates(self, id):
1646 """ 1647 Get a list of available templates for a device. 1648 1649 @type id: string 1650 @param id: Device uid to query for templates 1651 @rtype: DirectResponse 1652 @return: B{Properties}: 1653 - data: ([dictionary]) List of objects representing templates 1654 """ 1655 facade = self._getFacade() 1656 templates = facade.getTemplates(id) 1657 return Zuul.marshal(templates)
1658 1659 @serviceConnectionError
1660 - def getUnboundTemplates(self, uid):
1661 """ 1662 Get a list of unbound templates for a device. 1663 1664 @type uid: string 1665 @param uid: Device uid to query for templates 1666 @rtype: DirectResponse 1667 @return: B{Properties}: 1668 - data: ([dictionary]) List of objects representing templates 1669 """ 1670 facade = self._getFacade() 1671 templates = facade.getUnboundTemplates(uid) 1672 data = [] 1673 for template in templates: 1674 label = '%s (%s)' % (template.titleOrId(), template.getUIPath()) 1675 data.append([template.id, label]) 1676 return DirectResponse.succeed(data=Zuul.marshal(data))
1677 1678 @serviceConnectionError
1679 - def getBoundTemplates(self, uid):
1680 """ 1681 Get a list of bound templates for a device. 1682 1683 @type uid: string 1684 @param uid: Device uid to query for templates 1685 @rtype: DirectResponse 1686 @return: B{Properties}: 1687 - data: ([dictionary]) List of objects representing templates 1688 """ 1689 facade = self._getFacade() 1690 templates = facade.getBoundTemplates(uid) 1691 data = [] 1692 for template in templates: 1693 label = '%s (%s)' % (template.titleOrId(), template.getUIPath()) 1694 data.append([template.id, label]) 1695 return DirectResponse.succeed(data=Zuul.marshal(data))
1696 1697 @require('Edit Local Templates')
1698 - def setBoundTemplates(self, uid, templateIds):
1699 """ 1700 Set a list of templates as bound to a device. 1701 1702 @type uid: string 1703 @param uid: Device uid to bind templates to 1704 @type templateIds: [string] 1705 @param templateIds: List of template uids to bind to device 1706 @rtype: DirectResponse 1707 @return: Success message 1708 """ 1709 facade = self._getFacade() 1710 facade.setBoundTemplates(uid, templateIds) 1711 audit('UI.Device.BindTemplates', uid, templates=templateIds) 1712 return DirectResponse.succeed()
1713 1714 @require('Edit Local Templates')
1715 - def resetBoundTemplates(self, uid):
1716 """ 1717 Remove all bound templates from a device. 1718 1719 @type uid: string 1720 @param uid: Device uid to remove bound templates from 1721 @rtype: DirectResponse 1722 @return: Success message 1723 """ 1724 facade = self._getFacade() 1725 facade.resetBoundTemplates(uid) 1726 audit('UI.Device.ResetBoundTemplates', uid) 1727 return DirectResponse.succeed()
1728 1729 @require('Edit Local Templates')
1730 - def bindOrUnbindTemplate(self, uid, templateUid):
1731 """ 1732 Bind an unbound template or unbind a bound template from a device. 1733 1734 @type uid: string 1735 @param uid: Device uid to bind/unbind template 1736 @type templateUid: string 1737 @param templateUid: Template uid to bind/unbind 1738 @rtype: DirectResponse 1739 @return: Success message 1740 """ 1741 facade = self._getFacade() 1742 template = facade._getObject(templateUid) 1743 templateIds = [t.id for t in facade.getBoundTemplates(uid)] 1744 # not bound 1745 if not template.id in templateIds: 1746 self.setBoundTemplates(uid, templateIds + [template.id]) 1747 audit('UI.Device.BindTemplate', uid, template=templateUid) 1748 else: 1749 # already bound so unbind it 1750 templateIds = [t for t in templateIds if t != template.id] 1751 self.setBoundTemplates(uid, templateIds) 1752 audit('UI.Device.UnbindTemplate', uid, template=templateUid) 1753 return DirectResponse.succeed()
1754
1755 - def getOverridableTemplates(self, query, uid):
1756 """ 1757 Get a list of available templates on a device that can be overridden. 1758 1759 @type query: string 1760 @param query: not used 1761 @type uid: string 1762 @param uid: Device to query for overridable templates 1763 @rtype: DirectResponse 1764 @return: B{Properties}: 1765 - data: ([dictionary]) List of objects representing templates 1766 """ 1767 facade = self._getFacade() 1768 templates = facade.getOverridableTemplates(uid) 1769 # we just need the text and the id (for our combobox) 1770 data = [] 1771 for template in templates: 1772 label = '%s (%s)' % (template.text, template.getUIPath()) 1773 data.append(dict(label=label, uid=template.uid)) 1774 return DirectResponse.succeed(data=data)
1775 1776 @require('Manage DMD')
1777 - def clearGeocodeCache(self):
1778 """ 1779 Clear the Google Maps geocode cache. 1780 1781 @rtype: DirectResponse 1782 @return: Success message 1783 """ 1784 self.context.clearGeocodeCache() 1785 audit('UI.GeocodeCache.Clear') 1786 return DirectResponse.succeed()
1787 1788 @serviceConnectionError
1789 - def getZenProperty(self, uid, zProperty):
1790 """ 1791 Returns information about a zproperty for a 1792 given context, including its value 1793 @rtype: Dictionary 1794 @return: B{Properties}: 1795 - path: (string) where the property is defined 1796 - type: (string) type of zproperty it is 1797 - options: (Array) available options for the zproperty 1798 - value (Array) value of the zproperty 1799 - valueAsString (string) 1800 """ 1801 facade = self._getFacade() 1802 data = facade.getZenProperty(uid, zProperty) 1803 return DirectResponse.succeed(data=Zuul.marshal(data))
1804 1805 @serviceConnectionError
1806 - def getModelerPluginDocStrings(self, uid):
1807 """ 1808 Given a uid returns the documentation for all the modeler plugins. 1809 """ 1810 facade = self._getFacade() 1811 data = facade.getModelerPluginDocStrings(uid) 1812 return DirectResponse.succeed(data=Zuul.marshal(data))
1813
1814 - def addIpRouteEntry(self, uid, dest='', routemask='', nexthopid='', interface='', 1815 routeproto='', routetype='', userCreated=True):
1816 """ 1817 Adds an Ip Route Entry to this device 1818 """ 1819 facade = self._getFacade() 1820 data = facade.addIpRouteEntry(uid, dest, routemask, nexthopid, interface, 1821 routeproto, routetype, userCreated) 1822 return DirectResponse.succeed(data=Zuul.marshal(data))
1823
1824 - def addIpInterface(self, uid, newId, userCreated=True):
1825 """ 1826 Adds an Ip Interface 1827 """ 1828 facade = self._getFacade() 1829 data = facade.addIpInterface(uid, newId, userCreated) 1830 return DirectResponse.succeed(data=Zuul.marshal(data))
1831
1832 - def addOSProcess(self, uid, newClassName, userCreated=True):
1833 """ 1834 Adds an os processes 1835 """ 1836 facade = self._getFacade() 1837 data = facade.addOSProcess(uid, newClassName, userCreated) 1838 return DirectResponse.succeed(data=Zuul.marshal(data))
1839
1840 - def addFileSystem(self, uid, newId, userCreated=True):
1841 """ 1842 Adds an Ip Interface 1843 """ 1844 facade = self._getFacade() 1845 data = facade.addFileSystem(uid, newId, userCreated) 1846 return DirectResponse.succeed(data=Zuul.marshal(data))
1847
1848 - def addIpService(self, uid, newClassName, protocol, userCreated=True):
1849 """ 1850 Adds an Ip Service 1851 """ 1852 facade = self._getFacade() 1853 data = facade.addIpService(uid, newClassName, protocol, userCreated) 1854 return DirectResponse.succeed(data=Zuul.marshal(data))
1855 1856
1857 - def addWinService(self, uid, newClassName, userCreated=True):
1858 """ 1859 Adds an Ip Service 1860 """ 1861 facade = self._getFacade() 1862 data = facade.addWinService(uid, newClassName, userCreated) 1863 return DirectResponse.succeed(data=Zuul.marshal(data))
1864