googlemap and querytable now use 2 keys
[myslice.git] / portal / sliceview.py
1 from django.template                 import RequestContext
2 from django.shortcuts                import render_to_response
3
4 from unfold.loginrequired            import LoginRequiredAutoLogoutView
5
6 from unfold.page                     import Page
7 from manifold.core.query             import Query, AnalyzedQuery
8
9 from ui.topmenu                      import topmenu_items, the_user
10
11 from plugins.raw                     import Raw
12 from plugins.stack                   import Stack
13 from plugins.tabs                    import Tabs
14 from plugins.querytable              import QueryTable 
15 from plugins.querygrid               import QueryGrid
16 from plugins.queryupdater            import QueryUpdater
17 from plugins.googlemap               import GoogleMap
18 from plugins.senslabmap              import SensLabMap
19 from plugins.scheduler               import Scheduler
20 from plugins.querycode               import QueryCode
21 # Thierry
22 # stay away from query editor for now as it seems to make things go very slow
23 # see https://lists.myslice.info/pipermail/devel-myslice/2013-December/000221.html 
24 #from plugins.query_editor            import QueryEditor
25 from plugins.active_filters          import ActiveFilters
26 from plugins.quickfilter             import QuickFilter
27 from plugins.messages                import Messages
28 from plugins.slicestat               import SliceStat
29
30 from myslice.config                  import Config
31
32 tmp_default_slice='ple.upmc.myslicedemo'
33
34 # temporary : turn off the users part to speed things up
35 #do_query_users=True
36 do_query_users=False
37
38 #do_query_leases=True
39 do_query_leases=False
40
41 insert_grid=False
42 #insert_grid=True
43
44 insert_messages=False
45 #insert_messages=True
46
47 class SliceView (LoginRequiredAutoLogoutView):
48
49     def get (self,request, slicename=tmp_default_slice):
50     
51         page = Page(request)
52         page.add_css_files ('css/slice-view.css')
53         page.add_js_files  ( [ "js/common.functions.js" ] )
54         page.add_js_chunks ('$(function() { messages.debug("sliceview: jQuery version " + $.fn.jquery); });')
55         page.add_js_chunks ('$(function() { messages.debug("sliceview: users turned %s"); });'%("on" if do_query_users else "off"))
56         page.add_js_chunks ('$(function() { messages.debug("sliceview: leases turned %s"); });'%("on" if do_query_leases else "off"))
57         config=Config()
58         page.add_js_chunks ('$(function() { messages.debug("manifold URL %s"); });'%(config.manifold_url()))
59         page.expose_js_metadata()
60     
61         metadata = page.get_metadata()
62         resource_md = metadata.details_by_object('resource')
63         resource_fields = [column['name'] for column in resource_md['column']]
64     
65         user_md = metadata.details_by_object('user')
66         user_fields = ['user_hrn'] # [column['name'] for column in user_md['column']]
67     
68         # TODO The query to run is embedded in the URL
69         main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
70         main_query.select(
71                 'slice_hrn',
72                 #'resource.hrn', 'resource.urn', 
73                 'resource.hostname', 'resource.type', 
74                 'resource.network_hrn',
75                 'lease.urn',
76                 'user.user_hrn',
77                 #'application.measurement_point.counter'
78         )
79         # for internal use in the querytable plugin;
80         # needs to be a unique column present for each returned record
81         main_query_init_key = 'hostname'
82     
83         query_resource_all = Query.get('resource').select(resource_fields)
84         if do_query_users:
85             query_user_all = Query.get('user').select(user_fields)
86     
87         aq = AnalyzedQuery(main_query, metadata=metadata)
88         page.enqueue_query(main_query, analyzed_query=aq)
89         page.enqueue_query(query_resource_all)
90         if do_query_users:
91             page.enqueue_query(query_user_all)
92     
93         # ... and for the relations
94         # XXX Let's hardcode resources for now
95         sq_resource    = aq.subquery('resource')
96         sq_user        = aq.subquery('user')
97         sq_lease       = aq.subquery('lease')
98         sq_measurement = aq.subquery('measurement')
99         
100     
101         # Prepare the display according to all metadata
102         # (some parts will be pending, others can be triggered by users).
103         # 
104         # For example slice measurements will not be requested by default...
105     
106         # Create the base layout (Stack)...
107         main_stack = Stack (
108             page=page,
109             title="Slice %s"%slicename,
110             sons=[],
111         )
112     
113         # ... responsible for the slice properties...
114     
115         # a nice header
116         main_stack.insert (
117             Raw (page=page,
118                  togglable=False, 
119                  toggled=True,
120                  html="<h2 class='well well-lg'> Slice %s</h2>"%slicename)
121         )
122     
123         # --------------------------------------------------------------------------
124         # QueryUpdater (Pending Operations)
125
126         main_stack.insert(QueryUpdater(
127             page                = page,
128             title               = 'Pending operations',
129             query               = main_query,
130             togglable           = True,
131             # start turned off, it will open up itself when stuff comes in
132             toggled             = False, 
133             domid               = 'pending',
134             outline_complete    = True,
135         ))
136
137         # --------------------------------------------------------------------------
138         # Filter Resources
139        
140 # turn off for now -- see above
141 #        filter_query_editor = QueryEditor(
142 #            page  = page,
143 #            query = sq_resource, 
144 #            query_all = query_resource_all,
145 #            title = "Select Columns",
146 #            domid = 'select-columns',
147 #            )
148         filter_active_filters = ActiveFilters(
149             page  = page,
150             query = sq_resource,
151             title = "Active Filters",
152             )
153         filters_area = Stack(
154             page                = page,
155             title               = 'Filter Resources',
156             domid               = 'filters',
157             sons                = [# filter_query_editor, 
158                                    filter_active_filters],
159             togglable           = True,
160             toggled             = 'persistent',
161             outline_complete    = True, 
162         )
163         main_stack.insert (filters_area)
164
165         # --------------------------------------------------------------------------
166         # RESOURCES
167         # the resources part is made of a Tabs (Geographic, List), 
168
169         resources_as_gmap = GoogleMap(
170             page       = page,
171             title      = 'Geographic view',
172             domid      = 'resources-map',
173             # tab's sons preferably turn this off
174             togglable  = False,
175             query      = sq_resource,
176             query_all  = query_resource_all,
177             # this key is the one issued by google
178             googlemap_api_key = Config().googlemap_api_key(),
179             # the key to use at init-time
180             init_key   = main_query_init_key,
181             checkboxes = True,
182             # center on Paris
183             latitude   = 49.,
184             longitude  = 9,
185             zoom       = 4,
186         )
187
188         resources_as_3dmap = SensLabMap(
189             page       = page,
190             title      = '3D Map',
191             domid      = 'senslabmap',
192             query      = sq_resource,
193             query_all  = query_resource_all,
194         )
195
196         resources_as_list = QueryTable( 
197             page       = page,
198             domid      = 'resources-list',
199             title      = 'List view',
200             # this is the query at the core of the slice list
201             query      = sq_resource,
202             query_all  = query_resource_all,
203             # use 'hrn' as the internal unique key for this plugin
204             init_key     = main_query_init_key,
205             checkboxes = True,
206             datatables_options = { 
207                 'iDisplayLength': 25,
208                 'bLengthChange' : True,
209                 'bAutoWidth'    : True,
210                 },
211             )
212
213         if insert_grid:
214             resources_as_grid = QueryGrid( 
215                 page       = page,
216                 domid      = 'resources-grid',
217                 title      = 'Grid view',
218                 # this is the query at the core of the slice list
219                 query      = sq_resource,
220                 query_all  = query_resource_all,
221                 # use 'hrn' as the internal unique key for this plugin
222                 # xxx todo on querygrid as well
223                 # init_key     = main_query_init_key,
224                 checkboxes = True,
225                 )
226
227         if do_query_leases:
228             resources_as_scheduler = Scheduler(
229                 page        = page,
230                 title       = 'Scheduler',
231                 domid       = 'scheduler',
232                 query       = sq_resource,
233                 query_all_resources = query_resource_all,
234                 query_lease = sq_lease,
235                 )
236
237        # with the new 'Filter' stuff on top, no need for anything but the querytable
238         resources_as_list_area = resources_as_list 
239
240         resources_sons = [
241             resources_as_gmap, 
242             resources_as_3dmap,
243             resources_as_scheduler,
244             resources_as_list_area,
245             ] if do_query_leases else [
246             resources_as_gmap, 
247             resources_as_3dmap,
248             resources_as_list_area,
249             ]
250         if insert_grid:
251             resources_sons.append(resources_as_grid)
252
253         resources_area = Tabs ( page=page, 
254                                 domid="resources",
255                                 togglable=True,
256                                 title="Resources",
257                                 outline_complete=True,
258                                 sons= resources_sons,
259                                 active_domid = 'resources-map',
260                                 persistent_active=True,
261                                 )
262         main_stack.insert (resources_area)
263
264         # --------------------------------------------------------------------------
265         # USERS
266     
267         if do_query_users:
268             tab_users = Tabs(
269                 page                = page,
270                 domid               = 'users',
271                 outline_complete    = True,
272                 togglable           = True,
273                 title               = 'Users',
274                 active_domid        = 'users-list',
275                 )
276             main_stack.insert(tab_users)
277     
278             tab_users.insert(QueryTable( 
279                 page        = page,
280                 title       = 'Users List',
281                 domid       = 'users-list',
282                 # tab's sons preferably turn this off
283                 togglable   = False,
284                 # this is the query at the core of the slice list
285                 query       = sq_user,
286                 query_all  = query_user_all,
287                 checkboxes  = True,
288                 datatables_options = { 
289                     'iDisplayLength' : 25,
290                     'bLengthChange'  : True,
291                     'bAutoWidth'     : True,
292                 },
293             ))
294
295 # DEMO    
296         # --------------------------------------------------------------------------
297         # MEASUREMENTS
298         measurements_stats_cpu = SliceStat(
299             title = "CPU Usage",
300             domid = 'resources-stats-cpu',
301             page  = page,
302             stats = 'slice',
303             key   = 'hrn',
304             query = 'none',
305             slicename = slicename,
306             o = 'cpu'
307         )
308         
309         measurements_stats_mem = SliceStat(
310             title = "Memory Usage",
311             domid = 'resources-stats-mem',
312             page  = page,
313             stats = 'slice',
314             key   = 'hrn',
315             query = 'none',
316             slicename = slicename,
317             o = 'mem'
318         )
319         
320         measurements_stats_asb = SliceStat(
321             title = "Traffic Sent",
322             domid = 'resources-stats-asb',
323             page  = page,
324             stats = 'slice',
325             key   = 'hrn',
326             query = 'none',
327             slicename = slicename,
328             o = 'asb'
329         )
330         
331         measurements_stats_arb = SliceStat(
332             title = "Traffic Received",
333             domid = 'resources-stats-arb',
334             page  = page,
335             stats = 'slice',
336             key   = 'hrn',
337             query = 'none',
338             slicename = slicename,
339             o = 'arb'
340         )
341
342         tab_measurements = Tabs ( page=page,
343                                 domid="measurements",
344                                 togglable=True,
345                                 toggled  = False,
346                                 title="Measurements",
347                                 outline_complete=True,
348                                 sons=[ measurements_stats_cpu, measurements_stats_mem, measurements_stats_asb, measurements_stats_arb ],
349                                 active_domid = 'measurements_stats_cpu',
350                                 )
351         main_stack.insert (tab_measurements)
352         
353 #        tab_measurements = Tabs (
354 #            page                = page,
355 #            active_domid        = 'measurements-list',
356 #            outline_complete    = True,
357 #            togglable           = True,
358 #            title               = 'Measurements',
359 #            domid               = 'measurements',
360 #        )
361 #        main_stack.insert(tab_measurements)
362 #    
363 #        tab_measurements.insert(QueryTable( 
364 #            page        = page,
365 #            title       = 'Measurements',
366 #            domid       = 'measurements-list',
367 #            # tab's sons preferably turn this off
368 #            togglable   = False,
369 #            # this is the query at the core of the slice list
370 #            query       = sq_measurement,
371 #            # do NOT set checkboxes to False
372 #            # this table being otherwise empty, it just does not fly with dataTables
373 #            checkboxes  = True,
374 #            datatables_options = { 
375 #                'iDisplayLength' : 25,
376 #                'bLengthChange'  : True,
377 #                'bAutoWidth'     : True,
378 #            },
379 #        ))
380 #    
381 #        # --------------------------------------------------------------------------
382 #        # MESSAGES (we use transient=False for now)
383         if insert_messages:
384             main_stack.insert(Messages(
385                     page   = page,
386                     title  = "Runtime messages for slice %s"%slicename,
387                     domid  = "msgs-pre",
388                     levels = "ALL",
389                     # plain messages are probably less nice for production but more reliable for development for now
390                     transient = False,
391                     # these make sense only in non-transient mode..
392                     togglable = True,
393                     toggled = 'persistent',
394                     outline_complete = True,
395                     ))
396     
397     
398         # variables that will get passed to the view-unfold1.html template
399         template_env = {}
400         
401         # define 'unfold_main' to the template engine - the main contents
402         template_env [ 'unfold_main' ] = main_stack.render(request)
403     
404         # more general variables expected in the template
405         template_env [ 'title' ] = '%(slicename)s'%locals()
406         # the menu items on the top
407         template_env [ 'topmenu_items' ] = topmenu_items('Slice', request) 
408         # so we can sho who is logged
409         template_env [ 'username' ] = the_user (request) 
410     
411         # don't forget to run the requests
412         page.expose_queries ()
413     
414         # xxx create another plugin with the same query and a different layout (with_datatables)
415         # show that it worls as expected, one single api call to backend and 2 refreshed views
416     
417         # the prelude object in page contains a summary of the requirements() for all plugins
418         # define {js,css}_{files,chunks}
419         prelude_env = page.prelude_env()
420         template_env.update(prelude_env)
421         result=render_to_response ('view-unfold1.html',template_env,
422                                    context_instance=RequestContext(request))
423         return result