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.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__) 
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 = 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 # update devices systems if the parent system is being removed 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
115 - def moveOrganizer(self, targetUid, organizerUid):
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
134 - def gzip_b64(self, string):
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
145 - def gunzip_b64(self, string):
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
164 - def _getFacade(self):
165 """ 166 Abstract method for child classes to use to get their facade 167 """ 168 raise NotImplementedError("You must implement the _getFacade method")
169
170 - def asyncGetTree(self, id=None, additionalKeys=()):
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 # we want every tree property except the "children" one 188 keys = ('id', 'path', 'uid', 'iconCls', 'text', 'hidden', 'leaf') + additionalKeys 189 190 # load the severities in one request 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 # explicitly marshall the children 204 for child in childNodes: 205 childData = Marshaller(child).marshal(keys) 206 # set children so that there is not an expanding 207 # icon next to this child 208 # see if there are any subtypes so we can show or not show the 209 # expanding icon without serializing all the children. 210 # Note that this is a performance optimization see ZEN-15857 211 organizer = child._get_object() 212 # this looks at the children's type without waking them up 213 hasChildren = any((o['meta_type'] for o in organizer._objects if o['meta_type'] == organizer.meta_type)) 214 # reports have a different meta_type for the child organizers 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 # check to see if we are asking for the root 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
229 - def objectExists(self, uid):
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
246 - def _canDeleteUid(self, uid):
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 # check the number of levels deep it is 254 levels = len(uid.split('/')) 255 return levels > 4
256