PageRenderTime 57ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/python/nav/web/report/handler.py

https://bitbucket.org/m_eide/nav-3.9.x
Python | 376 lines | 338 code | 19 blank | 19 comment | 11 complexity | a0e984369ce66a4a8b16e09763ef2132 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, Apache-2.0, AGPL-1.0
  1. #
  2. # Copyright (C) 2003-2005 Norwegian University of Science and Technology
  3. # Copyright (C) 2008-2011 UNINETT AS
  4. #
  5. # This file is part of Network Administration Visualized (NAV).
  6. #
  7. # NAV is free software: you can redistribute it and/or modify it under
  8. # the terms of the GNU General Public License version 2 as published by
  9. # the Free Software Foundation.
  10. #
  11. # This program is distributed in the hope that it will be useful, but WITHOUT ANY
  12. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  13. # PARTICULAR PURPOSE. See the GNU General Public License for more details.
  14. # You should have received a copy of the GNU General Public License along with
  15. # NAV. If not, see <http://www.gnu.org/licenses/>.
  16. #
  17. """Handling web requests for the Report subsystem."""
  18. from IPy import IP
  19. try:
  20. from mod_python import apache
  21. except ImportError:
  22. apache = None
  23. from operator import itemgetter
  24. from time import localtime, strftime
  25. import copy
  26. import csv
  27. import os
  28. import os.path
  29. import re
  30. import string
  31. import urllib
  32. os.environ['DJANGO_SETTINGS_MODULE'] = 'nav.django.settings'
  33. from django.core.cache import cache
  34. from IPy import IP
  35. from nav import db
  36. from nav.report.IPtree import getMaxLeaf, buildTree
  37. from nav.report.generator import Generator, ReportList
  38. from nav.report.matrixIPv4 import MatrixIPv4
  39. from nav.report.matrixIPv6 import MatrixIPv6
  40. from nav.report.metaIP import MetaIP
  41. from nav.web import redirect
  42. from nav.web import state
  43. from nav.web.URI import URI
  44. from nav.web.templates.MatrixScopesTemplate import MatrixScopesTemplate
  45. from nav.web.templates.ReportListTemplate import ReportListTemplate
  46. from nav.web.templates.ReportTemplate import ReportTemplate, MainTemplate
  47. from nav.web.encoding import encoded_output
  48. import nav.path
  49. config_file_package = os.path.join(nav.path.sysconfdir, "report/report.conf")
  50. config_file_local = os.path.join(nav.path.sysconfdir, "report/report.local.conf")
  51. frontFile = os.path.join(nav.path.sysconfdir, "report/front.html")
  52. @encoded_output
  53. def handler(req):
  54. (report_name, export_delimiter, uri, nuri) = arg_parsing(req)
  55. if report_name == "report" or report_name == "index":
  56. page = MainTemplate()
  57. req.content_type = "text/html"
  58. req.send_http_header()
  59. page.path = [("Home", "/"), ("Report", False)]
  60. page.title = "Report - Index"
  61. page.content = lambda:file(frontFile).read()
  62. req.write(page.respond())
  63. elif report_name == "matrix":
  64. matrix_report(req)
  65. elif report_name == "reportlist":
  66. report_list(req)
  67. else:
  68. make_report(req, report_name, export_delimiter, uri, nuri)
  69. return apache.OK
  70. def arg_parsing(req):
  71. uri = req.unparsed_uri
  72. nuri = URI(uri)
  73. export_delimiter = None
  74. # These arguments and their friends will be deleted
  75. remove = []
  76. # Finding empty values
  77. for key, val in nuri.args.items():
  78. if val == "":
  79. remove.append(key)
  80. if 'exportcsv' in nuri.args and 'export' in nuri.args:
  81. delimiter = urllib.unquote(nuri.args['export'])
  82. # Remember to match against 'page.delimiters'
  83. match = re.search("(\,|\;|\:|\|)", delimiter)
  84. if match:
  85. export_delimiter = match.group(0)
  86. else:
  87. remove.append('export')
  88. remove.append('exportcsv')
  89. # Deleting empty values
  90. for r in remove:
  91. if nuri.args.has_key(r):
  92. del(nuri.args[r])
  93. if nuri.args.has_key("op_"+r):
  94. del(nuri.args["op_"+r])
  95. if nuri.args.has_key("not_"+r):
  96. del(nuri.args["not_"+r])
  97. # Redirect if any arguments were removed
  98. if len(remove):
  99. redirect(req, nuri.make())
  100. match = re.search("\/(\w+?)(?:\/$|\?|\&|$)", req.uri)
  101. if match:
  102. report_name = match.group(1)
  103. else:
  104. report_name = "report"
  105. return (report_name, export_delimiter, uri, nuri)
  106. def matrix_report(req):
  107. req.content_type = "text/html"
  108. req.send_http_header()
  109. ## Parameterdictionary
  110. argsdict = {}
  111. if req.args:
  112. reqargsplit = urllib.unquote_plus(req.args).split("&")
  113. if len(reqargsplit):
  114. for a in reqargsplit:
  115. (c, d) = a.split("=")
  116. argsdict[c] = d
  117. scope = None
  118. if argsdict.has_key("scope") and argsdict["scope"]:
  119. scope = IP(argsdict["scope"])
  120. else:
  121. # Find all scopes in database.
  122. connection = db.getConnection('webfront','manage')
  123. database = connection.cursor()
  124. database.execute("SELECT netaddr FROM prefix INNER JOIN vlan USING (vlanid) WHERE nettype='scope'")
  125. databasescopes = database.fetchall()
  126. if len(databasescopes) == 1:
  127. # If there is a single scope in the db, display that
  128. scope = IP(databasescopes[0][0])
  129. else:
  130. # Otherwise, show an error or let the user select from
  131. # a list of scopes.
  132. page = MatrixScopesTemplate()
  133. page.path = [("Home", "/"), ("Report", "/report/"),
  134. ("Prefix Matrix", False)]
  135. page.scopes = []
  136. for scope in databasescopes:
  137. page.scopes.append(scope[0])
  138. req.write(page.respond())
  139. return apache.OK
  140. # If a single scope has been selected, display that.
  141. if scope is not None:
  142. show_unused_addresses = True
  143. if argsdict.has_key("show_unused_addresses"):
  144. boolstring = argsdict["show_unused_addresses"]
  145. if boolstring == "True":
  146. show_unused_addresses = True
  147. elif boolstring == "False":
  148. show_unused_addresses = False
  149. matrix = None
  150. tree = buildTree(scope)
  151. if scope.version() == 6:
  152. end_net = getMaxLeaf(tree)
  153. matrix = MatrixIPv6(scope, end_net=end_net)
  154. elif scope.version() == 4:
  155. end_net = None
  156. if scope.prefixlen() < 24:
  157. end_net = IP("/".join([scope.net().strNormal(),"27"]))
  158. matrix = MatrixIPv4(scope, show_unused_addresses,
  159. end_net=end_net)
  160. else:
  161. max_leaf = getMaxLeaf(tree)
  162. bits_in_matrix = max_leaf.prefixlen()-scope.prefixlen()
  163. matrix = MatrixIPv4(scope, show_unused_addresses,
  164. end_net=max_leaf,
  165. bits_in_matrix=bits_in_matrix)
  166. else:
  167. raise UnknownNetworkTypeException, "version: " + str(scope.version())
  168. req.write(matrix.getTemplateResponse())
  169. # Invalidating the MetaIP cache to get rid of processed data.
  170. MetaIP.invalidateCache()
  171. def report_list(req):
  172. page = ReportListTemplate()
  173. req.content_type = "text/html"
  174. req.send_http_header()
  175. # Default config
  176. report_list = ReportList(config_file_package).getReportList()
  177. map(itemgetter(1), report_list)
  178. report_list = sorted(report_list, key=itemgetter(1))
  179. # Local config
  180. report_list_local = ReportList(config_file_local).getReportList()
  181. map(itemgetter(1), report_list_local)
  182. report_list_local = sorted(report_list_local, key=itemgetter(1))
  183. name = "Report List"
  184. name_link = "reportlist"
  185. page.path = [("Home", "/"), ("Report", "/report/"), (name, "/report/" + name_link)]
  186. page.title = "Report - " + name
  187. page.report_list = report_list
  188. page.report_list_local = report_list_local
  189. req.write(page.respond())
  190. def make_report(req, report_name, export_delimiter, uri, nuri):
  191. # Initiating variables used when caching
  192. report = contents = neg = operator = adv = dbresult = result_time = None
  193. # Deleting meta variables from uri to help identifying if the report
  194. # asked for is in the cache or not.
  195. nuri.setArguments(['offset', 'limit', 'export', 'exportcsv'], '')
  196. for key, val in nuri.args.items():
  197. if val == "":
  198. del nuri.args[key]
  199. uri_strip = nuri.make()
  200. username = req.session['user']['login']
  201. mtime_config = os.stat(config_file_package).st_mtime + os.stat(config_file_local).st_mtime
  202. cache_name = 'report_' + username + '_' + str(mtime_config)
  203. gen = Generator()
  204. # Caching. Checks if cache exists for this user, that the cached report is
  205. # the one requested and that config files are unchanged.
  206. if cache.get(cache_name) and cache.get(cache_name)[0] == uri_strip:
  207. report_cache = cache.get(cache_name)
  208. dbresult_cache = report_cache[7]
  209. config_cache = report_cache[6]
  210. (report, contents, neg, operator, adv) = gen.makeReport(report_name, None, None, uri, config_cache, dbresult_cache)
  211. result_time = cache.get(cache_name)[8]
  212. dbresult = dbresult_cache
  213. else: # Report not in cache, fetch data from DB
  214. (report, contents, neg, operator, adv, config, dbresult) = gen.makeReport(report_name, config_file_package, config_file_local, uri, None, None)
  215. result_time = strftime("%H:%M:%S", localtime())
  216. cache.set(cache_name, (uri_strip, report, contents, neg, operator, adv, config, dbresult, result_time))
  217. if export_delimiter:
  218. generate_export(req, report, report_name, export_delimiter)
  219. else:
  220. req.content_type = "text/html"
  221. req.send_http_header()
  222. page = ReportTemplate()
  223. page.result_time = result_time
  224. page.report = report
  225. page.contents = contents
  226. page.operator = operator
  227. page.neg = neg
  228. namename = ""
  229. if report:
  230. namename = report.title
  231. if not namename:
  232. namename = report_name
  233. namelink = "/report/"+report_name
  234. else:
  235. namename = "Error"
  236. namelink = False
  237. page.path = [("Home", "/"), ("Report", "/report/"),
  238. (namename, namelink)]
  239. page.title = "Report - "+namename
  240. old_uri = req.unparsed_uri
  241. page.old_uri = old_uri
  242. if adv:
  243. page.adv_block = True
  244. else:
  245. page.adv_block = False
  246. if report:
  247. if old_uri.find("?")>0:
  248. old_uri += "&"
  249. else:
  250. old_uri += "?"
  251. page.old_uri = old_uri
  252. #### A maintainable list of variables sent to template
  253. # Searching
  254. page.operators = {"eq": "=",
  255. "like": "~",
  256. "gt": "&gt;",
  257. "lt": "&lt;",
  258. "geq": "&gt;=",
  259. "leq": "&lt;=",
  260. "between": "[:]",
  261. "in":"(,,)",
  262. }
  263. page.operatorlist = ["eq", "like", "gt", "lt", "geq", "leq",
  264. "between", "in"]
  265. page.descriptions = {
  266. "eq": "equals",
  267. "like": "contains substring (case-insensitive)",
  268. "gt": "greater than",
  269. "lt": "less than",
  270. "geq": "greater than or equals",
  271. "leq": "less than or equals",
  272. "between": "between (colon-separated)",
  273. "in":"is one of (comma separated)",
  274. }
  275. # CSV Export dialects/delimiters
  276. page.delimiters = (",", ";", ":", "|")
  277. req.write(page.respond())
  278. def generate_export(req, report, report_name, export_delimiter):
  279. req.content_type = "text/x-csv"
  280. req.headers_out["Content-Type"] = "application/force-download"
  281. req.headers_out["Content-Disposition"] = "attachment; filename=report-%s-%s.csv" % (report_name, strftime("%Y%m%d", localtime()))
  282. req.send_http_header()
  283. writer = csv.writer(req, delimiter=export_delimiter)
  284. rows = []
  285. # Make a list of headers
  286. header_row = []
  287. for cell in report.table.header.cells:
  288. header_row.append(cell.text)
  289. writer.writerow(header_row)
  290. # Make a list of lists containing each cell. Considers the 'hidden' option from the config.
  291. for row in report.table.rows:
  292. tmp_row = []
  293. for cell in row.cells:
  294. tmp_row.append(cell.text)
  295. rows.append(tmp_row)
  296. writer.writerows(rows)
  297. req.write("")
  298. class UnknownNetworkTypeException(Exception): pass