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', 'tagNumber',
458 'hwManufacturer', 'hwModel', 'osModel', 'osManufacturer',
459 'collector', 'priority', 'systems', 'groups', 'location',
460 'pythonClass', 'tagNumber', 'serialNumber',
461 'hwModel', 'hwManufacturer',
462 'osModel', 'osManufacturer',
463 'groups', 'systems', 'location']
464 usedKeys = keys or allKeys
465 if not 'uid' in usedKeys:
466 usedKeys.append('uid')
467
468 data = Zuul.marshal(devices.results, usedKeys)
469
470 return DirectResponse(devices=data, totalCount=devices.total,
471 hash=devices.hash_)
472
474 """
475 Set the device specified by the uid,"uid" to have the
476 the id "newId"
477 This will raise an exception if it fails.
478
479 @type uid: string
480 @param uid: The unique id of the device we are renaming
481 @type newId: string
482 @param newId: string of the new id
483 """
484 facade = self._getFacade()
485 newUid = facade.renameDevice(uid, newId)
486 return DirectResponse.succeed(uid=newUid)
487
488 - def moveDevices(self, uids, target, hashcheck=None, ranges=(), uid=None,
489 params=None, sort='name', dir='ASC', asynchronous=True):
490 """
491 Moves the devices specified by uids to the organizer specified by 'target'.
492
493 @type uids: [string]
494 @param uids: List of device uids to move
495 @type target: string
496 @param target: Uid of the organizer to move the devices to
497 @type hashcheck: string
498 @param hashcheck: Hashcheck for the devices (from getDevices())
499 @type ranges: [integer]
500 @param ranges: (optional) List of two integers that are the min/max
501 values of a range of uids to include (default: None)
502 @type uid: string
503 @param uid: (optional) Organizer to use when using ranges to get
504 additional uids (default: None)
505 @type params: dictionary
506 @param params: (optional) Key-value pair of filters for this search.
507 Can be one of the following: name, ipAddress,
508 deviceClass, or productionState (default: None)
509 @type sort: string
510 @param sort: (optional) Key on which to sort the return result (default:
511 'name')
512 @type dir: string
513 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
514 (default: 'ASC')
515 @rtype: DirectResponse
516 @return: B{Properties}:
517 - tree: ([dictionary]) Object representing the new device tree
518 - exports: (integer) Number of devices moved
519 """
520 if ranges:
521 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir)
522 uids = filterUidsByPermission(self.context.dmd, ZEN_MANAGE_DEVICE, uids)
523 facade = self._getFacade()
524
525
526
527
528
529 targetType = getDisplayType(facade._getObject(target))
530 autoRemovalTypes = ('DeviceClass', 'Location')
531 action = ('Change' if targetType in autoRemovalTypes else 'AddTo') + targetType
532 for uid in uids:
533 oldData = {}
534 if targetType == 'Location':
535 location = facade._getObject(uid).location()
536 locationPath = location.getPrimaryId() if location else ''
537 oldData[targetType] = locationPath
538 elif targetType == 'DeviceClass':
539 deviceClass = facade._getObject(uid).deviceClass()
540 deviceClassPath = deviceClass.getPrimaryId() if deviceClass else ''
541 oldData[targetType] = deviceClassPath
542 audit(['UI.Device', action], uid,
543 data_={targetType:target}, oldData_=oldData)
544 try:
545 targetObj = facade._getObject(target)
546 if Zuul.checkPermission(ZEN_ADMIN_DEVICE, targetObj):
547 result = facade.moveDevices(uids, target, asynchronous=asynchronous)
548 else:
549 return DirectResponse.fail(msg='User does not have permissions to move devices to {0}'.format(target))
550 except Exception, e:
551 log.exception("Failed to move devices")
552 return DirectResponse.exception(e, 'Failed to move devices.')
553 if asynchronous:
554 return DirectResponse.succeed(new_jobs=Zuul.marshal([result],
555 keys=('uuid', 'description', 'started')))
556 else:
557 return DirectResponse.succeed(exports=result)
558
559 @require('Manage Device')
560 - def pushChanges(self, uids, hashcheck, ranges=(), uid=None, params=None,
561 sort='name', dir='ASC'):
562 """
563 Push changes on device(s) configuration to collectors.
564
565 @type uids: [string]
566 @param uids: List of device uids to push changes
567 @type hashcheck: string
568 @param hashcheck: Hashcheck for the devices (from getDevices())
569 @type ranges: [integer]
570 @param ranges: (optional) List of two integers that are the min/max
571 values of a range of uids to include (default: None)
572 @type uid: string
573 @param uid: (optional) Organizer to use when using ranges to get
574 additional uids (default: None)
575 @type params: dictionary
576 @param params: (optional) Key-value pair of filters for this search.
577 Can be one of the following: name, ipAddress,
578 deviceClass, or productionState (default: None)
579 @type sort: string
580 @param sort: (optional) Key on which to sort the return result (default:
581 'name')
582 @type dir: string
583 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
584 (default: 'ASC')
585 @rtype: DirectResponse
586 @return: Success message
587 """
588 if ranges:
589 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir)
590
591 facade = self._getFacade()
592 facade.pushChanges(uids)
593 for uid in uids:
594 audit('UI.Device.PushChanges', uid)
595 return DirectResponse.succeed('Changes pushed to collectors.')
596
597 - def lockDevices(self, uids, hashcheck, ranges=(), updates=False,
598 deletion=False, sendEvent=False, uid=None, params=None,
599 sort='name', dir='ASC'):
600 """
601 Lock device(s) from changes.
602
603 @type uids: [string]
604 @param uids: List of device uids to lock
605 @type hashcheck: string
606 @param hashcheck: Hashcheck for the devices (from getDevices())
607 @type ranges: [integer]
608 @param ranges: (optional) List of two integers that are the min/max
609 values of a range of uids to include (default: None)
610 @type updates: boolean
611 @param updates: (optional) True to lock device from updates (default: False)
612 @type deletion: boolean
613 @param deletion: (optional) True to lock device from deletion
614 (default: False)
615 @type sendEvent: boolean
616 @param sendEvent: (optional) True to send an event when an action is
617 blocked by locking (default: False)
618 @type uid: string
619 @param uid: (optional) Organizer to use when using ranges to get
620 additional uids (default: None)
621 @type params: dictionary
622 @param params: (optional) Key-value pair of filters for this search.
623 Can be one of the following: name, ipAddress,
624 deviceClass, or productionState (default: None)
625 @type sort: string
626 @param sort: (optional) Key on which to sort the return result (default:
627 'name')
628 @type dir: string
629 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
630 (default: 'ASC')
631 @rtype: DirectResponse
632 @return: Success or failure message
633 """
634 if ranges:
635 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir)
636 facade = self._getFacade()
637 uids = filterUidsByPermission(self.context.dmd, ZEN_MANAGE_DMD, uids)
638 try:
639 facade.setLockState(uids, deletion=deletion, updates=updates,
640 sendEvent=sendEvent)
641 if not deletion and not updates:
642 message = "Unlocked %s devices." % len(uids)
643 else:
644 actions = []
645 if deletion:
646 actions.append('deletion')
647 if updates:
648 actions.append('updates')
649 message = "Locked %s devices from %s." % (len(uids),
650 ' and '.join(actions))
651 for uid in uids:
652 audit('UI.Device.EditLocks', uid,
653 deletion=deletion, updates=updates, sendEvent=sendEvent)
654 return DirectResponse.succeed(message)
655 except Exception, e:
656 log.exception(e)
657 return DirectResponse.exception(e, 'Failed to lock devices.')
658
659
660 - def resetIp(self, uids, hashcheck, uid=None, ranges=(), params=None,
661 sort='name', dir='ASC', ip=''):
662 """
663 Reset IP address(es) of device(s) to the results of a DNS lookup or
664 a manually set address
665
666 @type uids: [string]
667 @param uids: List of device uids with IP's to reset
668 @type hashcheck: string
669 @param hashcheck: Hashcheck for the devices (from getDevices())
670 @type uid: string
671 @param uid: (optional) Organizer to use when using ranges to get
672 additional uids (default: None)
673 @type ranges: [integer]
674 @param ranges: (optional) List of two integers that are the min/max
675 values of a range of uids to include (default: None)
676 @type params: dictionary
677 @param params: (optional) Key-value pair of filters for this search.
678 Can be one of the following: name, ipAddress,
679 deviceClass, or productionState (default: None)
680 @type sort: string
681 @param sort: (optional) Key on which to sort the return result (default:
682 'name')
683 @type dir: string
684 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
685 (default: 'ASC')
686 @type ip: string
687 @param ip: (optional) IP to set device to. Empty string causes DNS
688 lookup (default: '')
689 @rtype: DirectResponse
690 @return: Success or failure message
691 """
692 if ranges:
693 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir)
694 facade = self._getFacade()
695 uids = filterUidsByPermission(self.context.dmd, ZEN_ADMIN_DEVICE, uids)
696 try:
697 for uid in uids:
698 info = facade.getInfo(uid)
699 info.ipAddress = ip
700 audit('UI.Device.ResetIP', uid, ip=ip)
701 return DirectResponse('Reset %s IP addresses.' % len(uids))
702 except Exception, e:
703 log.exception(e)
704 return DirectResponse.exception(e, 'Failed to reset IP addresses.')
705
706 @require('Manage Device')
709 """
710 Reset SNMP community string(s) on device(s)
711
712 @type uids: [string]
713 @param uids: List of device uids to reset
714 @type hashcheck: string
715 @param hashcheck: Hashcheck for the devices (from getDevices())
716 @type uid: string
717 @param uid: (optional) Organizer to use when using ranges to get
718 additional uids (default: None)
719 @type ranges: [integer]
720 @param ranges: (optional) List of two integers that are the min/max
721 values of a range of uids to include (default: None)
722 @type params: dictionary
723 @param params: (optional) Key-value pair of filters for this search.
724 Can be one of the following: name, ipAddress,
725 deviceClass, or productionState (default: None)
726 @type sort: string
727 @param sort: (optional) Key on which to sort the return result (default:
728 'name')
729 @type dir: string
730 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
731 (default: 'ASC')
732 @rtype: DirectResponse
733 @return: Success or failure message
734 """
735 if ranges:
736 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir)
737 facade = self._getFacade()
738 try:
739 for uid in uids:
740 facade.resetCommunityString(uid)
741 audit('UI.Device.ResetCommunity', uid)
742 return DirectResponse('Reset %s community strings.' % len(uids))
743 except Exception, e:
744 log.exception(e)
745 return DirectResponse.exception(e, 'Failed to reset community strings.')
746
747 - def setProductionState(self, uids, prodState, hashcheck, uid=None,
748 ranges=(), params=None, sort='name', dir='ASC'):
749 """
750 Set the production state of device(s).
751
752 @type uids: [string]
753 @param uids: List of device uids to set
754 @type prodState: integer
755 @param prodState: Production state to set device(s) to.
756 @type hashcheck: string
757 @param hashcheck: Hashcheck for the devices (from getDevices())
758 @type uid: string
759 @param uid: (optional) Organizer to use when using ranges to get
760 additional uids (default: None)
761 @type ranges: [integer]
762 @param ranges: (optional) List of two integers that are the min/max
763 values of a range of uids to include (default: None)
764 @type params: dictionary
765 @param params: (optional) Key-value pair of filters for this search.
766 Can be one of the following: name, ipAddress,
767 deviceClass, or productionState (default: None)
768 @type sort: string
769 @param sort: (optional) Key on which to sort the return result (default:
770 'name')
771 @type dir: string
772 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
773 (default: 'ASC')
774 @rtype: DirectResponse
775 @return: Success or failure message
776 """
777 if ranges:
778 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir)
779 facade = self._getFacade()
780 uids = filterUidsByPermission(self.context.dmd, ZEN_CHANGE_DEVICE_PRODSTATE,
781 uids)
782 try:
783 oldStates = {}
784 uids = (uids,) if isinstance(uids, basestring) else uids
785 for uid in uids:
786 device = facade._getObject(uid)
787 if isinstance(device, Device):
788 oldStates[uid] = self.context.convertProdState(device.productionState)
789
790 prodStateName = self.context.convertProdState(prodState)
791
792 auditData = {'productionState': prodStateName}
793 for uid in uids:
794 oldAuditData = {'productionState': oldStates[uid]}
795 audit('UI.Device.Edit', uid, oldData_=oldAuditData, data_=auditData)
796 facade.setProductionState(uids, prodState, asynchronous=True)
797 return DirectResponse('Set %s devices to %s.' % (
798 len(uids), prodStateName))
799 except Exception, e:
800 log.exception(e)
801 return DirectResponse.exception(e, 'Failed to change production state.')
802
803 - def setPriority(self, uids, priority, hashcheck, uid=None, ranges=(),
804 params=None, sort='name', dir='ASC'):
805 """
806 Set device(s) priority.
807
808 @type uids: [string]
809 @param uids: List of device uids to set
810 @type priority: integer
811 @param priority: Priority to set device(s) to.
812 @type hashcheck: string
813 @param hashcheck: Hashcheck for the devices (from getDevices())
814 @type uid: string
815 @param uid: (optional) Organizer to use when using ranges to get
816 additional uids (default: None)
817 @type ranges: [integer]
818 @param ranges: (optional) List of two integers that are the min/max
819 values of a range of uids to include (default: None)
820 @type params: dictionary
821 @param params: (optional) Key-value pair of filters for this search.
822 Can be one of the following: name, ipAddress,
823 deviceClass, or productionState (default: None)
824 @type sort: string
825 @param sort: (optional) Key on which to sort the return result (default:
826 'name')
827 @type dir: string
828 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
829 (default: 'ASC')
830 @rtype: DirectResponse
831 @return: Success or failure message
832 """
833 if ranges:
834 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir)
835 facade = self._getFacade()
836 uids = filterUidsByPermission(self.context.dmd, ZEN_MANAGE_DEVICE, uids)
837 try:
838 for uid in uids:
839 info = facade.getInfo(uid)
840 oldPriorityLabel = info.priorityLabel
841 info.priority = priority
842 notify(IndexingEvent(info._object))
843 audit('UI.Device.Edit', uid,
844 priority=info.priorityLabel,
845 oldData_={'priority':oldPriorityLabel})
846 return DirectResponse('Set %s devices to %s priority.' % (
847 len(uids), info.priorityLabel))
848 except Exception, e:
849 log.exception(e)
850 return DirectResponse.exception(e, 'Failed to change priority.')
851
852 - def setCollector(self, uids, collector, hashcheck, uid=None, ranges=(),
853 params=None, sort='name', dir='ASC', moveData=False,
854 asynchronous=True):
855 """
856 Set device(s) collector.
857
858 @type uids: [string]
859 @param uids: List of device uids to set
860 @type collector: string
861 @param collector: Collector to set devices to
862 @type hashcheck: string
863 @param hashcheck: Hashcheck for the devices (from getDevices())
864 @type uid: string
865 @param uid: (optional) Organizer to use when using ranges to get
866 additional uids (default: None)
867 @type ranges: [integer]
868 @param ranges: (optional) List of two integers that are the min/max
869 values of a range of uids to include (default: None)
870 @type params: dictionary
871 @param params: (optional) Key-value pair of filters for this search.
872 Can be one of the following: name, ipAddress,
873 deviceClass, or productionState (default: None)
874 @type sort: string
875 @param sort: (optional) Key on which to sort the return result (default:
876 'name')
877 @type dir: string
878 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
879 (default: 'ASC')
880 @rtype: DirectResponse
881 @return: Success or failure message
882 """
883 if ranges:
884 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir)
885 facade = self._getFacade()
886 uids = filterUidsByPermission(self.context.dmd, ZEN_ADMIN_DEVICE, uids)
887 try:
888
889 result = facade.setCollector(uids, collector, asynchronous)
890 for devUid in uids:
891 audit('UI.Device.ChangeCollector', devUid, collector=collector)
892 if asynchronous and result:
893 return DirectResponse.succeed(new_jobs=Zuul.marshal(result,
894 keys=('uuid', 'description', 'started')))
895 else:
896 return DirectResponse.succeed('Changed collector to %s for %s devices.' %
897 (collector, len(uids)))
898 except Exception, e:
899 log.exception(e)
900 return DirectResponse.exception(e, 'Failed to change the collector.')
901
902 - def setComponentsMonitored(self, uids, hashcheck, monitor=False, uid=None,
903 ranges=(), meta_type=None, keys=None,
904 start=0, limit=50, sort='name', dir='ASC',
905 name=None):
906 """
907 Set the monitoring flag for component(s)
908
909 @type uids: [string]
910 @param uids: List of component uids to set
911 @type hashcheck: string
912 @param hashcheck: Hashcheck for the components (from getComponents())
913 @type monitor: boolean
914 @param monitor: (optional) True to monitor component (default: False)
915 @type uid: string
916 @param uid: (optional) Device to use when using ranges to get
917 additional uids (default: None)
918 @type ranges: [integer]
919 @param ranges: (optional) List of two integers that are the min/max
920 values of a range of uids to include (default: None)
921 @type meta_type: string
922 @param meta_type: (optional) The meta type of the components to retrieve
923 (default: None)
924 @type keys: [string]
925 @param keys: not used
926 @type start: integer
927 @param start: (optional) Offset to return the results from; used in
928 pagination (default: 0)
929 @type limit: integer
930 @param limit: (optional) Number of items to return; used in pagination
931 (default: 50)
932 @type sort: string
933 @param sort: (optional) Key on which to sort the return result (default:
934 'name')
935 @type dir: string
936 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
937 (default: 'ASC')
938 @type name: string
939 @param name: (optional) Component name to search for when loading ranges
940 (default: None)
941 @rtype: DirectResponse
942 @return: Success or failure message
943 """
944 if ranges:
945 uids += self.loadComponentRanges(ranges, hashcheck, uid, (),
946 meta_type, start, limit, sort,
947 dir, name)
948 facade = self._getFacade()
949 facade.setMonitor(uids, monitor)
950 action = 'SetMonitored' if monitor else 'SetUnmonitored'
951 for uid in uids:
952 audit(['UI.Component', action], uid)
953 return DirectResponse.succeed(('Set monitoring to %s for %s'
954 ' components.') % (monitor, len(uids)))
955
956 - def lockComponents(self, uids, hashcheck, uid=None, ranges=(),
957 updates=False, deletion=False, sendEvent=False,
958 meta_type=None, keys=None, start=0, limit=50,
959 sort='name', dir='ASC', name=None):
960 """
961 Lock component(s) from changes.
962
963 @type uids: [string]
964 @param uids: List of component uids to lock
965 @type hashcheck: string
966 @param hashcheck: Hashcheck for the components (from getComponents())
967 @type uid: string
968 @param uid: (optional) Device to use when using ranges to get
969 additional uids (default: None)
970 @type ranges: [integer]
971 @param ranges: (optional) List of two integers that are the min/max
972 values of a range of uids to include (default: None)
973 @type updates: boolean
974 @param updates: (optional) True to lock component from updates (default: False)
975 @type deletion: boolean
976 @param deletion: (optional) True to lock component from deletion
977 (default: False)
978 @type sendEvent: boolean
979 @param sendEvent: (optional) True to send an event when an action is
980 blocked by locking (default: False)
981 @type meta_type: string
982 @param meta_type: (optional) The meta type of the components to retrieve
983 (default: None)
984 @type keys: [string]
985 @param keys: not used
986 @type start: integer
987 @param start: (optional) Offset to return the results from; used in
988 pagination (default: 0)
989 @type limit: integer
990 @param limit: (optional) Number of items to return; used in pagination
991 (default: 50)
992 @type sort: string
993 @param sort: (optional) Key on which to sort the return result (default:
994 'name')
995 @type dir: string
996 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
997 (default: 'ASC')
998 @type name: string
999 @param name: (optional) Component name to search for when loading ranges
1000 (default: None)
1001 @rtype: DirectResponse
1002 @return: Success or failure message
1003 """
1004 if ranges:
1005 uids += self.loadComponentRanges(ranges, hashcheck, uid, (),
1006 meta_type, start, limit, sort,
1007 dir, name)
1008 facade = self._getFacade()
1009 try:
1010 facade.setLockState(uids, deletion=deletion, updates=updates,
1011 sendEvent=sendEvent)
1012 if not deletion and not updates:
1013 message = "Unlocked %d components." % len(uids)
1014 else:
1015 actions = []
1016 if deletion:
1017 actions.append('deletion')
1018 if updates:
1019 actions.append('updates')
1020 actions = ' and '.join(actions)
1021 message = "Locked %d components from %s." % (len(uids), actions)
1022 for uid in uids:
1023 audit('UI.Component.EditLocks', uid,
1024 deletion=deletion, updates=updates, sendEvents=sendEvent)
1025 return DirectResponse.succeed(message)
1026 except Exception, e:
1027 log.exception(e)
1028 return DirectResponse.exception(e, 'Failed to lock components.')
1029
1030 - def deleteComponents(self, uids, hashcheck, uid=None, ranges=(),
1031 meta_type=None, keys=None, start=0, limit=50,
1032 sort='name', dir='ASC', name=None):
1033 """
1034 Delete device component(s).
1035
1036 @type uids: [string]
1037 @param uids: List of component uids to delete
1038 @type hashcheck: string
1039 @param hashcheck: Hashcheck for the components (from getComponents())
1040 @type uid: string
1041 @param uid: (optional) Device to use when using ranges to get
1042 additional uids (default: None)
1043 @type ranges: [integer]
1044 @param ranges: (optional) List of two integers that are the min/max
1045 values of a range of uids to include (default: None)
1046 @type meta_type: string
1047 @param meta_type: (optional) The meta type of the components to retrieve
1048 (default: None)
1049 @type keys: [string]
1050 @param keys: not used
1051 @type start: integer
1052 @param start: (optional) Offset to return the results from; used in
1053 pagination (default: 0)
1054 @type limit: integer
1055 @param limit: (optional) Number of items to return; used in pagination
1056 (default: 50)
1057 @type sort: string
1058 @param sort: (optional) Key on which to sort the return result (default:
1059 'name')
1060 @type dir: string
1061 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
1062 (default: 'ASC')
1063 @type name: string
1064 @param name: (optional) Component name to search for when loading ranges
1065 (default: None)
1066 @rtype: DirectResponse
1067 @return: Success or failure message
1068 """
1069 if ranges:
1070 uids += self.loadComponentRanges(ranges, hashcheck, uid, (),
1071 meta_type, start, limit, sort,
1072 dir, name)
1073 facade = self._getFacade()
1074 try:
1075 facade.deleteComponents(uids)
1076 for uid in uids:
1077 audit('UI.Component.Delete', uid)
1078 return DirectResponse.succeed('Components deleted.')
1079 except Exception, e:
1080 log.exception(e)
1081 return DirectResponse.exception(e, 'Failed to delete components.')
1082
1083 - def removeDevices(self, uids, hashcheck, action="remove", uid=None,
1084 ranges=(), params=None, sort='name', dir='ASC',
1085 deleteEvents=False, deletePerf=False
1086 ):
1087 """
1088 Remove/delete device(s).
1089
1090 @type uids: [string]
1091 @param uids: List of device uids to remove
1092 @type hashcheck: string
1093 @param hashcheck: Hashcheck for the devices (from getDevices())
1094 @type action: string
1095 @param action: Action to take. 'remove' to remove devices from organizer
1096 uid, and 'delete' to delete the device from Zenoss.
1097 @type uid: string
1098 @param uid: (optional) Organizer to use when using ranges to get
1099 additional uids and/or to remove device (default: None)
1100 @type ranges: [integer]
1101 @param ranges: (optional) List of two integers that are the min/max
1102 values of a range of uids to include (default: None)
1103 @type params: dictionary
1104 @param params: (optional) Key-value pair of filters for this search.
1105 Can be one of the following: name, ipAddress,
1106 deviceClass, or productionState (default: None)
1107 @type sort: string
1108 @param sort: (optional) Key on which to sort the return result (default:
1109 'name')
1110 @type dir: string
1111 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
1112 (default: 'ASC')
1113 @type deleteEvents: bool
1114 @param deleteEvents: will remove all the events for the devices as well
1115 @type deletePerf: bool
1116 @param deletePerf: will remove all the perf data for the devices
1117 @rtype: DirectResponse
1118 @return: B{Properties}:
1119 - devtree: ([dictionary]) Object representing the new device tree
1120 - grptree: ([dictionary]) Object representing the new group tree
1121 - systree: ([dictionary]) Object representing the new system tree
1122 - loctree: ([dictionary]) Object representing the new location tree
1123 """
1124 if ranges:
1125 uids += self.loadRanges(ranges, hashcheck, uid, params, sort, dir)
1126 facade = self._getFacade()
1127 removedUids = tuple()
1128 uids = filterUidsByPermission(self.context.dmd, ZEN_DELETE_DEVICE, uids)
1129 try:
1130 if action == "remove":
1131 removed = facade.removeDevices(uids, organizer=uid)
1132
1133
1134 organizer = facade._getObject(uid) if isinstance(uid, basestring) else uid
1135 organizerType = organizer.meta_type
1136 action = 'RemoveFrom' + organizerType
1137 removedUids = map(lambda x: x.uid, removed)
1138 for devuid in removedUids:
1139
1140 audit('UI.Device.%s' % action, devuid, data_={organizerType:uid})
1141 notRemovedUids = list(set(uids) - set(removedUids))
1142 return DirectResponse.succeed(
1143 removedUids=removedUids,
1144 notRemovedUids=notRemovedUids)
1145 elif action == "delete":
1146 for devuid in uids:
1147 audit('UI.Device.Delete', devuid,
1148 deleteEvents=deleteEvents,
1149 deletePerf=deletePerf)
1150 facade.deleteDevices(uids,
1151 deleteEvents=deleteEvents,
1152 deletePerf=deletePerf)
1153 return DirectResponse.succeed()
1154 except Exception, e:
1155 log.exception(e)
1156 return DirectResponse.exception(e, 'Failed to remove devices.')
1157
1158 @serviceConnectionError
1160 """
1161 Returns the url and title for each graph
1162 for the object passed in.
1163 @type uid: string
1164 @param uid: unique identifier of an object
1165 """
1166 facade = self._getFacade()
1167 data = facade.getGraphDefs(uid, drange)
1168 return DirectResponse(data=Zuul.marshal(data))
1169
1170 - def loadRanges(self, ranges, hashcheck, uid=None, params=None,
1171 sort='name', dir='ASC'):
1172 """
1173 Get a range of device uids.
1174
1175 @type ranges: [integer]
1176 @param ranges: List of two integers that are the min/max values of a
1177 range of uids
1178 @type hashcheck: string
1179 @param hashcheck: Hashcheck for the devices (from getDevices())
1180 @type uid: string
1181 @param uid: (optional) Organizer to use to get uids (default: None)
1182 @type params: dictionary
1183 @param params: (optional) Key-value pair of filters for this search.
1184 Can be one of the following: name, ipAddress,
1185 deviceClass, or productionState (default: None)
1186 @type sort: string
1187 @param sort: (optional) Key on which to sort the return result (default:
1188 'name')
1189 @type dir: string
1190 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
1191 (default: 'ASC')
1192 @rtype: [string]
1193 @return: A list of device uids
1194 """
1195 facade = self._getFacade()
1196 if isinstance(params, basestring):
1197 params = unjson(params)
1198 devs = facade.getDeviceBrains(uid, limit=None, sort=sort, dir=dir,
1199 params=params, hashcheck=hashcheck)
1200 uids = []
1201 for start, stop in sorted(ranges):
1202 uids.extend(b.getPath() for b in islice(devs, start, stop + 1))
1203 return uids
1204
1205 - def loadComponentRanges(self, ranges, hashcheck, uid=None, types=(),
1206 meta_type=(), start=0, limit=None, sort='name',
1207 dir='ASC', name=None):
1208 """
1209 Get a range of component uids.
1210
1211 @type ranges: [integer]
1212 @param ranges: List of two integers that are the min/max values of a
1213 range of uids
1214 @type hashcheck: string
1215 @param hashcheck: not used
1216 @type uid: string
1217 @param uid: (optional) Device to use to get uids (default: None)
1218 @type types: [string]
1219 @param types: (optional) The types of components to retrieve (default: None)
1220 @type meta_type: string
1221 @param meta_type: (optional) The meta type of the components to retrieve
1222 (default: None)
1223 @type start: integer
1224 @param start: (optional) Offset to return the results from; used in
1225 pagination (default: 0)
1226 @type limit: integer
1227 @param limit: (optional) Number of items to return; used in pagination
1228 (default: None)
1229 @type sort: string
1230 @param sort: (optional) Key on which to sort the return result (default:
1231 'name')
1232 @type dir: string
1233 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
1234 (default: 'ASC')
1235 @type name: string
1236 @param name: (optional) Component name to search for when loading ranges
1237 (default: None)
1238 @rtype: [string]
1239 @return: A list of component uids
1240 """
1241 if uid is None:
1242 uid = "/".join(self.context.getPhysicalPath())
1243 facade = self._getFacade()
1244 comps = facade.getComponents(uid, types, meta_type, start, limit, sort,
1245 dir, name)
1246 uids = []
1247 for start, stop in sorted(ranges):
1248 uids.extend(b.uid for b in islice(comps, start, stop))
1249 return uids
1250
1251 @serviceConnectionError
1253 """
1254 Get a list of user commands for a device uid.
1255
1256 @type uid: string
1257 @param uid: Device to use to get user commands
1258 @rtype: [dictionary]
1259 @return: List of objects representing user commands
1260 """
1261 facade = self._getFacade()
1262 cmds = facade.getUserCommands(uid)
1263 return Zuul.marshal(cmds, ['id', 'description'])
1264
1266 """
1267 Get a list of available production states.
1268
1269 @rtype: [dictionary]
1270 @return: List of name/value pairs of available production states
1271 """
1272 return DirectResponse(data=[dict(name=s.split(':')[0],
1273 value=int(s.split(':')[1])) for s in
1274 self.context.dmd.prodStateConversions])
1275
1277 """
1278 Get a list of available device priorities.
1279
1280 @rtype: [dictionary]
1281 @return: List of name/value pairs of available device priorities
1282 """
1283 return DirectResponse(data=[dict(name=s.split(':')[0],
1284 value=int(s.split(':')[1])) for s in
1285 self.context.dmd.priorityConversions])
1286
1288 """
1289 Get a list of available collectors.
1290
1291 @rtype: [string]
1292 @return: List of collectors
1293 """
1294 return self.context.dmd.Monitors.getPerformanceMonitorNames()
1295
1297 """
1298 Get a list of all device classes.
1299
1300 @rtype: DirectResponse
1301 @return: B{Properties}:
1302 - deviceClasses: ([dictionary]) List of device classes
1303 - totalCount: (integer) Total number of device classes
1304 """
1305 devices = self.context.dmd.Devices
1306 deviceClasses = devices.getOrganizerNames(addblank=True)
1307 result = [{'name': name} for name in deviceClasses]
1308 return DirectResponse(deviceClasses=result, totalCount=len(result))
1309
1311 """
1312 Get a list of all systems.
1313
1314 @rtype: DirectResponse
1315 @return: B{Properties}:
1316 - systems: ([dictionary]) List of systems
1317 - totalCount: (integer) Total number of systems
1318 """
1319 systems = self.context.dmd.Systems.getOrganizerNames()
1320 result = [{'name': name} for name in systems if name != '/']
1321 return DirectResponse(systems=result, totalCount=len(result))
1322
1324 """
1325 Get a list of all groups.
1326
1327 @rtype: DirectResponse
1328 @return: B{Properties}:
1329 - systems: ([dictionary]) List of groups
1330 - totalCount: (integer) Total number of groups
1331 """
1332 groups = self.context.dmd.Groups.getOrganizerNames()
1333 result = [{'name': name} for name in groups if name != '/']
1334 return DirectResponse(groups=result, totalCount=len(result))
1335
1337 """
1338 Get a list of all locations.
1339
1340 @rtype: DirectResponse
1341 @return: B{Properties}:
1342 - systems: ([dictionary]) List of locations
1343 - totalCount: (integer) Total number of locations
1344 """
1345 locations = self.context.dmd.Locations.getOrganizerNames()
1346 result = [{'name': name} for name in locations if name != '/']
1347 return DirectResponse(locations=result, totalCount=len(result))
1348
1350 """
1351 Get a list of all manufacturer names.
1352
1353 @rtype: DirectResponse
1354 @return: B{Properties}:
1355 - manufacturers: ([dictionary]) List of manufacturer names
1356 - totalCount: (integer) Total number of manufacturer names
1357 """
1358 names = self.context.dmd.Manufacturers.getManufacturerNames()
1359 result = [{'name': name} for name in names]
1360 return DirectResponse(manufacturers=result, totalCount=len(result))
1361
1363 """
1364 Get a list of all hardware product names from a manufacturer.
1365
1366 @type manufacturer: string
1367 @param manufacturer: Manufacturer name
1368 @rtype: DirectResponse
1369 @return: B{Properties}:
1370 - productNames: ([dictionary]) List of hardware product names
1371 - totalCount: (integer) Total number of hardware product names
1372 """
1373 manufacturers = self.context.dmd.Manufacturers
1374 names = manufacturers.getProductNames(manufacturer, 'HardwareClass')
1375 result = [{'name': name} for name in names]
1376 return DirectResponse(productNames=result, totalCount=len(result))
1377
1379 """
1380 Get a list of all OS product names from a manufacturer.
1381
1382 @type manufacturer: string
1383 @param manufacturer: Manufacturer name
1384 @rtype: DirectResponse
1385 @return: B{Properties}:
1386 - productNames: ([dictionary]) List of OS product names
1387 - totalCount: (integer) Total number of OS product names
1388 """
1389 manufacturers = self.context.dmd.Manufacturers
1390 names = manufacturers.getProductNames(manufacturer, 'OS')
1391 result = [{'name': name} for name in names]
1392 return DirectResponse(productNames=result, totalCount=len(result))
1393
1394 - def addDevice(self, deviceName, deviceClass, title=None,
1395 snmpCommunity="", snmpPort=161, manageIp="",
1396 model=False, collector='localhost', rackSlot=0,
1397 locationPath="", systemPaths=[], groupPaths=[],
1398 productionState=1000, comments="", hwManufacturer="",
1399 hwProductName="", osManufacturer="", osProductName="",
1400 priority=3, tag="", serialNumber="", zCommandUsername="",
1401 zCommandPassword="", zWinUser="", zWinPassword="",
1402 zProperties={}, cProperties={},):
1403
1404 """
1405 Add a device.
1406
1407 @type deviceName: string
1408 @param deviceName: Name or IP of the new device
1409 @type deviceClass: string
1410 @param deviceClass: The device class to add new device to
1411 @type title: string
1412 @param title: (optional) The title of the new device (default: '')
1413 @type snmpCommunity: string
1414 @param snmpCommunity: (optional) A specific community string to use for
1415 this device. (default: '')
1416 @type snmpPort: integer
1417 @param snmpPort: (optional) SNMP port on new device (default: 161)
1418 @type manageIp: string
1419 @param manageIp: (optional) Management IP address on new device (default:
1420 empty/derive from DNS)
1421 @type locationPath: string
1422 @param locationPath: (optional) Organizer path of the location for this device
1423 @type systemPaths: List (strings)
1424 @param systemPaths: (optional) List of organizer paths for the device
1425 @type groupPaths: List (strings)
1426 @param groupPaths: (optional) List of organizer paths for the device
1427 @type model: boolean
1428 @param model: (optional) True to model device at add time (default: False)
1429 @type collector: string
1430 @param collector: (optional) Collector to use for new device (default:
1431 localhost)
1432 @type rackSlot: string
1433 @param rackSlot: (optional) Rack slot description (default: '')
1434 @type productionState: integer
1435 @param productionState: (optional) Production state of the new device
1436 (default: 1000)
1437 @type comments: string
1438 @param comments: (optional) Comments on this device (default: '')
1439 @type hwManufacturer: string
1440 @param hwManufacturer: (optional) Hardware manufacturer name (default: '')
1441 @type hwProductName: string
1442 @param hwProductName: (optional) Hardware product name (default: '')
1443 @type osManufacturer: string
1444 @param osManufacturer: (optional) OS manufacturer name (default: '')
1445 @type osProductName: string
1446 @param osProductName: (optional) OS product name (default: '')
1447 @type priority: integer
1448 @param priority: (optional) Priority of this device (default: 3)
1449 @type tag: string
1450 @param tag: (optional) Tag number of this device (default: '')
1451 @type serialNumber: string
1452 @param serialNumber: (optional) Serial number of this device (default: '')
1453 @type zCommandUsername: string
1454 @param zWinUser: (optional) Username for WMI (default: '')
1455 @type zCommandPassword: string
1456 @param zWinPassword: (optional) Password for WMI (default: '')
1457 @rtype: DirectResponse
1458 @return: B{Properties}:
1459 - jobId: (string) ID of the add device job
1460 """
1461
1462
1463 facade = self._getFacade()
1464 organizerUid = '/zport/dmd/Devices' + deviceClass
1465 organizer = facade._getObject(organizerUid)
1466 if not Zuul.checkPermission("Manage Device", organizer):
1467 raise Unauthorized('Calling AddDevice requires ' +
1468 'Manage Device permission on %s' % deviceClass)
1469
1470 if title is None:
1471 title = deviceName
1472
1473
1474
1475
1476 safeDeviceName = organizer.prepId(deviceName)
1477
1478 device = facade.getDeviceByIpAddress(safeDeviceName, collector, manageIp)
1479 if device:
1480 return DirectResponse.fail(deviceUid=device.getPrimaryId(),
1481 msg="Device %s already exists. <a href='%s'>Go to the device</a>" % (deviceName, device.getPrimaryId()))
1482
1483 if isinstance(systemPaths, basestring):
1484 systemPaths = [systemPaths]
1485 if isinstance(groupPaths, basestring):
1486 groupPaths = [groupPaths]
1487
1488 jobrecords = self._getFacade().addDevice(deviceName,
1489 deviceClass,
1490 title,
1491 snmpCommunity,
1492 snmpPort,
1493 manageIp,
1494 model,
1495 collector,
1496 rackSlot,
1497 productionState,
1498 comments,
1499 hwManufacturer,
1500 hwProductName,
1501 osManufacturer,
1502 osProductName,
1503 priority,
1504 tag,
1505 serialNumber,
1506 locationPath,
1507 zCommandUsername,
1508 zCommandPassword,
1509 zWinUser,
1510 zWinPassword,
1511 systemPaths,
1512 groupPaths,
1513 zProperties,
1514 cProperties,
1515 )
1516
1517 deviceUid = '/'.join([organizerUid, 'devices', deviceName])
1518
1519 hasGroups = len(groupPaths) > 1 or (groupPaths and groupPaths[0])
1520 hasSystems = len(systemPaths) > 1 or (systemPaths and systemPaths[0])
1521 auditData = {
1522 'deviceClass': '/Devices' + deviceClass,
1523 'location': '/Locations' + locationPath if locationPath else None,
1524 'deviceGroups': ['/Groups' + x for x in groupPaths] if hasGroups else None,
1525 'systems': ['/Systems' + x for x in systemPaths] if hasSystems else None,
1526 'device_name': title if title else deviceName,
1527 'collector': collector,
1528 'model': str(model),
1529 'productionState': self.context.convertProdState(productionState),
1530 'priority': self.context.convertPriority(priority),
1531 }
1532 audit('UI.Device.Add', deviceUid, data_=auditData)
1533 return DirectResponse.succeed(new_jobs=Zuul.marshal(jobrecords, keys=('uuid', 'description')))
1534
1535 @require('Manage Device')
1537 """
1538 Submit a job to have a device remodeled.
1539
1540 @type deviceUid: string
1541 @param deviceUid: Device uid to have local template
1542 @rtype: DirectResponse
1543 @return: B{Properties}:
1544 - jobId: (string) ID of the add device job
1545 """
1546 jobStatus = self._getFacade().remodel(deviceUid)
1547 audit('UI.Device.Remodel', deviceUid)
1548 return DirectResponse.succeed(jobId=jobStatus.id)
1549
1550 @require('Edit Local Templates')
1552 """
1553 Adds a local template on a device.
1554
1555 @type deviceUid: string
1556 @param deviceUid: Device uid to have local template
1557 @type templateId: string
1558 @param templateId: Name of the new template
1559 @rtype: DirectResponse
1560 @return: Success message
1561 """
1562 facade = self._getFacade()
1563 facade.addLocalTemplate(deviceUid, templateId)
1564 audit('UI.Device.AddLocalTemplate', deviceUid, template=templateId)
1565 return DirectResponse.succeed()
1566
1567 @require('Edit Local Templates')
1569 """
1570 Removes a locally defined template on a device.
1571
1572 @type deviceUid: string
1573 @param deviceUid: Device uid that has local template
1574 @type templateUid: string
1575 @param templateUid: Name of the template to remove
1576 @rtype: DirectResponse
1577 @return: Success message
1578 """
1579 facade = self._getFacade()
1580 facade.removeLocalTemplate(deviceUid, templateUid)
1581 audit('UI.Device.RemoveLocalTemplate', deviceUid, template=templateUid)
1582 return DirectResponse.succeed()
1583
1585 """
1586 Get a list of locally defined templates on a device.
1587
1588 @type query: string
1589 @param query: not used
1590 @type uid: string
1591 @param uid: Device uid to query for templates
1592 @rtype: DirectResponse
1593 @return: B{Properties}:
1594 - data: ([dictionary]) List of objects representing local templates
1595 """
1596 facade = self._getFacade()
1597 templates = facade.getLocalTemplates(uid)
1598 data = []
1599 for template in templates:
1600 data.append(dict(label=template['text'], uid=template['uid']))
1601 return DirectResponse.succeed(data=data)
1602
1603 @serviceConnectionError
1605 """
1606 Get a list of available templates for a device.
1607
1608 @type id: string
1609 @param id: Device uid to query for templates
1610 @rtype: DirectResponse
1611 @return: B{Properties}:
1612 - data: ([dictionary]) List of objects representing templates
1613 """
1614 facade = self._getFacade()
1615 templates = facade.getTemplates(id)
1616 return Zuul.marshal(templates)
1617
1618 @serviceConnectionError
1620 """
1621 Get a list of unbound templates for a device.
1622
1623 @type uid: string
1624 @param uid: Device uid to query for templates
1625 @rtype: DirectResponse
1626 @return: B{Properties}:
1627 - data: ([dictionary]) List of objects representing templates
1628 """
1629 facade = self._getFacade()
1630 templates = facade.getUnboundTemplates(uid)
1631 data = []
1632 for template in templates:
1633 label = '%s (%s)' % (template.titleOrId(), template.getUIPath())
1634 data.append([template.id, label])
1635 return DirectResponse.succeed(data=Zuul.marshal(data))
1636
1637 @serviceConnectionError
1639 """
1640 Get a list of bound templates for a device.
1641
1642 @type uid: string
1643 @param uid: Device uid to query for templates
1644 @rtype: DirectResponse
1645 @return: B{Properties}:
1646 - data: ([dictionary]) List of objects representing templates
1647 """
1648 facade = self._getFacade()
1649 templates = facade.getBoundTemplates(uid)
1650 data = []
1651 for template in templates:
1652 label = '%s (%s)' % (template.titleOrId(), template.getUIPath())
1653 data.append([template.id, label])
1654 return DirectResponse.succeed(data=Zuul.marshal(data))
1655
1656 @require('Edit Local Templates')
1658 """
1659 Set a list of templates as bound to a device.
1660
1661 @type uid: string
1662 @param uid: Device uid to bind templates to
1663 @type templateIds: [string]
1664 @param templateIds: List of template uids to bind to device
1665 @rtype: DirectResponse
1666 @return: Success message
1667 """
1668 facade = self._getFacade()
1669 try:
1670 facade.setBoundTemplates(uid, templateIds)
1671 except DatapointNameConfict, e:
1672 log.info("Failed to bind templates for {}: {}".format(uid, e))
1673 return DirectResponse.exception(e, 'Failed to bind templates.')
1674 audit('UI.Device.BindTemplates', uid, templates=templateIds)
1675 return DirectResponse.succeed()
1676
1677 @require('Edit Local Templates')
1679 """
1680 Remove all bound templates from a device.
1681
1682 @type uid: string
1683 @param uid: Device uid to remove bound templates from
1684 @rtype: DirectResponse
1685 @return: Success message
1686 """
1687 facade = self._getFacade()
1688 facade.resetBoundTemplates(uid)
1689 audit('UI.Device.ResetBoundTemplates', uid)
1690 return DirectResponse.succeed()
1691
1692 @require('Edit Local Templates')
1694 """
1695 Bind an unbound template or unbind a bound template from a device.
1696
1697 @type uid: string
1698 @param uid: Device uid to bind/unbind template
1699 @type templateUid: string
1700 @param templateUid: Template uid to bind/unbind
1701 @rtype: DirectResponse
1702 @return: Success message
1703 """
1704 facade = self._getFacade()
1705 template = facade._getObject(templateUid)
1706 templateIds = [t.id for t in facade.getBoundTemplates(uid)]
1707
1708 if not template.id in templateIds:
1709 self.setBoundTemplates(uid, templateIds + [template.id])
1710 audit('UI.Device.BindTemplate', uid, template=templateUid)
1711 else:
1712
1713 templateIds = [t for t in templateIds if t != template.id]
1714 self.setBoundTemplates(uid, templateIds)
1715 audit('UI.Device.UnbindTemplate', uid, template=templateUid)
1716 return DirectResponse.succeed()
1717
1719 """
1720 Get a list of available templates on a device that can be overridden.
1721
1722 @type query: string
1723 @param query: not used
1724 @type uid: string
1725 @param uid: Device to query for overridable templates
1726 @rtype: DirectResponse
1727 @return: B{Properties}:
1728 - data: ([dictionary]) List of objects representing templates
1729 """
1730 facade = self._getFacade()
1731 templates = facade.getOverridableTemplates(uid)
1732
1733 data = []
1734 for template in templates:
1735 label = '%s (%s)' % (template.text, template.getUIPath())
1736 data.append(dict(label=label, uid=template.uid))
1737 return DirectResponse.succeed(data=data)
1738
1739 @require('Manage DMD')
1741 """
1742 Clear the Google Maps geocode cache.
1743
1744 @rtype: DirectResponse
1745 @return: Success message
1746 """
1747 facade = self._getFacade()
1748 facade.clearGeocodeCache()
1749 audit('UI.GeocodeCache.Clear')
1750 return DirectResponse.succeed()
1751
1753 """
1754 Returns the zproperty information about those zproperties which comprise
1755 the credentials
1756 @rtype: List of Dictionaries
1757 @return: B{Properties}:
1758 - path: (string) where the property is defined
1759 - type: (string) type of zproperty it is
1760 - options: (Array) available options for the zproperty
1761 - value (Array) value of the zproperty
1762 - valueAsString (string)
1763 """
1764 facade = self._getFacade()
1765 data = facade.getConnectionInfo(uid)
1766 return DirectResponse.succeed(data=Zuul.marshal(data))
1767
1768 @serviceConnectionError
1770 """
1771 Given a uid returns the documentation for all the modeler plugins.
1772 """
1773 facade = self._getFacade()
1774 data = facade.getModelerPluginDocStrings(uid)
1775 return DirectResponse.succeed(data=Zuul.marshal(data))
1776
1777 - def addIpRouteEntry(self, uid, dest='', routemask='', nexthopid='', interface='',
1778 routeproto='', routetype='', userCreated=True):
1779 """
1780 Adds an Ip Route Entry to this device
1781 """
1782 facade = self._getFacade()
1783 data = facade.addIpRouteEntry(uid, dest, routemask, nexthopid, interface,
1784 routeproto, routetype, userCreated)
1785 return DirectResponse.succeed(data=Zuul.marshal(data))
1786
1788 """
1789 Adds an Ip Interface
1790 """
1791 facade = self._getFacade()
1792 data = facade.addIpInterface(uid, newId, userCreated)
1793 return DirectResponse.succeed(data=Zuul.marshal(data))
1794
1795 - def addOSProcess(self, uid, newClassName, example, userCreated=True):
1796 """
1797 Adds an os processes
1798 """
1799 facade = self._getFacade()
1800 data = facade.addOSProcess(uid, newClassName, example, userCreated)
1801 return DirectResponse.succeed(data=Zuul.marshal(data))
1802
1804 """
1805 Adds an Ip Interface
1806 """
1807 facade = self._getFacade()
1808 data = facade.addFileSystem(uid, newId, userCreated)
1809 return DirectResponse.succeed(data=Zuul.marshal(data))
1810
1811 - def addIpService(self, uid, newClassName, protocol, userCreated=True):
1812 """
1813 Adds an Ip Service
1814 """
1815 facade = self._getFacade()
1816 data = facade.addIpService(uid, newClassName, protocol, userCreated)
1817 return DirectResponse.succeed(data=Zuul.marshal(data))
1818
1819
1821 """
1822 Adds an Ip Service
1823 """
1824 facade = self._getFacade()
1825 data = facade.addWinService(uid, newClassName, userCreated)
1826 return DirectResponse.succeed(data=Zuul.marshal(data))
1827
1829
1830 facade = self._getFacade()
1831 software = facade.getSoftware(uid)
1832 return DirectResponse(data=Zuul.marshal(software, keys))
1833
1835 """
1836 returns a list of Overridden Objects and properties for this context
1837 """
1838 facade = self._getFacade()
1839 data = facade.getOverriddenObjectsList(uid, propname, relName)
1840 return DirectResponse.succeed(data=Zuul.marshal(data))
1841
1843 """
1844 returns the base of the Overridden Objects
1845 """
1846 facade = self._getFacade()
1847 data = facade.getOverriddenObjectsParent(uid, propname)
1848 return DirectResponse.succeed(data=Zuul.marshal(data))
1849
1851 """
1852 returns a list of zProperty values for the overridden objects
1853 """
1854 facade = self._getFacade()
1855 data = facade.getOverriddenZprops(uid, all)
1856 return DirectResponse.succeed(data=Zuul.marshal(data))
1857
1859 facade = self._getFacade()
1860 data = facade.getGraphDefinitionsForComponent(uid)
1861 return DirectResponse.succeed(data=Zuul.marshal(data))
1862
1864 """
1865 Returns the graph denoted by graphId for every component in
1866 device (uid) with the meta_type meta_type
1867 """
1868 facade = self._getFacade()
1869 data = facade.getComponentGraphs(uid, meta_type, graphId, allOnSame=allOnSame)
1870 return DirectResponse.succeed(data=Zuul.marshal(data))
1871
1873 """
1874 Returns a list of devtypes for the wizard
1875 """
1876 facade = self._getFacade()
1877 data = facade.getDevTypes(uid)
1878 return DirectResponse.succeed(data=Zuul.marshal(data))
1879