Package Products ::
Package Zuul ::
Package routers
|
|
1
2
3
4
5
6
7
8
9
10
11 """
12 Zenoss JSON API
13 """
14
15 from Products.ZenUtils.Ext import DirectRouter, DirectResponse
16 from Products.Zuul.decorators import contextRequire
17 from Products.Zuul.catalog.interfaces import IModelCatalogTool
18 from Products.Zuul.marshalling import Marshaller
19 from Products.ZenModel.DeviceClass import DeviceClass
20 from Products.ZenModel.System import System
21 from Products.ZenMessaging.audit import audit
22 from Products.ZenUtils.Utils import getDisplayType
23 from Products import Zuul
24 import logging
25 import zlib
26 import base64
27 log = logging.getLogger(__name__)
31 """
32 A common base class for routers that have a hierarchical tree structure.
33 """
34
35 @contextRequire("Manage DMD", 'contextUid')
36 - def addNode(self, type, contextUid, id, description=None):
37 """
38 Add a node to the existing tree underneath the node specified
39 by the context UID
40
41 @type type: string
42 @param type: Either 'class' or 'organizer'
43 @type contextUid: string
44 @param contextUid: Path to the node that will
45 be the new node's parent (ex. /zport/dmd/Devices)
46 @type id: string
47 @param id: Identifier of the new node, must be unique in the
48 parent context
49 @type description: string
50 @param description: (optional) Describes this new node (default: None)
51 @rtype: dictionary
52 @return: Marshaled form of the created node
53 """
54 result = {}
55 try:
56 facade = self._getFacade()
57 if type.lower() == 'class':
58 uid = facade.addClass(contextUid, id)
59 audit('UI.Class.Add', uid)
60 else:
61 organizer = facade.addOrganizer(contextUid, id, description)
62 uid = organizer.uid
63 audit(['UI', getDisplayType(organizer), 'Add'], organizer)
64
65 treeNode = facade.getTree(uid)
66 result['nodeConfig'] = Zuul.marshal(treeNode)
67 result['success'] = True
68 except Exception, e:
69 log.exception(e)
70 result['msg'] = str(e)
71 result['success'] = False
72 return result
73
74 @contextRequire("Manage DMD", 'uid')
76 """
77 Deletes a node from the tree.
78
79 B{NOTE}: You can not delete a root node of a tree
80
81 @type uid: string
82 @param uid: Unique identifier of the node we wish to delete
83 @rtype: DirectResponse
84 @return: B{Properties}:
85 - msg: (string) Status message
86 """
87
88 if not self._canDeleteUid(uid):
89 raise Exception('You cannot delete the root node')
90 facade = self._getFacade()
91 node = facade._getObject(uid)
92
93
94
95
96 if isinstance(node, DeviceClass):
97 childBrains = IModelCatalogTool(node).search((
98 'Products.ZenModel.DeviceClass.DeviceClass',
99 'Products.ZenModel.Device.Device', ), fields="meta_type")
100 for child in childBrains:
101 audit(['UI', getDisplayType(child), 'Delete'], child.getPath())
102 elif isinstance(node, System):
103
104 for dev in facade.getDevices(uid):
105 newSystems = facade._removeOrganizer(node, dev._object.getSystemNames())
106 dev._object.setSystems(newSystems)
107 audit(['UI', getDisplayType(node), 'Delete'], node)
108 else:
109 audit(['UI', getDisplayType(node), 'Delete'], node)
110
111 facade.deleteNode(uid)
112 msg = "Deleted node '%s'" % uid
113 return DirectResponse.succeed(msg=msg)
114
116 """
117 Move the organizer uid to be underneath the organizer
118 specified by the targetUid.
119
120 @type targetUid: string
121 @param targetUid: New parent of the organizer
122 @type organizerUid: string
123 @param organizerUid: The organizer to move
124 @rtype: DirectResponse
125 @return: B{Properties}:
126 - data: (dictionary) Moved organizer
127 """
128 facade = self._getFacade()
129 display_type = getDisplayType(facade._getObject(organizerUid))
130 audit(['UI', display_type, 'Move'], organizerUid, to=targetUid)
131 data = facade.moveOrganizer(targetUid, organizerUid)
132 return DirectResponse.succeed(data=Zuul.marshal(data))
133
135 """
136 gzip an arbitrary string, base64 encode it, and return it
137 """
138 try:
139 compressed = base64.urlsafe_b64encode(zlib.compress(string))
140 except Exception as e:
141 log.exception(e)
142 return DirectResponse.exception(e, 'Unable to compress data')
143 return DirectResponse.succeed(data=Zuul.marshal({'data': compressed}))
144
146 """
147 Base 64 decode a string, then gunzip it and return the result as JSON.
148 The input to this method should be gzipped, base 64 encoded JSON. Base
149 64 encoded strings are allowed to have up to 2 '='s of padding. The zenoss
150 Ext router eats these, so there is some logic to try padding them back into
151 the string should initial decoding fail.
152 """
153 data = ''
154 for pad in ('', '=', '=='):
155 try:
156 data = zlib.decompress(base64.urlsafe_b64decode(string + pad))
157 break
158 except Exception as e:
159 if pad == '==':
160 log.exception(e)
161 return DirectResponse.exception(e, 'Unable to decompress data')
162 return DirectResponse.succeed(data=Zuul.marshal({'data': data}))
163
165 """
166 Abstract method for child classes to use to get their facade
167 """
168 raise NotImplementedError("You must implement the _getFacade method")
169
171 """
172 Server side method for asynchronous tree calls. Retrieves
173 the immediate children of the node specified by "id"
174
175 NOTE: our convention on the UI side is if we are asking
176 for the root node then return the root and its children
177 otherwise just return the children
178
179 @type id: string
180 @param id: The uid of the node we are getting the children for
181 @rtype: [dictionary]
182 @return: Object representing the immediate children
183 """
184 showEventSeverityIcons = self.context.dmd.UserInterfaceSettings.getInterfaceSettings().get('showEventSeverityIcons')
185 facade = self._getFacade()
186 currentNode = facade.getTree(id)
187
188 keys = ('id', 'path', 'uid', 'iconCls', 'text', 'hidden', 'leaf') + additionalKeys
189
190
191 childNodes = list(currentNode.children)
192 if showEventSeverityIcons:
193 uuids = [n.uuid for n in childNodes if n.uuid]
194 zep = Zuul.getFacade('zep', self.context.dmd)
195
196 if uuids:
197 severities = zep.getWorstSeverity(uuids)
198 for child in childNodes:
199 if child.uuid:
200 child.setSeverity(zep.getSeverityName(severities.get(child.uuid, 0)).lower())
201
202 children = []
203
204 for child in childNodes:
205 childData = Marshaller(child).marshal(keys)
206
207
208
209
210
211 organizer = child._get_object()
212
213 hasChildren = any((o['meta_type'] for o in organizer._objects if o['meta_type'] == organizer.meta_type))
214
215 if "report" not in organizer.meta_type.lower() and not hasChildren:
216 childData['children'] = []
217 children.append(childData)
218 children.sort(key=lambda e: (e['leaf'], e['uid'].lower()))
219 obj = currentNode._object._unrestrictedGetObject()
220
221
222 primaryId = obj.getDmdRoot(obj.dmdRootName).getPrimaryId()
223 if id == primaryId:
224 root = Marshaller(currentNode).marshal(keys)
225 root['children'] = children
226 return [root]
227 return children
228
230 """
231 @rtype: DirectResponse
232 @return:
233 - Properties:
234 - B{exists} - Returns true if we can find the object specified by the uid
235
236 """
237 from Products.Zuul.facades import ObjectNotFoundException
238 facade = self._getFacade()
239 try:
240 facade._getObject(uid)
241 exists = True
242 except ObjectNotFoundException:
243 exists = False
244 return DirectResponse(success=True, exists=exists)
245
247 """
248 We can not delete top level UID's. For example:
249 - '/zport/dmd/Processes' this will return False (we can NOT delete)
250 - '/zport/dmd/Processes/Child' will return True
251 (we can delete this)
252 """
253
254 levels = len(uid.split('/'))
255 return levels > 4
256