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