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