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