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