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 cgi import escape 
  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_DELETE_DEVICE 
  27  from Products.Zuul import filterUidsByPermission 
  28  from Products.Zuul.routers import TreeRouter 
  29  from Products.Zuul.exceptions import DatapointNameConfict 
  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, IGUIDManager 
  34  from Products.ZenMessaging.audit import audit 
  35  from zope.event import notify 
  36   
  37  log = logging.getLogger('zen.Zuul') 
38 39 -class DeviceRouter(TreeRouter):
40 """ 41 A JSON/ExtDirect interface to operations on devices 42 """ 43 44 @serviceConnectionError 45 @contextRequire("Manage DMD", 'contextUid')
46 - def addDeviceClassNode(self, type, contextUid, id, description=None, connectionInfo=None):
47 """ 48 Adds a new device class organizer specified by the parameter id to 49 the parent organizer specified by contextUid. 50 51 contextUid must be a path to a DeviceClass. 52 53 @type type: string 54 @param type: Node type (always 'organizer' in this case) 55 @type contextUid: string 56 @param contextUid: Path to the location organizer that will 57 be the new node's parent (ex. /zport/dmd/Devices/) 58 @type id: string 59 @param id: The identifier of the new node 60 @type description: string 61 @param description: (optional) Describes the new device class 62 @type connectionInfo: list 63 @param connectionInfo: (optional) List of zproperties that constitute credentials for this device classs 64 @rtype: dictionary 65 @return: B{Properties}: 66 - success: (bool) Success of node creation 67 - nodeConfig: (dictionary) The new device class's properties 68 """ 69 facade = self._getFacade() 70 organizer = facade.addDeviceClass(contextUid, 71 id, 72 description, 73 connectionInfo) 74 uid = organizer.uid 75 76 treeNode = facade.getTree(uid) 77 audit('UI.DeviceClass.Add', uid, description=description, connectionInfo=connectionInfo) 78 return DirectResponse.succeed("Device Class Added", nodeConfig=Zuul.marshal(treeNode))
79 80 81 @serviceConnectionError 82 @contextRequire("Manage DMD", 'contextUid')
83 - def addLocationNode(self, type, contextUid, id, 84 description=None, address=None):
85 """ 86 Adds a new location organizer specified by the parameter id to 87 the parent organizer specified by contextUid. 88 89 contextUid must be a path to a Location. 90 91 @type type: string 92 @param type: Node type (always 'organizer' in this case) 93 @type contextUid: string 94 @param contextUid: Path to the location organizer that will 95 be the new node's parent (ex. /zport/dmd/Devices/Locations) 96 @type id: string 97 @param id: The identifier of the new node 98 @type description: string 99 @param description: (optional) Describes the new location 100 @type address: string 101 @param address: (optional) Physical address of the new location 102 @rtype: dictionary 103 @return: B{Properties}: 104 - success: (bool) Success of node creation 105 - nodeConfig: (dictionary) The new location's properties 106 """ 107 facade = self._getFacade() 108 organizer = facade.addLocationOrganizer(contextUid, 109 id, 110 description, 111 address) 112 uid = organizer.uid 113 114 treeNode = facade.getTree(uid) 115 audit('UI.Location.Add', uid, description=description, address=address) 116 return DirectResponse.succeed("Location added", nodeConfig=Zuul.marshal(treeNode))
117
118 - def _getFacade(self):
119 return Zuul.getFacade('device', self.context)
120 121 @serviceConnectionError
122 - def getTree(self, id):
123 """ 124 Returns the tree structure of an organizer hierarchy where 125 the root node is the organizer identified by the id parameter. 126 127 @type id: string 128 @param id: Id of the root node of the tree to be returned 129 @rtype: [dictionary] 130 @return: Object representing the tree 131 """ 132 facade = self._getFacade() 133 tree = facade.getTree(id) 134 data = Zuul.marshal(tree) 135 return [data]
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, name=name, keys=keys) 181 total = comps.total 182 hash = comps.hash_ 183 184 data = Zuul.marshal(comps, keys=keys) 185 return DirectResponse(data=data, totalCount=total, 186 hash=hash)
187
188 - def getComponentTree(self, uid=None, id=None, sorting_dict=None):
189 """ 190 Retrieves all of the components set up to be used in a 191 tree. 192 193 @type uid: string 194 @param uid: Unique identifier of the root of the tree to retrieve 195 @type id: string 196 @param id: not used 197 @rtype: [dictionary] 198 @return: Component properties in tree form 199 """ 200 if id: 201 uid = id 202 facade = self._getFacade() 203 data = facade.getComponentTree(uid) 204 sevs = [c[0].lower() for c in 205 self.context.ZenEventManager.severityConversions] 206 data.sort(cmp=lambda a, b: cmp(sevs.index(a['severity']), 207 sevs.index(b['severity']))) 208 result = [] 209 for datum in data: 210 result.append(dict( 211 id=datum['type'], 212 path='Components/%s' % datum['type'], 213 text={ 214 'text': datum['type'], 215 'count': datum['count'], 216 'description': 'components'}, 217 iconCls='tree-severity-icon-small-' + datum['severity'], 218 leaf=True)) 219 if sorting_dict: 220 sorting_keys_list = [key for key in sorting_dict.iterkeys()] 221 def cmp_items(first, second): 222 # Resolving keys from a dictionary of given names convention 223 x = str(first['text']['text']) 224 y = str(second['text']['text']) 225 if x in sorting_keys_list: 226 x = sorting_dict[x][0] 227 if y in sorting_keys_list: 228 y = sorting_dict[y][0] 229 if x < y: 230 return -1 231 elif x > y: 232 return 1 233 else: 234 return 0
235 result.sort(cmp=cmp_items) 236 return result
237
238 - def findComponentIndex(self, componentUid, uid=None, meta_type=None, 239 sort='name', dir='ASC', name=None, **kwargs):
240 """ 241 Given a component uid and the component search criteria, this retrieves 242 the position of the component in the results. 243 244 @type componentUid: string 245 @param componentUid: Unique identifier of the component whose index 246 to return 247 @type uid: string 248 @param uid: Unique identifier of the device queried for components 249 @type meta_type: string 250 @param meta_type: (optional) The meta type of the components to retrieve 251 (default: None) 252 @type sort: string 253 @param sort: (optional) Key on which to sort the return results (default: 254 'name') 255 @type dir: string 256 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 257 (default: 'ASC') 258 @type name: regex 259 @param name: (optional) Used to filter the results (default: None) 260 @rtype: DirectResponse 261 @return: B{Properties}: 262 - index: (integer) Index of the component 263 """ 264 facade = self._getFacade() 265 i = facade.findComponentIndex(componentUid, uid, 266 meta_type, sort, dir, name) 267 return DirectResponse(index=i)
268 269 @serviceConnectionError
270 - def getForm(self, uid):
271 """ 272 Given an object identifier, this returns all of the editable fields 273 on that object as well as their ExtJs xtype that one would 274 use on a client side form. 275 276 @type uid: string 277 @param uid: Unique identifier of an object 278 @rtype: DirectResponse 279 @return: B{Properties} 280 - form: (dictionary) form fields for the object 281 """ 282 info = self._getFacade().getInfo(uid) 283 form = IFormBuilder(info).render(fieldsets=False) 284 form = Zuul.marshal(form) 285 return DirectResponse(form=form)
286 287 @serviceConnectionError
288 - def getInfo(self, uid, keys=None):
289 """ 290 Get the properties of a device or device organizer 291 292 @type uid: string 293 @param uid: Unique identifier of an object 294 @type keys: list 295 @param keys: (optional) List of keys to include in the returned 296 dictionary. If None then all keys will be returned 297 (default: None) 298 @rtype: DirectResponse 299 @return: B{Properties} 300 - data: (dictionary) Object properties 301 - disabled: (bool) If current user doesn't have permission to use setInfo 302 """ 303 facade = self._getFacade() 304 process = facade.getInfo(uid) 305 data = Zuul.marshal(process, keys) 306 disabled = not Zuul.checkPermission('Manage DMD', self.context) 307 return DirectResponse(data=data, disabled=disabled)
308 309 @serviceConnectionError
310 - def setInfo(self, **data):
311 """ 312 Set attributes on a device or device organizer. 313 This method accepts any keyword argument for the property that you wish 314 to set. The only required property is "uid". 315 316 @type uid: string 317 @keyword uid: Unique identifier of an object 318 @rtype: DirectResponse 319 """ 320 facade = self._getFacade() 321 if not (Zuul.checkPermission(ZEN_MANAGE_DEVICE, self.context) or ( 322 Zuul.checkPermission(ZEN_CHANGE_DEVICE_PRODSTATE, 323 self.context) and 'productionState' in data.keys())): 324 raise Exception('You do not have permission to save changes.') 325 the_uid = data['uid'] # gets deleted 326 process = facade.getInfo(the_uid) 327 oldData = self._getInfoData(process, data.keys()) 328 Zuul.unmarshal(data, process) 329 newData = self._getInfoData(process, data.keys()) 330 # reindex the object if necessary 331 if hasattr(process._object, 'index_object'): 332 process._object.index_object() 333 334 # Ex: ('UI.Device.Edit', uid, data_={'productionState': 'High'}) 335 # Ex: ('UI.Location.Edit', uid, description='Blah', old_description='Foo') 336 if 'name' in oldData: 337 oldData['device_name'] = oldData['name'] # we call it this now 338 del oldData['name'] 339 if 'name' in newData: 340 del newData['name'] # it gets printed automatically 341 if isinstance(process._object, Device): 342 # ZEN-2837, ZEN-247: Audit names instead of numbers 343 dmd = self.context 344 if 'productionState' in oldData: 345 oldData['productionState'] = dmd.convertProdState(oldData['productionState']) 346 if 'productionState' in newData: 347 newData['productionState'] = dmd.convertProdState(newData['productionState']) 348 if 'priority' in oldData: 349 oldData['priority'] = dmd.convertPriority(oldData['priority']) 350 if 'priority' in newData: 351 newData['priority'] = dmd.convertPriority(newData['priority']) 352 audit(['UI', getDisplayType(process._object), 'Edit'], the_uid, 353 data_=newData, oldData_=oldData, skipFields_='uid') 354 return DirectResponse.succeed()
355
356 - def _getInfoData(self, info, keys):
357 # TODO: generalize this code for all object types, if possible. 358 values = {} 359 for key in keys: 360 val = getattr(info, key, None) 361 if val is not None: 362 values[key] = str(val) # unmutable copy 363 return values
364 365 @require('Manage Device')
366 - def setProductInfo(self, uid, **data):
367 """ 368 Sets the ProductInfo on a device. This method has the following valid 369 keyword arguments: 370 371 @type uid: string 372 @keyword uid: Unique identifier of a device 373 @type hwManufacturer: string 374 @keyword hwManufacturer: Hardware manufacturer 375 @type hwProductName: string 376 @keyword hwProductName: Hardware product name 377 @type osManufacturer: string 378 @keyword osManufacturer: Operating system manufacturer 379 @type osProductName: string 380 @keyword osProductName: Operating system product name 381 @rtype: DirectResponse 382 """ 383 facade = self._getFacade() 384 facade.setProductInfo(uid, **data) 385 audit('UI.Device.Edit', uid, data_=data) 386 return DirectResponse()
387
388 - def getDeviceUuidsByName(self, query="", start=0, limit=25, page=1, uuid=None):
389 """ 390 Retrieves a list of device uuids. For use in combos. 391 If uuid is set, ensures that it is included in the returned list. 392 """ 393 facade = self._getFacade() 394 devices = facade.getDevices(params={'name':query}) # TODO: pass start=start, limit=limit 395 result = [{'name':escape(dev.name), 396 'uuid':IGlobalIdentifier(dev._object).getGUID()} 397 for dev in devices] 398 399 if uuid and uuid not in (device['uuid'] for device in result): 400 guidManager = IGUIDManager(self.context.dmd) 401 device = guidManager.getObject(uuid) 402 if device: 403 result.append({'name':escape(device.name()), 'uuid':uuid}) 404 405 return DirectResponse.succeed(data=result)
406
407 - def getDeviceUids(self, uid):
408 """ 409 Return a list of device uids underneath an organizer. This includes 410 all the devices belonging to an child organizers. 411 412 @type uid: string 413 @param uid: Unique identifier of the organizer to get devices from 414 @rtype: DirectResponse 415 @return: B{Properties}: 416 - devices: (list) device uids 417 """ 418 facade = self._getFacade() 419 uids = facade.getDeviceUids(uid) 420 return DirectResponse.succeed(devices=uids)
421 422 @serviceConnectionError
423 - def getDevices(self, uid=None, start=0, params=None, limit=50, sort='name', 424 page=None, 425 dir='ASC', keys=None):
426 """ 427 Retrieves a list of devices. This method supports pagination. 428 429 @type uid: string 430 @param uid: Unique identifier of the organizer to get devices from 431 @type start: integer 432 @param start: (optional) Offset to return the results from; used in 433 pagination (default: 0) 434 @type params: dictionary 435 @param params: (optional) Key-value pair of filters for this search. 436 Can be one of the following: name, ipAddress, 437 deviceClass, or productionState (default: None) 438 @type limit: integer 439 @param limit: (optional) Number of items to return; used in pagination 440 (default: 50) 441 @type sort: string 442 @param sort: (optional) Key on which to sort the return results (default: 443 'name') 444 @type dir: string 445 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 446 (default: 'ASC') 447 @rtype: DirectResponse 448 @return: B{Properties}: 449 - devices: (list) Dictionaries of device properties 450 - totalCount: (integer) Number of devices returned 451 - hash: (string) Hashcheck of the current device state (to check 452 whether devices have changed since last query) 453 """ 454 facade = self._getFacade() 455 if isinstance(params, basestring): 456 params = unjson(params) 457 458 devices = facade.getDevices(uid, start, limit, sort, dir, params) 459 allKeys = ['name', 'ipAddress', 'productionState', 'events', 460 'ipAddressString', 'serialNumber', 'hwManufacturer', 461 'hwModel', 'osModel', 'osManufacturer', 'collector', 462 'priority', 'systems', 'groups', 'location', 463 'pythonClass', 'tagNumber'] 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.getProductionState()) 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 moveCollectorDevices(self, srcCollectors, dstCollector, hashcheck, uid=None, ranges=(), 853 params=None, sort='name', dir='ASC', moveData=False, 854 asynchronous=True):
855 """ 856 Move all devices under one or more collectors to another collector 857 858 The signature is exactly the same as setCollector(), except that the 859 'uids' parameter is replaced with 'srcCollectors' 860 861 @type srcCollectors: list of strings 862 @param srcCollectors: The collectors to move all devices from 863 """ 864 monitorFacade = Zuul.getFacade('monitors', self.context) 865 if isinstance(srcCollectors, basestring): 866 srcCollectorObjs = monitorFacade.get(srcCollectors) 867 else: 868 srcCollectorObjs = [] 869 for collector in srcCollectors: 870 srcCollectorObjs.append(monitorFacade.get(collector)) 871 deviceUids = [] 872 for collector in srcCollectorObjs: 873 deviceUids.extend([ dev.getPrimaryId() for dev in collector.getDevices() ]) 874 return self.setCollector(deviceUids, dstCollector, hashcheck, uid, ranges, 875 params, sort, dir, moveData, asynchronous)
876
877 - def setCollector(self, uids, collector, hashcheck, uid=None, ranges=(), 878 params=None, sort='name', dir='ASC', moveData=False, 879 asynchronous=True):
880 """ 881 Set device(s) collector. 882 883 @type uids: [string] 884 @param uids: List of device uids to set 885 @type collector: string 886 @param collector: Collector to set devices to 887 @type hashcheck: string 888 @param hashcheck: Hashcheck for the devices (from getDevices()) 889 @type uid: string 890 @param uid: (optional) Organizer to use when using ranges to get 891 additional uids (default: None) 892 @type ranges: [integer] 893 @param ranges: (optional) List of two integers that are the min/max 894 values of a range of uids to include (default: None) 895 @type params: dictionary 896 @param params: (optional) Key-value pair of filters for this search. 897 Can be one of the following: name, ipAddress, 898 deviceClass, or productionState (default: None) 899 @type sort: string 900 @param sort: (optional) Key on which to sort the return result (default: 901 'name') 902 @type dir: string 903 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 904 (default: 'ASC') 905 @rtype: DirectResponse 906 @return: Success or failure message 907 """ 908 if ranges: 909 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 910 facade = self._getFacade() 911 uids = filterUidsByPermission(self.context.dmd, ZEN_ADMIN_DEVICE, uids) 912 try: 913 # iterate through uids so that logging works as expected 914 result = facade.setCollector(uids, collector, asynchronous) 915 for devUid in uids: 916 audit('UI.Device.ChangeCollector', devUid, collector=collector) 917 if asynchronous and result: 918 return DirectResponse.succeed(new_jobs=Zuul.marshal(result, 919 keys=('uuid', 'description', 'started'))) 920 else: 921 return DirectResponse.succeed('Changed collector to %s for %s devices.' % 922 (collector, len(uids))) 923 except Exception, e: 924 log.exception(e) 925 return DirectResponse.exception(e, 'Failed to change the collector.')
926
927 - def setComponentsMonitored(self, uids, hashcheck, monitor=False, uid=None, 928 ranges=(), meta_type=None, keys=None, 929 start=0, limit=50, sort='name', dir='ASC', 930 name=None):
931 """ 932 Set the monitoring flag for component(s) 933 934 @type uids: [string] 935 @param uids: List of component uids to set 936 @type hashcheck: string 937 @param hashcheck: Hashcheck for the components (from getComponents()) 938 @type monitor: boolean 939 @param monitor: (optional) True to monitor component (default: False) 940 @type uid: string 941 @param uid: (optional) Device to use when using ranges to get 942 additional uids (default: None) 943 @type ranges: [integer] 944 @param ranges: (optional) List of two integers that are the min/max 945 values of a range of uids to include (default: None) 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 facade.setMonitor(uids, monitor) 975 action = 'SetMonitored' if monitor else 'SetUnmonitored' 976 for uid in uids: 977 audit(['UI.Component', action], uid) 978 return DirectResponse.succeed(('Set monitoring to %s for %s' 979 ' components.') % (monitor, len(uids)))
980
981 - def lockComponents(self, uids, hashcheck, uid=None, ranges=(), 982 updates=False, deletion=False, sendEvent=False, 983 meta_type=None, keys=None, start=0, limit=50, 984 sort='name', dir='ASC', name=None):
985 """ 986 Lock component(s) from changes. 987 988 @type uids: [string] 989 @param uids: List of component uids to lock 990 @type hashcheck: string 991 @param hashcheck: Hashcheck for the components (from getComponents()) 992 @type uid: string 993 @param uid: (optional) Device to use when using ranges to get 994 additional uids (default: None) 995 @type ranges: [integer] 996 @param ranges: (optional) List of two integers that are the min/max 997 values of a range of uids to include (default: None) 998 @type updates: boolean 999 @param updates: (optional) True to lock component from updates (default: False) 1000 @type deletion: boolean 1001 @param deletion: (optional) True to lock component from deletion 1002 (default: False) 1003 @type sendEvent: boolean 1004 @param sendEvent: (optional) True to send an event when an action is 1005 blocked by locking (default: False) 1006 @type meta_type: string 1007 @param meta_type: (optional) The meta type of the components to retrieve 1008 (default: None) 1009 @type keys: [string] 1010 @param keys: not used 1011 @type start: integer 1012 @param start: (optional) Offset to return the results from; used in 1013 pagination (default: 0) 1014 @type limit: integer 1015 @param limit: (optional) Number of items to return; used in pagination 1016 (default: 50) 1017 @type sort: string 1018 @param sort: (optional) Key on which to sort the return result (default: 1019 'name') 1020 @type dir: string 1021 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 1022 (default: 'ASC') 1023 @type name: string 1024 @param name: (optional) Component name to search for when loading ranges 1025 (default: None) 1026 @rtype: DirectResponse 1027 @return: Success or failure message 1028 """ 1029 if ranges: 1030 uids += self.loadComponentRanges(ranges, hashcheck, uid, (), 1031 meta_type, start, limit, sort, 1032 dir, name) 1033 facade = self._getFacade() 1034 try: 1035 facade.setLockState(uids, deletion=deletion, updates=updates, 1036 sendEvent=sendEvent) 1037 if not deletion and not updates: 1038 message = "Unlocked %d components." % len(uids) 1039 else: 1040 actions = [] 1041 if deletion: 1042 actions.append('deletion') 1043 if updates: 1044 actions.append('updates') 1045 actions = ' and '.join(actions) 1046 message = "Locked %d components from %s." % (len(uids), actions) 1047 for uid in uids: 1048 audit('UI.Component.EditLocks', uid, 1049 deletion=deletion, updates=updates, sendEvents=sendEvent) 1050 return DirectResponse.succeed(message) 1051 except Exception, e: 1052 log.exception(e) 1053 return DirectResponse.exception(e, 'Failed to lock components.')
1054
1055 - def deleteComponents(self, uids, hashcheck, uid=None, ranges=(), 1056 meta_type=None, keys=None, start=0, limit=50, 1057 sort='name', dir='ASC', name=None):
1058 """ 1059 Delete device component(s). 1060 1061 @type uids: [string] 1062 @param uids: List of component uids to delete 1063 @type hashcheck: string 1064 @param hashcheck: Hashcheck for the components (from getComponents()) 1065 @type uid: string 1066 @param uid: (optional) Device to use when using ranges to get 1067 additional uids (default: None) 1068 @type ranges: [integer] 1069 @param ranges: (optional) List of two integers that are the min/max 1070 values of a range of uids to include (default: None) 1071 @type meta_type: string 1072 @param meta_type: (optional) The meta type of the components to retrieve 1073 (default: None) 1074 @type keys: [string] 1075 @param keys: not used 1076 @type start: integer 1077 @param start: (optional) Offset to return the results from; used in 1078 pagination (default: 0) 1079 @type limit: integer 1080 @param limit: (optional) Number of items to return; used in pagination 1081 (default: 50) 1082 @type sort: string 1083 @param sort: (optional) Key on which to sort the return result (default: 1084 'name') 1085 @type dir: string 1086 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 1087 (default: 'ASC') 1088 @type name: string 1089 @param name: (optional) Component name to search for when loading ranges 1090 (default: None) 1091 @rtype: DirectResponse 1092 @return: Success or failure message 1093 """ 1094 if ranges: 1095 uids += self.loadComponentRanges(ranges, hashcheck, uid, (), 1096 meta_type, start, limit, sort, 1097 dir, name) 1098 facade = self._getFacade() 1099 try: 1100 facade.deleteComponents(uids) 1101 for uid in uids: 1102 audit('UI.Component.Delete', uid) 1103 return DirectResponse.succeed('Components deleted.') 1104 except Exception, e: 1105 log.exception(e) 1106 return DirectResponse.exception(e, 'Failed to delete components.')
1107
1108 - def removeDevices(self, uids, hashcheck, action="remove", uid=None, 1109 ranges=(), params=None, sort='name', dir='ASC', 1110 deleteEvents=False, deletePerf=False 1111 ):
1112 """ 1113 Remove/delete device(s). 1114 1115 @type uids: [string] 1116 @param uids: List of device uids to remove 1117 @type hashcheck: string 1118 @param hashcheck: Hashcheck for the devices (from getDevices()) 1119 @type action: string 1120 @param action: Action to take. 'remove' to remove devices from organizer 1121 uid, and 'delete' to delete the device from Zenoss. 1122 @type uid: string 1123 @param uid: (optional) Organizer to use when using ranges to get 1124 additional uids and/or to remove device (default: None) 1125 @type ranges: [integer] 1126 @param ranges: (optional) List of two integers that are the min/max 1127 values of a range of uids to include (default: None) 1128 @type params: dictionary 1129 @param params: (optional) Key-value pair of filters for this search. 1130 Can be one of the following: name, ipAddress, 1131 deviceClass, or productionState (default: None) 1132 @type sort: string 1133 @param sort: (optional) Key on which to sort the return result (default: 1134 'name') 1135 @type dir: string 1136 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 1137 (default: 'ASC') 1138 @type deleteEvents: bool 1139 @param deleteEvents: will remove all the events for the devices as well 1140 @type deletePerf: bool 1141 @param deletePerf: will remove all the perf data for the devices 1142 @rtype: DirectResponse 1143 @return: B{Properties}: 1144 - devtree: ([dictionary]) Object representing the new device tree 1145 - grptree: ([dictionary]) Object representing the new group tree 1146 - systree: ([dictionary]) Object representing the new system tree 1147 - loctree: ([dictionary]) Object representing the new location tree 1148 """ 1149 if ranges: 1150 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir) 1151 facade = self._getFacade() 1152 removedUids = tuple() 1153 uids = filterUidsByPermission(self.context.dmd, ZEN_DELETE_DEVICE, uids) 1154 try: 1155 if action == "remove": 1156 removed = facade.removeDevices(uids, organizer=uid) 1157 1158 # uid could be an object or string. 1159 organizer = facade._getObject(uid) if isinstance(uid, basestring) else uid 1160 organizerType = organizer.meta_type 1161 action = 'RemoveFrom' + organizerType # Ex: RemoveFromLocation 1162 removedUids = map(lambda x: x.uid, removed) 1163 for devuid in removedUids: 1164 # Ex: ('UI.Device.RemoveFromLocation', deviceUid, location=...) 1165 audit('UI.Device.%s' % action, devuid, data_={organizerType:uid}) 1166 notRemovedUids = list(set(uids) - set(removedUids)) 1167 return DirectResponse.succeed( 1168 removedUids=removedUids, 1169 notRemovedUids=notRemovedUids) 1170 elif action == "delete": 1171 for devuid in uids: 1172 audit('UI.Device.Delete', devuid, 1173 deleteEvents=deleteEvents, 1174 deletePerf=deletePerf) 1175 facade.deleteDevices(uids, 1176 deleteEvents=deleteEvents, 1177 deletePerf=deletePerf) 1178 return DirectResponse.succeed() 1179 except Exception, e: 1180 log.exception(e) 1181 return DirectResponse.exception(e, 'Failed to remove devices.')
1182 1183 @serviceConnectionError
1184 - def getGraphDefs(self, uid, drange=None):
1185 """ 1186 Returns the url and title for each graph 1187 for the object passed in. 1188 @type uid: string 1189 @param uid: unique identifier of an object 1190 """ 1191 facade = self._getFacade() 1192 data = facade.getGraphDefs(uid, drange) 1193 return DirectResponse(data=Zuul.marshal(data))
1194
1195 - def loadRanges(self, ranges, hashcheck, uid=None, params=None, 1196 sort='name', dir='ASC'):
1197 """ 1198 Get a range of device uids. 1199 1200 @type ranges: [integer] 1201 @param ranges: List of two integers that are the min/max values of a 1202 range of uids 1203 @type hashcheck: string 1204 @param hashcheck: Hashcheck for the devices (from getDevices()) 1205 @type uid: string 1206 @param uid: (optional) Organizer to use to get uids (default: None) 1207 @type params: dictionary 1208 @param params: (optional) Key-value pair of filters for this search. 1209 Can be one of the following: name, ipAddress, 1210 deviceClass, or productionState (default: None) 1211 @type sort: string 1212 @param sort: (optional) Key on which to sort the return result (default: 1213 'name') 1214 @type dir: string 1215 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 1216 (default: 'ASC') 1217 @rtype: [string] 1218 @return: A list of device uids 1219 """ 1220 facade = self._getFacade() 1221 if isinstance(params, basestring): 1222 params = unjson(params) 1223 devs = facade.getDeviceBrains(uid, limit=None, sort=sort, dir=dir, 1224 params=params, hashcheck=hashcheck) 1225 uids = [] 1226 for start, stop in sorted(ranges): 1227 uids.extend(b.getPath() for b in islice(devs, start, stop + 1)) 1228 return uids
1229
1230 - def loadComponentRanges(self, ranges, hashcheck, uid=None, types=(), 1231 meta_type=(), start=0, limit=None, sort='name', 1232 dir='ASC', name=None):
1233 """ 1234 Get a range of component uids. 1235 1236 @type ranges: [integer] 1237 @param ranges: List of two integers that are the min/max values of a 1238 range of uids 1239 @type hashcheck: string 1240 @param hashcheck: not used 1241 @type uid: string 1242 @param uid: (optional) Device to use to get uids (default: None) 1243 @type types: [string] 1244 @param types: (optional) The types of components to retrieve (default: None) 1245 @type meta_type: string 1246 @param meta_type: (optional) The meta type of the components to retrieve 1247 (default: None) 1248 @type start: integer 1249 @param start: (optional) Offset to return the results from; used in 1250 pagination (default: 0) 1251 @type limit: integer 1252 @param limit: (optional) Number of items to return; used in pagination 1253 (default: None) 1254 @type sort: string 1255 @param sort: (optional) Key on which to sort the return result (default: 1256 'name') 1257 @type dir: string 1258 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC' 1259 (default: 'ASC') 1260 @type name: string 1261 @param name: (optional) Component name to search for when loading ranges 1262 (default: None) 1263 @rtype: [string] 1264 @return: A list of component uids 1265 """ 1266 if uid is None: 1267 uid = "/".join(self.context.getPhysicalPath()) 1268 facade = self._getFacade() 1269 comps = facade.getComponents(uid, types, meta_type, start, limit, sort, 1270 dir, name) 1271 uids = [] 1272 for start, stop in sorted(ranges): 1273 uids.extend(b.uid for b in islice(comps, start, stop)) 1274 return uids
1275 1276 @serviceConnectionError
1277 - def getUserCommands(self, uid):
1278 """ 1279 Get a list of user commands for a device uid. 1280 1281 @type uid: string 1282 @param uid: Device to use to get user commands 1283 @rtype: [dictionary] 1284 @return: List of objects representing user commands 1285 """ 1286 facade = self._getFacade() 1287 cmds = facade.getUserCommands(uid) 1288 return Zuul.marshal(cmds, ['id', 'description'])
1289
1290 - def getProductionStates(self, **kwargs):
1291 """ 1292 Get a list of available production states. 1293 1294 @rtype: [dictionary] 1295 @return: List of name/value pairs of available production states 1296 """ 1297 return DirectResponse(data=[dict(name=s.split(':')[0], 1298 value=int(s.split(':')[1])) for s in 1299 self.context.dmd.prodStateConversions])
1300
1301 - def getPriorities(self, **kwargs):
1302 """ 1303 Get a list of available device priorities. 1304 1305 @rtype: [dictionary] 1306 @return: List of name/value pairs of available device priorities 1307 """ 1308 return DirectResponse(data=[dict(name=s.split(':')[0], 1309 value=int(s.split(':')[1])) for s in 1310 self.context.dmd.priorityConversions])
1311
1312 - def getCollectors(self):
1313 """ 1314 Get a list of available collectors. 1315 1316 @rtype: [string] 1317 @return: List of collectors 1318 """ 1319 return self.context.dmd.Monitors.getPerformanceMonitorNames()
1320
1321 - def getDeviceClasses(self, **data):
1322 """ 1323 Get a list of all device classes. 1324 1325 @rtype: DirectResponse 1326 @return: B{Properties}: 1327 - deviceClasses: ([dictionary]) List of device classes 1328 - totalCount: (integer) Total number of device classes 1329 """ 1330 devices = self.context.dmd.Devices 1331 deviceClasses = devices.getOrganizerNames(addblank=True) 1332 result = [{'name': name} for name in deviceClasses] 1333 return DirectResponse(deviceClasses=result, totalCount=len(result))
1334
1335 - def getSystems(self, **data):
1336 """ 1337 Get a list of all systems. 1338 1339 @rtype: DirectResponse 1340 @return: B{Properties}: 1341 - systems: ([dictionary]) List of systems 1342 - totalCount: (integer) Total number of systems 1343 """ 1344 systems = self.context.dmd.Systems.getOrganizerNames() 1345 result = [{'name': name} for name in systems if name != '/'] 1346 return DirectResponse(systems=result, totalCount=len(result))
1347
1348 - def getGroups(self, **data):
1349 """ 1350 Get a list of all groups. 1351 1352 @rtype: DirectResponse 1353 @return: B{Properties}: 1354 - systems: ([dictionary]) List of groups 1355 - totalCount: (integer) Total number of groups 1356 """ 1357 groups = self.context.dmd.Groups.getOrganizerNames() 1358 result = [{'name': name} for name in groups if name != '/'] 1359 return DirectResponse(groups=result, totalCount=len(result))
1360
1361 - def getLocations(self, **data):
1362 """ 1363 Get a list of all locations. 1364 1365 @rtype: DirectResponse 1366 @return: B{Properties}: 1367 - systems: ([dictionary]) List of locations 1368 - totalCount: (integer) Total number of locations 1369 """ 1370 locations = self.context.dmd.Locations.getOrganizerNames() 1371 result = [{'name': name} for name in locations if name != '/'] 1372 return DirectResponse(locations=result, totalCount=len(result))
1373
1374 - def getManufacturerNames(self, **data):
1375 """ 1376 Get a list of all manufacturer names. 1377 1378 @rtype: DirectResponse 1379 @return: B{Properties}: 1380 - manufacturers: ([dictionary]) List of manufacturer names 1381 - totalCount: (integer) Total number of manufacturer names 1382 """ 1383 names = self.context.dmd.Manufacturers.getManufacturerNames() 1384 result = [{'name': name} for name in names] 1385 return DirectResponse(manufacturers=result, totalCount=len(result))
1386
1387 - def getHardwareProductNames(self, manufacturer='', **data):
1388 """ 1389 Get a list of all hardware product names from a manufacturer. 1390 1391 @type manufacturer: string 1392 @param manufacturer: Manufacturer name 1393 @rtype: DirectResponse 1394 @return: B{Properties}: 1395 - productNames: ([dictionary]) List of hardware product names 1396 - totalCount: (integer) Total number of hardware product names 1397 """ 1398 manufacturers = self.context.dmd.Manufacturers 1399 names = manufacturers.getProductNames(manufacturer, 'HardwareClass') 1400 result = [{'name': name} for name in names] 1401 return DirectResponse(productNames=result, totalCount=len(result))
1402
1403 - def getOSProductNames(self, manufacturer='', **data):
1404 """ 1405 Get a list of all OS product names from a manufacturer. 1406 1407 @type manufacturer: string 1408 @param manufacturer: Manufacturer name 1409 @rtype: DirectResponse 1410 @return: B{Properties}: 1411 - productNames: ([dictionary]) List of OS product names 1412 - totalCount: (integer) Total number of OS product names 1413 """ 1414 manufacturers = self.context.dmd.Manufacturers 1415 names = manufacturers.getProductNames(manufacturer, 'OS') 1416 result = [{'name': name} for name in names] 1417 return DirectResponse(productNames=result, totalCount=len(result))
1418
1419 - def addDevice(self, deviceName, deviceClass, title=None, 1420 snmpCommunity="", snmpPort=161, manageIp="", 1421 model=False, collector='localhost', rackSlot=0, 1422 locationPath="", systemPaths=[], groupPaths=[], 1423 productionState=1000, comments="", hwManufacturer="", 1424 hwProductName="", osManufacturer="", osProductName="", 1425 priority=3, tag="", serialNumber="", zCommandUsername="", 1426 zCommandPassword="", zWinUser="", zWinPassword="", 1427 zProperties={}, cProperties={},):
1428 1429 """ 1430 Add a device. 1431 1432 @type deviceName: string 1433 @param deviceName: Name or IP of the new device 1434 @type deviceClass: string 1435 @param deviceClass: The device class to add new device to 1436 @type title: string 1437 @param title: (optional) The title of the new device (default: '') 1438 @type snmpCommunity: string 1439 @param snmpCommunity: (optional) A specific community string to use for 1440 this device. (default: '') 1441 @type snmpPort: integer 1442 @param snmpPort: (optional) SNMP port on new device (default: 161) 1443 @type manageIp: string 1444 @param manageIp: (optional) Management IP address on new device (default: 1445 empty/derive from DNS) 1446 @type locationPath: string 1447 @param locationPath: (optional) Organizer path of the location for this device 1448 @type systemPaths: List (strings) 1449 @param systemPaths: (optional) List of organizer paths for the device 1450 @type groupPaths: List (strings) 1451 @param groupPaths: (optional) List of organizer paths for the device 1452 @type model: boolean 1453 @param model: (optional) True to model device at add time (default: False) 1454 @type collector: string 1455 @param collector: (optional) Collector to use for new device (default: 1456 localhost) 1457 @type rackSlot: string 1458 @param rackSlot: (optional) Rack slot description (default: '') 1459 @type productionState: integer 1460 @param productionState: (optional) Production state of the new device 1461 (default: 1000) 1462 @type comments: string 1463 @param comments: (optional) Comments on this device (default: '') 1464 @type hwManufacturer: string 1465 @param hwManufacturer: (optional) Hardware manufacturer name (default: '') 1466 @type hwProductName: string 1467 @param hwProductName: (optional) Hardware product name (default: '') 1468 @type osManufacturer: string 1469 @param osManufacturer: (optional) OS manufacturer name (default: '') 1470 @type osProductName: string 1471 @param osProductName: (optional) OS product name (default: '') 1472 @type priority: integer 1473 @param priority: (optional) Priority of this device (default: 3) 1474 @type tag: string 1475 @param tag: (optional) Tag number of this device (default: '') 1476 @type serialNumber: string 1477 @param serialNumber: (optional) Serial number of this device (default: '') 1478 @type zCommandUsername: string 1479 @param zWinUser: (optional) Username for WMI (default: '') 1480 @type zCommandPassword: string 1481 @param zWinPassword: (optional) Password for WMI (default: '') 1482 @rtype: DirectResponse 1483 @return: B{Properties}: 1484 - jobId: (string) ID of the add device job 1485 """ 1486 # check for permission in the device organizer to which we are 1487 # adding the device 1488 facade = self._getFacade() 1489 organizerUid = '/zport/dmd/Devices' + deviceClass 1490 organizer = facade._getObject(organizerUid) 1491 if not Zuul.checkPermission("Manage Device", organizer): 1492 raise Unauthorized('Calling AddDevice requires ' + 1493 'Manage Device permission on %s' % deviceClass) 1494 1495 if title is None: 1496 title = deviceName 1497 1498 # the device name is used as part of the URL, so any unicode characters 1499 # will be stripped before saving. Pre-empt this and make the device name 1500 # safe prior to the uniqueness check. 1501 safeDeviceName = organizer.prepId(deviceName) 1502 1503 device = facade.getDeviceByIpAddress(safeDeviceName, collector, manageIp) 1504 if device: 1505 return DirectResponse.fail(deviceUid=device.getPrimaryId(), 1506 msg="Device %s already exists. <a href='%s'>Go to the device</a>" % (deviceName, device.getPrimaryId())) 1507 1508 if isinstance(systemPaths, basestring): 1509 systemPaths = [systemPaths] 1510 if isinstance(groupPaths, basestring): 1511 groupPaths = [groupPaths] 1512 1513 jobrecords = self._getFacade().addDevice(deviceName, 1514 deviceClass, 1515 title, 1516 snmpCommunity, 1517 snmpPort, 1518 manageIp, 1519 model, 1520 collector, 1521 rackSlot, 1522 productionState, 1523 comments, 1524 hwManufacturer, 1525 hwProductName, 1526 osManufacturer, 1527 osProductName, 1528 priority, 1529 tag, 1530 serialNumber, 1531 locationPath, 1532 zCommandUsername, 1533 zCommandPassword, 1534 zWinUser, 1535 zWinPassword, 1536 systemPaths, 1537 groupPaths, 1538 zProperties, 1539 cProperties, 1540 ) 1541 1542 deviceUid = '/'.join([organizerUid, 'devices', deviceName]) 1543 # Zero groups or systems sends as [''] so exclude that case. 1544 hasGroups = len(groupPaths) > 1 or (groupPaths and groupPaths[0]) 1545 hasSystems = len(systemPaths) > 1 or (systemPaths and systemPaths[0]) 1546 auditData = { 1547 'deviceClass': '/Devices' + deviceClass, 1548 'location': '/Locations' + locationPath if locationPath else None, 1549 'deviceGroups': ['/Groups' + x for x in groupPaths] if hasGroups else None, 1550 'systems': ['/Systems' + x for x in systemPaths] if hasSystems else None, 1551 'device_name': title if title else deviceName, # see Trac #30109 1552 'collector': collector, 1553 'model': str(model), # show value even if False 1554 'productionState': self.context.convertProdState(productionState), 1555 'priority': self.context.convertPriority(priority), 1556 } 1557 audit('UI.Device.Add', deviceUid, data_=auditData) 1558 return DirectResponse.succeed(new_jobs=Zuul.marshal(jobrecords, keys=('uuid', 'description')))
1559 1560 @require('Manage Device')
1561 - def remodel(self, deviceUid):
1562 """ 1563 Submit a job to have a device remodeled. 1564 1565 @type deviceUid: string 1566 @param deviceUid: Device uid to have local template 1567 @rtype: DirectResponse 1568 @return: B{Properties}: 1569 - jobId: (string) ID of the add device job 1570 """ 1571 jobStatus = self._getFacade().remodel(deviceUid) 1572 audit('UI.Device.Remodel', deviceUid) 1573 return DirectResponse.succeed(jobId=jobStatus.id)
1574 1575 @require('Edit Local Templates')
1576 - def addLocalTemplate(self, deviceUid, templateId):
1577 """ 1578 Adds a local template on a device. 1579 1580 @type deviceUid: string 1581 @param deviceUid: Device uid to have local template 1582 @type templateId: string 1583 @param templateId: Name of the new template 1584 @rtype: DirectResponse 1585 @return: Success message 1586 """ 1587 facade = self._getFacade() 1588 facade.addLocalTemplate(deviceUid, templateId) 1589 audit('UI.Device.AddLocalTemplate', deviceUid, template=templateId) 1590 return DirectResponse.succeed()
1591 1592 @require('Edit Local Templates')
1593 - def removeLocalTemplate(self, deviceUid, templateUid):
1594 """ 1595 Removes a locally defined template on a device. 1596 1597 @type deviceUid: string 1598 @param deviceUid: Device uid that has local template 1599 @type templateUid: string 1600 @param templateUid: Name of the template to remove 1601 @rtype: DirectResponse 1602 @return: Success message 1603 """ 1604 facade = self._getFacade() 1605 facade.removeLocalTemplate(deviceUid, templateUid) 1606 audit('UI.Device.RemoveLocalTemplate', deviceUid, template=templateUid) 1607 return DirectResponse.succeed()
1608
1609 - def getLocalTemplates(self, query, uid):
1610 """ 1611 Get a list of locally defined templates on a device. 1612 1613 @type query: string 1614 @param query: not used 1615 @type uid: string 1616 @param uid: Device uid to query for templates 1617 @rtype: DirectResponse 1618 @return: B{Properties}: 1619 - data: ([dictionary]) List of objects representing local templates 1620 """ 1621 facade = self._getFacade() 1622 templates = facade.getLocalTemplates(uid) 1623 data = [] 1624 for template in templates: 1625 data.append(dict(label=template['text'], uid=template['uid'])) 1626 return DirectResponse.succeed(data=data)
1627 1628 @serviceConnectionError
1629 - def getTemplates(self, id):
1630 """ 1631 Get a list of available templates for a device. 1632 1633 @type id: string 1634 @param id: Device uid to query for templates 1635 @rtype: DirectResponse 1636 @return: B{Properties}: 1637 - data: ([dictionary]) List of objects representing templates 1638 """ 1639 facade = self._getFacade() 1640 templates = facade.getTemplates(id) 1641 return Zuul.marshal(templates)
1642 1643 @serviceConnectionError
1644 - def getUnboundTemplates(self, uid):
1645 """ 1646 Get a list of unbound templates for a device. 1647 1648 @type uid: string 1649 @param uid: Device uid to query for templates 1650 @rtype: DirectResponse 1651 @return: B{Properties}: 1652 - data: ([dictionary]) List of objects representing templates 1653 """ 1654 facade = self._getFacade() 1655 templates = facade.getUnboundTemplates(uid) 1656 data = [] 1657 for template in templates: 1658 label = '%s (%s)' % (template.titleOrId(), template.getUIPath()) 1659 data.append([template.id, label]) 1660 return DirectResponse.succeed(data=Zuul.marshal(data))
1661 1662 @serviceConnectionError
1663 - def getBoundTemplates(self, uid):
1664 """ 1665 Get a list of bound templates for a device. 1666 1667 @type uid: string 1668 @param uid: Device uid to query for templates 1669 @rtype: DirectResponse 1670 @return: B{Properties}: 1671 - data: ([dictionary]) List of objects representing templates 1672 """ 1673 facade = self._getFacade() 1674 templates = facade.getBoundTemplates(uid) 1675 data = [] 1676 for template in templates: 1677 label = '%s (%s)' % (template.titleOrId(), template.getUIPath()) 1678 data.append([template.id, label]) 1679 return DirectResponse.succeed(data=Zuul.marshal(data))
1680 1681 @require('Edit Local Templates')
1682 - def setBoundTemplates(self, uid, templateIds):
1683 """ 1684 Set a list of templates as bound to a device. 1685 1686 @type uid: string 1687 @param uid: Device uid to bind templates to 1688 @type templateIds: [string] 1689 @param templateIds: List of template uids to bind to device 1690 @rtype: DirectResponse 1691 @return: Success message 1692 """ 1693 facade = self._getFacade() 1694 try: 1695 facade.setBoundTemplates(uid, templateIds) 1696 except DatapointNameConfict, e: 1697 log.info("Failed to bind templates for {}: {}".format(uid, e)) 1698 return DirectResponse.exception(e, 'Failed to bind templates.') 1699 audit('UI.Device.BindTemplates', uid, templates=templateIds) 1700 return DirectResponse.succeed()
1701 1702 @require('Edit Local Templates')
1703 - def resetBoundTemplates(self, uid):
1704 """ 1705 Remove all bound templates from a device. 1706 1707 @type uid: string 1708 @param uid: Device uid to remove bound templates from 1709 @rtype: DirectResponse 1710 @return: Success message 1711 """ 1712 facade = self._getFacade() 1713 facade.resetBoundTemplates(uid) 1714 audit('UI.Device.ResetBoundTemplates', uid) 1715 return DirectResponse.succeed()
1716 1717 @require('Edit Local Templates')
1718 - def bindOrUnbindTemplate(self, uid, templateUid):
1719 """ 1720 Bind an unbound template or unbind a bound template from a device. 1721 1722 @type uid: string 1723 @param uid: Device uid to bind/unbind template 1724 @type templateUid: string 1725 @param templateUid: Template uid to bind/unbind 1726 @rtype: DirectResponse 1727 @return: Success message 1728 """ 1729 facade = self._getFacade() 1730 template = facade._getObject(templateUid) 1731 templateIds = [t.id for t in facade.getBoundTemplates(uid)] 1732 # not bound 1733 if not template.id in templateIds: 1734 self.setBoundTemplates(uid, templateIds + [template.id]) 1735 audit('UI.Device.BindTemplate', uid, template=templateUid) 1736 else: 1737 # already bound so unbind it 1738 templateIds = [t for t in templateIds if t != template.id] 1739 self.setBoundTemplates(uid, templateIds) 1740 audit('UI.Device.UnbindTemplate', uid, template=templateUid) 1741 return DirectResponse.succeed()
1742
1743 - def getOverridableTemplates(self, query, uid):
1744 """ 1745 Get a list of available templates on a device that can be overridden. 1746 1747 @type query: string 1748 @param query: not used 1749 @type uid: string 1750 @param uid: Device to query for overridable templates 1751 @rtype: DirectResponse 1752 @return: B{Properties}: 1753 - data: ([dictionary]) List of objects representing templates 1754 """ 1755 facade = self._getFacade() 1756 templates = facade.getOverridableTemplates(uid) 1757 # we just need the text and the id (for our combobox) 1758 data = [] 1759 for template in templates: 1760 label = '%s (%s)' % (template.text, template.getUIPath()) 1761 data.append(dict(label=label, uid=template.uid)) 1762 return DirectResponse.succeed(data=data)
1763 1764 @require('Manage DMD')
1765 - def clearGeocodeCache(self):
1766 """ 1767 Clear the Google Maps geocode cache. 1768 1769 @rtype: DirectResponse 1770 @return: Success message 1771 """ 1772 facade = self._getFacade() 1773 facade.clearGeocodeCache() 1774 audit('UI.GeocodeCache.Clear') 1775 return DirectResponse.succeed()
1776
1777 - def getConnectionInfo(self, uid):
1778 """ 1779 Returns the zproperty information about those zproperties which comprise 1780 the credentials 1781 @rtype: List of Dictionaries 1782 @return: B{Properties}: 1783 - path: (string) where the property is defined 1784 - type: (string) type of zproperty it is 1785 - options: (Array) available options for the zproperty 1786 - value (Array) value of the zproperty 1787 - valueAsString (string) 1788 """ 1789 facade = self._getFacade() 1790 data = facade.getConnectionInfo(uid) 1791 return DirectResponse.succeed(data=Zuul.marshal(data))
1792 1793 @serviceConnectionError
1794 - def getModelerPluginDocStrings(self, uid):
1795 """ 1796 Given a uid returns the documentation for all the modeler plugins. 1797 """ 1798 facade = self._getFacade() 1799 data = facade.getModelerPluginDocStrings(uid) 1800 return DirectResponse.succeed(data=Zuul.marshal(data))
1801
1802 - def addIpRouteEntry(self, uid, dest='', routemask='', nexthopid='', interface='', 1803 routeproto='', routetype='', userCreated=True):
1804 """ 1805 Adds an Ip Route Entry to this device 1806 """ 1807 facade = self._getFacade() 1808 data = facade.addIpRouteEntry(uid, dest, routemask, nexthopid, interface, 1809 routeproto, routetype, userCreated) 1810 return DirectResponse.succeed(data=Zuul.marshal(data))
1811
1812 - def addIpInterface(self, uid, newId, userCreated=True):
1813 """ 1814 Adds an Ip Interface 1815 """ 1816 facade = self._getFacade() 1817 data = facade.addIpInterface(uid, newId, userCreated) 1818 return DirectResponse.succeed(data=Zuul.marshal(data))
1819
1820 - def addOSProcess(self, uid, newClassName, example, userCreated=True):
1821 """ 1822 Adds an os processes 1823 """ 1824 facade = self._getFacade() 1825 data = facade.addOSProcess(uid, newClassName, example, userCreated) 1826 return DirectResponse.succeed(data=Zuul.marshal(data))
1827
1828 - def addFileSystem(self, uid, newId, userCreated=True):
1829 """ 1830 Adds an Ip Interface 1831 """ 1832 facade = self._getFacade() 1833 data = facade.addFileSystem(uid, newId, userCreated) 1834 return DirectResponse.succeed(data=Zuul.marshal(data))
1835
1836 - def addIpService(self, uid, newClassName, protocol, userCreated=True):
1837 """ 1838 Adds an Ip Service 1839 """ 1840 facade = self._getFacade() 1841 data = facade.addIpService(uid, newClassName, protocol, userCreated) 1842 return DirectResponse.succeed(data=Zuul.marshal(data))
1843 1844
1845 - def addWinService(self, uid, newClassName, userCreated=True):
1846 """ 1847 Adds an Ip Service 1848 """ 1849 facade = self._getFacade() 1850 data = facade.addWinService(uid, newClassName, userCreated) 1851 return DirectResponse.succeed(data=Zuul.marshal(data))
1852
1853 - def getSoftware(self, uid, keys=None):
1854 1855 facade = self._getFacade() 1856 software = facade.getSoftware(uid) 1857 return DirectResponse(data=Zuul.marshal(software, keys))
1858
1859 - def getOverriddenObjectsList(self, uid, propname, relName):
1860 """ 1861 returns a list of Overridden Objects and properties for this context 1862 """ 1863 facade = self._getFacade() 1864 data = facade.getOverriddenObjectsList(uid, propname, relName) 1865 return DirectResponse.succeed(data=Zuul.marshal(data))
1866
1867 - def getOverriddenObjectsParent(self, uid, propname=''):
1868 """ 1869 returns the base of the Overridden Objects 1870 """ 1871 facade = self._getFacade() 1872 data = facade.getOverriddenObjectsParent(uid, propname) 1873 return DirectResponse.succeed(data=Zuul.marshal(data))
1874
1875 - def getOverriddenZprops(self, uid, all=True, pfilt=''):
1876 """ 1877 returns a list of zProperty values for the overridden objects 1878 """ 1879 facade = self._getFacade() 1880 data = facade.getOverriddenZprops(uid, all) 1881 return DirectResponse.succeed(data=Zuul.marshal(data))
1882
1883 - def getGraphDefintionsForComponents(self, uid):
1884 facade = self._getFacade() 1885 data = facade.getGraphDefinitionsForComponent(uid) 1886 return DirectResponse.succeed(data=Zuul.marshal(data))
1887
1888 - def getComponentGraphs(self, uid, meta_type, graphId, allOnSame=False):
1889 """ 1890 Returns the graph denoted by graphId for every component in 1891 device (uid) with the meta_type meta_type 1892 """ 1893 facade = self._getFacade() 1894 data = facade.getComponentGraphs(uid, meta_type, graphId, allOnSame=allOnSame) 1895 return DirectResponse.succeed(data=Zuul.marshal(data))
1896
1897 - def getDevTypes(self, uid, filter=None):
1898 """ 1899 Returns a list of devtypes for the wizard 1900 """ 1901 facade = self._getFacade() 1902 data = facade.getDevTypes(uid) 1903 return DirectResponse.succeed(data=Zuul.marshal(data))
1904