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