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