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