Package Products :: Package Zuul :: Package routers
[hide private]
[frames] | no frames]

Source Code for Package Products.Zuul.routers

  1  ############################################################################## 
  2  # 
  3  # Copyright (C) Zenoss, Inc. 2009, all rights reserved. 
  4  # 
  5  # This content is made available according to terms specified in 
  6  # License.zenoss under the directory where your Zenoss product is installed. 
  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.interfaces.tree import ICatalogTool 
 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__) 
28 29 30 -class TreeRouter(DirectRouter):
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')
75 - def deleteNode(self, 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 # make sure we are not deleting a root node 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 # Audit first so it can display details like "name" while they exist. 94 # Trac #29148: When we delete a DeviceClass we also delete its devices 95 # and child device classes and their devices, so audit them all. 96 if isinstance(node, DeviceClass): 97 childBrains = ICatalogTool(node).search(( 98 'Products.ZenModel.DeviceClass.DeviceClass', 99 'Products.ZenModel.Device.Device', 100 )) 101 for child in childBrains: 102 audit(['UI', getDisplayType(child), 'Delete'], child.getPath()) 103 elif isinstance(node, System): 104 # update devices systems if the parent system is being removed 105 for dev in facade.getDevices(uid): 106 newSystems = facade._removeOrganizer(node, dev._object.getSystemNames()) 107 dev._object.setSystems(newSystems) 108 audit(['UI', getDisplayType(node), 'Delete'], node) 109 else: 110 audit(['UI', getDisplayType(node), 'Delete'], node) 111 112 facade.deleteNode(uid) 113 msg = "Deleted node '%s'" % uid 114 return DirectResponse.succeed(msg=msg)
115
116 - def moveOrganizer(self, targetUid, organizerUid):
117 """ 118 Move the organizer uid to be underneath the organizer 119 specified by the targetUid. 120 121 @type targetUid: string 122 @param targetUid: New parent of the organizer 123 @type organizerUid: string 124 @param organizerUid: The organizer to move 125 @rtype: DirectResponse 126 @return: B{Properties}: 127 - data: (dictionary) Moved organizer 128 """ 129 facade = self._getFacade() 130 display_type = getDisplayType(facade._getObject(organizerUid)) 131 audit(['UI', display_type, 'Move'], organizerUid, to=targetUid) 132 data = facade.moveOrganizer(targetUid, organizerUid) 133 return DirectResponse.succeed(data=Zuul.marshal(data))
134
135 - def gzip_b64(self, string):
136 """ 137 gzip an arbitrary string, base64 encode it, and return it 138 """ 139 try: 140 compressed = base64.urlsafe_b64encode(zlib.compress(string)) 141 except Exception as e: 142 log.exception(e) 143 return DirectResponse.exception(e, 'Unable to compress data') 144 return DirectResponse.succeed(data=Zuul.marshal({'data': compressed}))
145
146 - def gunzip_b64(self, string):
147 """ 148 Base 64 decode a string, then gunzip it and return the result as JSON. 149 The input to this method should be gzipped, base 64 encoded JSON. Base 150 64 encoded strings are allowed to have up to 2 '='s of padding. The zenoss 151 Ext router eats these, so there is some logic to try padding them back into 152 the string should initial decoding fail. 153 """ 154 data = '' 155 for pad in ('', '=', '=='): 156 try: 157 data = zlib.decompress(base64.urlsafe_b64decode(string + pad)) 158 break 159 except Exception as e: 160 if pad == '==': 161 log.exception(e) 162 return DirectResponse.exception(e, 'Unable to decompress data') 163 return DirectResponse.succeed(data=Zuul.marshal({'data': data}))
164
165 - def _getFacade(self):
166 """ 167 Abstract method for child classes to use to get their facade 168 """ 169 raise NotImplementedError("You must implement the _getFacade method")
170
171 - def asyncGetTree(self, id=None, additionalKeys=()):
172 """ 173 Server side method for asynchronous tree calls. Retrieves 174 the immediate children of the node specified by "id" 175 176 NOTE: our convention on the UI side is if we are asking 177 for the root node then return the root and its children 178 otherwise just return the children 179 180 @type id: string 181 @param id: The uid of the node we are getting the children for 182 @rtype: [dictionary] 183 @return: Object representing the immediate children 184 """ 185 showEventSeverityIcons = self.context.dmd.UserInterfaceSettings.getInterfaceSettings().get('showEventSeverityIcons') 186 facade = self._getFacade() 187 currentNode = facade.getTree(id) 188 # we want every tree property except the "children" one 189 keys = ('id', 'path', 'uid', 'iconCls', 'text', 'hidden', 'leaf') + additionalKeys 190 191 # load the severities in one request 192 childNodes = list(currentNode.children) 193 if showEventSeverityIcons: 194 uuids = [n.uuid for n in childNodes if n.uuid] 195 zep = Zuul.getFacade('zep', self.context.dmd) 196 197 if uuids: 198 severities = zep.getWorstSeverity(uuids) 199 for child in childNodes: 200 if child.uuid: 201 child.setSeverity(zep.getSeverityName(severities.get(child.uuid, 0)).lower()) 202 203 children = [] 204 # explicitly marshall the children 205 for child in childNodes: 206 childData = Marshaller(child).marshal(keys) 207 # set children so that there is not an expanding 208 # icon next to this child 209 # see if there are any subtypes so we can show or not show the 210 # expanding icon without serializing all the children. 211 # Note that this is a performance optimization see ZEN-15857 212 organizer = child._get_object() 213 # this looks at the children's type without waking them up 214 hasChildren = any((o['meta_type'] for o in organizer._objects if o['meta_type'] == organizer.meta_type)) 215 # reports have a different meta_type for the child organizers 216 if "report" not in organizer.meta_type.lower() and not hasChildren: 217 childData['children'] = [] 218 children.append(childData) 219 children.sort(key=lambda e: (e['leaf'], e['uid'].lower())) 220 obj = currentNode._object._unrestrictedGetObject() 221 222 # check to see if we are asking for the root 223 primaryId = obj.getDmdRoot(obj.dmdRootName).getPrimaryId() 224 if id == primaryId: 225 root = Marshaller(currentNode).marshal(keys) 226 root['children'] = children 227 return [root] 228 return children
229
230 - def objectExists(self, uid):
231 """ 232 @rtype: DirectResponse 233 @return: 234 - Properties: 235 - B{exists} - Returns true if we can find the object specified by the uid 236 237 """ 238 from Products.Zuul.facades import ObjectNotFoundException 239 facade = self._getFacade() 240 try: 241 facade._getObject(uid) 242 exists = True 243 except ObjectNotFoundException: 244 exists = False 245 return DirectResponse(success=True, exists=exists)
246
247 - def _canDeleteUid(self, uid):
248 """ 249 We can not delete top level UID's. For example: 250 - '/zport/dmd/Processes' this will return False (we can NOT delete) 251 - '/zport/dmd/Processes/Child' will return True 252 (we can delete this) 253 """ 254 # check the number of levels deep it is 255 levels = len(uid.split('/')) 256 return levels > 4
257