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

Source Code for Module Products.Zuul.routers.report

  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  Operations for Reports. 
 13   
 14  Available at:  /zport/dmd/report_router 
 15  """ 
 16   
 17  import logging 
 18  from itertools import izip_longest 
 19  from Products.ZenMessaging.audit import audit 
 20  from Products.ZenUtils.Ext import DirectResponse 
 21  from Products.Zuul.decorators import require 
 22  from Products.Zuul.marshalling import Marshaller 
 23  from Products.Zuul.utils import ZuulMessageFactory as _t 
 24  from Products.Zuul.routers import TreeRouter 
 25  from Products import Zuul 
 26  from Products.ZenModel.ReportClass import ReportClass 
 27  from Products.ZenModel.BaseReport import BaseReport 
 28  from Products.Zuul.interfaces import ICatalogTool 
 29   
 30  log = logging.getLogger('zen.ReportRouter') 
 31   
 32  reportTypes = [ 
 33      'customDeviceReport', 
 34      'graphReport', 
 35      'multiGraphReport', 
 36  ] 
 37   
 38  menuText = [ 
 39      _t('Custom Device Report'), 
 40      _t('Graph Report'), 
 41      _t('Multi-Graph Report'), 
 42  ] 
 43   
 44  essentialReportOrganizers = [ 
 45      '/zport/dmd/Reports/Custom Device Reports', 
 46      '/zport/dmd/Reports/Graph Reports', 
 47      '/zport/dmd/Reports/Multi-Graph Reports', 
 48      '/zport/dmd/Reports', 
 49  ] 
50 51 -class ReportRouter(TreeRouter):
52 """ 53 A JSON/ExtDirect interface to operations on reports 54 """ 55 56
57 - def __init__(self, context, request):
58 self.api = Zuul.getFacade('reports') 59 self.context = context 60 self.request = request 61 self.keys = ('deletable', 'edit_url', 'isMultiGraphReport', 'isGraphReport', 'columns') 62 super(ReportRouter, self).__init__(context, request)
63
64 - def _getFacade(self):
65 return self.api
66
67 - def getTree(self, id):
68 """ 69 Returns the tree structure of an organizer hierarchy where 70 the root node is the organizer identified by the id parameter. 71 72 @type id: string 73 @param id: Id of the root node of the tree to be returned 74 @rtype: [dictionary] 75 @return: Object representing the tree 76 """ 77 facade = self._getFacade() 78 tree = facade.getTree(id) 79 data = Zuul.marshal(tree) 80 return [data]
81
82 - def getReportTypes(self):
83 """ 84 Get the available report types. 85 86 @rtype: DirectResponse 87 @return: B{Properties}: 88 - menuText: ([string]) Human readable list of report types 89 - reportTypes: ([string]) A list of the available report types 90 """ 91 return DirectResponse.succeed(reportTypes=reportTypes, 92 menuText=menuText)
93
94 - def asyncGetTree(self, id=None):
95 return super(ReportRouter, self).asyncGetTree(id, additionalKeys=self.keys)
96 97 @require('Manage DMD')
98 - def addNode(self, nodeType, contextUid, id):
99 """ 100 Add a new report or report organizer. 101 102 @type nodeType: string 103 @param nodeType: Type of new node. Can either be 'organizer' or one of 104 the report types returned from getReportTypes() 105 @type contextUid: string 106 @param contextUid: The organizer where the new node should be added 107 @type id: string 108 @param id: The new node's ID 109 @rtype: DirectResponse 110 @return: B{Properties}: 111 - tree: (dictionary) Object representing the new Reports tree 112 - newNode: (dictionary) Object representing the added node 113 """ 114 facade = self._getFacade() 115 if nodeType in reportTypes: 116 facade.addReport(nodeType, contextUid, id) 117 audit('UI.Report.Add', contextUid + '/' + id, reporttype=nodeType) 118 else: 119 facade.addOrganizer(contextUid, id, None) 120 audit('UI.Organizer.Add', contextUid + '/' + id) 121 122 return self._getTreeUpdates(contextUid, id)
123 124 @require('Manage DMD')
125 - def deleteNode(self, uid):
126 """ 127 Remove a report or report organizer. 128 129 @type uid: string 130 @param uid: The UID of the node to delete 131 @rtype: [dictionary] 132 @return: B{Properties}: 133 - tree: (dictionary) Object representing the new Reports tree 134 """ 135 # make sure we are not deleting a required node 136 if uid in essentialReportOrganizers: 137 raise Exception('You cannot delete this organizer') 138 139 # Getting all of the child nodes for auditing purposes 140 node = self.context.dmd.unrestrictedTraverse(uid) 141 brains = ICatalogTool(node).search((ReportClass,BaseReport)) 142 family = [] 143 for brain in brains: 144 family.append([brain.getPath(), isinstance(brain.getObject(), ReportClass)]) 145 146 self._getFacade().deleteNode(uid) 147 148 # Audit messaging 149 for name, isOrganizer in family: 150 if isOrganizer: 151 audit('UI.Organizer.Delete', name) 152 else: 153 audit('UI.Report.Delete', name) 154 155 contextUid = '/'.join(uid.split('/')[:-1]) 156 return self._getTreeUpdates(contextUid)
157
158 - def _getTreeUpdates(self, contextUid, newId=None):
159 marshalled = self._marshalPath(contextUid, newId, localKeys=self.keys) 160 for parent, child in zip(marshalled[:-1], marshalled[1:]): 161 parent['children'] = [child] 162 result = {'tree': [marshalled[0]]} 163 if newId: 164 result['newNode'] = marshalled[-1] 165 return DirectResponse.succeed(**result)
166 167 @require('Manage DMD')
168 - def moveNode(self, uid, target):
169 """ 170 Move a report or report organizer from one organizer to another. 171 172 @type uid: string 173 @param uid: The UID of node to move 174 @type target: string 175 @param target: The UID of the target Report organizer 176 @rtype: [dictionary] 177 @return: B{Properties}: 178 - tree: (dictionary) Object representing the new Reports tree 179 - newNode: (dictionary) Object representing the moved node 180 """ 181 self._getFacade().moveNode(uid, target) 182 audit('UI.Report.Move', uid, target=target) 183 return self._treeMoveUpdates(uid, target)
184
185 - def _treeMoveUpdates(self, uid, target):
186 oldPathTokens = uid.split('/') 187 oldPath = '/'.join(oldPathTokens[:-1]) 188 oldBranch = self._marshalPath(oldPath, localKeys=self.keys + ('id', 'children')) 189 newId = oldPathTokens[-1] 190 newBranch = self._marshalPath(target, newId, localKeys=self.keys + ('id', 'children')) 191 for newParent, newChild, oldParent, oldChild in izip_longest(newBranch[:-1], newBranch[1:], oldBranch[:-1], oldBranch[1:], fillvalue=None): 192 if newParent and oldParent and newParent['id'] != oldParent['id']: 193 newParent['children'] = [newChild] 194 oldParent['children'] = [oldChild] 195 else: 196 parent = newParent if newParent else oldParent 197 if newChild and oldChild and newChild['id'] != oldChild['id']: 198 parent['children'] = [oldChild, newChild] 199 else: 200 child = newChild if newChild else oldChild 201 parent['children'] = [child] 202 tree = [newBranch[0]] 203 if oldBranch[0]['id'] != newBranch[0]['id']: 204 tree.append(oldBranch[0]) 205 #newNode = newBranch[-1] 206 return DirectResponse.succeed()
207
208 - def _marshalPath(self, contextUid, newId=None, localKeys=None):
209 tokens = contextUid.split('/') 210 if newId: 211 tokens.append(newId) 212 paths = [] 213 # ["", "zport", "dmd", "Reports", <new node or an ancestor, at 4>, ...] 214 for x in range(4, len(tokens) + 1): 215 paths.append('/'.join(tokens[:x])) 216 nodes = [self._getFacade().getTree(id) for id in paths] 217 return [Marshaller(node).marshal(localKeys) for node in nodes]
218
219 - def _correctReportTitles(self, data):
220 data = Zuul.marshal(data) 221 # show the context in the report title, otherwise the user 222 # has no idea which component the graph is for 223 for row in data: 224 row['title'] = row['contextTitle'] 225 return DirectResponse(data=data)
226
227 - def getGraphReportDefs(self, uid, drange=None):
228 """ 229 Returns the json necessary for rendering graphs with the metric 230 service for each component in the graph definition. 231 @type uid: string 232 @param uid: unique identifier of an object 233 """ 234 facade = self._getFacade() 235 return self._correctReportTitles(facade.getGraphReportDefs(uid))
236
237 - def getMultiGraphReportDefs(self, uid, drange=None):
238 """ 239 Gets the json necessary for rendering graphs with the metric services 240 for multi graph reports. 241 @type uid: string 242 @param uid: unique identifier of an object 243 """ 244 facade = self._getFacade() 245 return self._correctReportTitles(facade.getMultiGraphReportDefs(uid))
246