2 from django.template import RequestContext
3 from django.shortcuts import render_to_response
5 from unfold.loginrequired import LoginRequiredAutoLogoutView
7 from unfold.page import Page
8 from manifold.core.query import Query, AnalyzedQuery
9 from manifold.manifoldapi import execute_query
11 from ui.topmenu import topmenu_items, the_user
13 from plugins.topmenuvalidation import TopmenuValidation
14 from plugins.raw import Raw
15 from plugins.stack import Stack
16 from plugins.tabs import Tabs
17 from plugins.querytable import QueryTable
18 from plugins.querygrid import QueryGrid
19 from plugins.queryupdater import QueryUpdater
20 from plugins.googlemap import GoogleMap
21 from plugins.senslabmap import SensLabMap
22 from plugins.scheduler import Scheduler
23 from plugins.querycode import QueryCode
25 # stay away from query editor for now as it seems to make things go very slow
26 # see https://lists.myslice.info/pipermail/devel-myslice/2013-December/000221.html
27 #from plugins.query_editor import QueryEditor
28 from plugins.active_filters import ActiveFilters
29 from plugins.quickfilter import QuickFilter
30 from plugins.messages import Messages
31 from plugins.slicestat import SliceStat
33 from myslice.config import Config
35 tmp_default_slice='ple.upmc.myslicedemo'
37 # temporary : turn off the users part to speed things up
50 class SliceView (LoginRequiredAutoLogoutView):
52 def get (self,request, slicename=tmp_default_slice):
55 page.add_css_files ('css/slice-view.css')
56 page.add_js_files ( [ "js/common.functions.js" ] )
57 page.add_js_chunks ('$(function() { messages.debug("sliceview: jQuery version " + $.fn.jquery); });')
58 page.add_js_chunks ('$(function() { messages.debug("sliceview: users turned %s"); });'%("on" if do_query_users else "off"))
59 page.add_js_chunks ('$(function() { messages.debug("sliceview: leases turned %s"); });'%("on" if do_query_leases else "off"))
61 page.add_js_chunks ('$(function() { messages.debug("manifold URL %s"); });'%(config.manifold_url()))
63 page.expose_js_metadata()
65 metadata = page.get_metadata()
66 resource_md = metadata.details_by_object('resource')
67 resource_fields = [column['name'] for column in resource_md['column']]
69 user_md = metadata.details_by_object('user')
70 user_fields = ['user_hrn'] # [column['name'] for column in user_md['column']]
72 # TODO The query to run is embedded in the URL
73 main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
76 #'resource.hrn', 'resource.urn',
77 'resource.hostname', 'resource.type',
78 'resource.network_hrn',
81 #'application.measurement_point.counter'
83 # for internal use in the querytable plugin;
84 # needs to be a unique column present for each returned record
85 main_query_init_key = 'hostname'
87 query_resource_all = Query.get('resource').select(resource_fields)
89 aq = AnalyzedQuery(main_query, metadata=metadata)
90 page.enqueue_query(main_query, analyzed_query=aq)
91 page.enqueue_query(query_resource_all)
93 # Required: the user must have an authority in its user.config
94 # XXX Temporary solution
95 user_query = Query().get('local:user').select('config','email')
96 user_details = execute_query(self.request, user_query)
98 # not always found in user_details...
100 # for user_detail in user_details:
101 # #email = user_detail['email']
102 # if user_detail['config']:
103 # config = json.loads(user_detail['config'])
104 # user_detail['authority'] = config.get('authority',"Unknown Authority")
106 # if user_detail['authority'] is not None:
107 # sub_authority = user_detail['authority'].split('.')
108 # root_authority = sub_authority[0]
109 # query_user_all = Query.get(root_authority+':user').select(user_fields)
111 # # XXX TODO this filter doesn't work - to be improved in Manifold
112 # #.filter_by('authority.authority_hrn', '=', user_detail['authority'])
114 # page.enqueue_query(query_user_all)
116 # print "authority of the user is not in local:user db"
117 query_user_all = Query.get('user').select(user_fields)
118 # query_user_all = None
120 # ... and for the relations
121 # XXX Let's hardcode resources for now
122 sq_resource = aq.subquery('resource')
123 sq_user = aq.subquery('user')
124 sq_lease = aq.subquery('lease')
125 sq_measurement = aq.subquery('measurement')
128 # Prepare the display according to all metadata
129 # (some parts will be pending, others can be triggered by users).
131 # For example slice measurements will not be requested by default...
133 # Create the base layout (Stack)...
136 title="Slice %s"%slicename,
140 # ... responsible for the slice properties...
147 html="<h2 class='well well-lg'> Slice %s</h2>"%slicename)
150 # --------------------------------------------------------------------------
151 # QueryUpdater (Pending Operations)
153 main_stack.insert(QueryUpdater(
155 title = 'Pending operations',
158 # start turned off, it will open up itself when stuff comes in
161 outline_complete = True,
164 # --------------------------------------------------------------------------
167 # turn off for now -- see above
168 # filter_query_editor = QueryEditor(
170 # query = sq_resource,
171 # query_all = query_resource_all,
172 # title = "Select Columns",
173 # domid = 'select-columns',
175 filter_active_filters = ActiveFilters(
178 title = "Active Filters",
180 filters_area = Stack(
182 title = 'Filter Resources',
184 sons = [# filter_query_editor,
185 filter_active_filters],
187 toggled = 'persistent',
188 outline_complete = True,
190 main_stack.insert (filters_area)
192 # --------------------------------------------------------------------------
194 # the resources part is made of a Tabs (Geographic, List),
196 resources_as_gmap = GoogleMap(
198 title = 'Geographic view',
199 domid = 'resources-map',
200 # tab's sons preferably turn this off
203 query_all = query_resource_all,
204 # this key is the one issued by google
205 googlemap_api_key = Config().googlemap_api_key(),
206 # the key to use at init-time
207 init_key = main_query_init_key,
215 resources_as_3dmap = SensLabMap(
218 domid = 'senslabmap',
220 query_all = query_resource_all,
223 resources_as_list = QueryTable(
225 domid = 'resources-list',
227 # this is the query at the core of the slice list
229 query_all = query_resource_all,
230 # use 'hrn' as the internal unique key for this plugin
231 init_key = main_query_init_key,
233 datatables_options = {
234 'iDisplayLength': 25,
235 'bLengthChange' : True,
241 resources_as_grid = QueryGrid(
243 domid = 'resources-grid',
245 # this is the query at the core of the slice list
247 query_all = query_resource_all,
248 # use 'hrn' as the internal unique key for this plugin
249 # xxx todo on querygrid as well
250 # init_key = main_query_init_key,
255 resources_as_scheduler = Scheduler(
260 query_all_resources = query_resource_all,
261 query_lease = sq_lease,
264 # with the new 'Filter' stuff on top, no need for anything but the querytable
265 resources_as_list_area = resources_as_list
270 resources_as_scheduler,
271 resources_as_list_area,
272 ] if do_query_leases else [
275 resources_as_list_area,
278 resources_sons.append(resources_as_grid)
280 resources_area = Tabs ( page=page,
284 outline_complete=True,
285 sons= resources_sons,
286 active_domid = 'resources-map',
287 persistent_active=True,
289 main_stack.insert (resources_area)
291 # --------------------------------------------------------------------------
294 if do_query_users and query_user_all is not None:
298 outline_complete = True,
301 active_domid = 'users-list',
303 main_stack.insert(tab_users)
305 tab_users.insert(QueryTable(
307 title = 'Users List',
308 domid = 'users-list',
309 # tab's sons preferably turn this off
311 # this is the query at the core of the slice list
313 query_all = query_user_all,
315 datatables_options = {
316 'iDisplayLength' : 25,
317 'bLengthChange' : True,
323 # --------------------------------------------------------------------------
325 measurements_stats_cpu = SliceStat(
327 domid = 'resources-stats-cpu',
332 slicename = slicename,
336 measurements_stats_mem = SliceStat(
337 title = "Memory Usage",
338 domid = 'resources-stats-mem',
343 slicename = slicename,
347 measurements_stats_asb = SliceStat(
348 title = "Traffic Sent",
349 domid = 'resources-stats-asb',
354 slicename = slicename,
358 measurements_stats_arb = SliceStat(
359 title = "Traffic Received",
360 domid = 'resources-stats-arb',
365 slicename = slicename,
369 tab_measurements = Tabs ( page=page,
370 domid="measurements",
373 title="Measurements",
374 outline_complete=True,
375 sons=[ measurements_stats_cpu, measurements_stats_mem, measurements_stats_asb, measurements_stats_arb ],
376 active_domid = 'measurements_stats_cpu',
378 main_stack.insert (tab_measurements)
380 # tab_measurements = Tabs (
382 # active_domid = 'measurements-list',
383 # outline_complete = True,
385 # title = 'Measurements',
386 # domid = 'measurements',
388 # main_stack.insert(tab_measurements)
390 # tab_measurements.insert(QueryTable(
392 # title = 'Measurements',
393 # domid = 'measurements-list',
394 # # tab's sons preferably turn this off
396 # # this is the query at the core of the slice list
397 # query = sq_measurement,
398 # # do NOT set checkboxes to False
399 # # this table being otherwise empty, it just does not fly with dataTables
401 # datatables_options = {
402 # 'iDisplayLength' : 25,
403 # 'bLengthChange' : True,
404 # 'bAutoWidth' : True,
408 # # --------------------------------------------------------------------------
409 # # MESSAGES (we use transient=False for now)
411 main_stack.insert(Messages(
413 title = "Runtime messages for slice %s"%slicename,
416 # plain messages are probably less nice for production but more reliable for development for now
418 # these make sense only in non-transient mode..
420 toggled = 'persistent',
421 outline_complete = True,
425 # xxx all this should go into a plugin if its own with the topmenu and all...
426 query_pi_auths = Query.get('ple:user').filter_by('user_hrn', '==', '$user_hrn' ).select('pi_authorities')
427 page.enqueue_query(query_pi_auths)
428 # even though this plugin does not have any html materialization, the corresponding domid
429 # must exist because it is searched at init-time to create the JS plugin
430 # so we simply piggy-back the target button here
431 topmenuvalidation = TopmenuValidation (
434 domid='topmenu-validation',
435 query=query_pi_auths,
436 # this one is the target for a $.show() when the query comes back
437 button_domid="topmenu-validation")
438 # although the result does not matter, rendering is required for the JS init code to make it in the page
439 topmenuvalidation.render(request)
440 # end topmenu addition
442 # variables that will get passed to the view-unfold1.html template
445 # define 'unfold_main' to the template engine - the main contents
446 template_env [ 'unfold_main' ] = main_stack.render(request)
448 # more general variables expected in the template
449 template_env [ 'title' ] = '%(slicename)s'%locals()
450 # the menu items on the top
451 template_env [ 'topmenu_items' ] = topmenu_items('Slice', request)
452 # so we can sho who is logged
453 template_env [ 'username' ] = the_user (request)
455 # don't forget to run the requests
456 page.expose_queries ()
458 # xxx create another plugin with the same query and a different layout (with_datatables)
459 # show that it worls as expected, one single api call to backend and 2 refreshed views
461 # the prelude object in page contains a summary of the requirements() for all plugins
462 # define {js,css}_{files,chunks}
463 prelude_env = page.prelude_env()
464 template_env.update(prelude_env)
465 result=render_to_response ('view-unfold1.html',template_env,
466 context_instance=RequestContext(request))