Chrysostomos for scheduler
[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.scheduler2              import Scheduler2
23 from plugins.querycode               import QueryCode
24 # Thierry
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
32
33 from myslice.configengine            import ConfigEngine
34
35 tmp_default_slice='ple.upmc.myslicedemo'
36
37 # temporary : turn off the users part to speed things up
38 #do_query_users=True
39 do_query_users=False
40
41 #do_query_leases=True
42 do_query_leases=False
43
44 insert_grid=False
45 #insert_grid=True
46
47 insert_messages=False
48 #insert_messages=True
49
50 class SliceView (LoginRequiredAutoLogoutView):
51
52     def get (self,request, slicename=tmp_default_slice):
53     
54         page = Page(request)
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"))
60         page.add_js_chunks ('$(function() { messages.debug("manifold URL %s"); });'%(ConfigEngine().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 = ConfigEngine().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             init_key     = main_query_init_key,
228             checkboxes = True,
229             datatables_options = { 
230                 'iDisplayLength': 25,
231                 'bLengthChange' : True,
232                 'bAutoWidth'    : True,
233                 },
234             )
235
236         if insert_grid:
237             resources_as_grid = QueryGrid( 
238                 page       = page,
239                 domid      = 'resources-grid',
240                 title      = 'Grid view',
241                 # this is the query at the core of the slice list
242                 query      = sq_resource,
243                 query_all  = query_resource_all,
244                 init_key     = main_query_init_key,
245                 checkboxes = True,
246                 )
247
248         
249
250         #if do_query_leases:
251         #    resources_as_scheduler = Scheduler(
252
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
262         resources_as_scheduler2 = Scheduler2( 
263             page       = page,
264             domid      = 'scheduler',
265             title      = 'Scheduler',
266             # this is the query at the core of the slice list
267             query = sq_resource,
268             query_all_resources = query_resource_all,
269             query_lease = sq_lease,
270             )
271
272        # with the new 'Filter' stuff on top, no need for anything but the querytable
273         resources_as_list_area = resources_as_list 
274
275         resources_sons = [
276             resources_as_gmap, 
277             resources_as_3dmap,
278             resources_as_scheduler2,
279             resources_as_list_area,
280             ] if do_query_leases else [
281             resources_as_gmap, 
282             resources_as_3dmap,
283             resources_as_list_area,
284             resources_as_scheduler2,
285             ]
286         if insert_grid:
287             resources_sons.append(resources_as_grid)
288
289         resources_area = Tabs ( page=page, 
290                                 domid="resources",
291                                 togglable=True,
292                                 title="Resources",
293                                 outline_complete=True,
294                                 sons= resources_sons,
295
296                                 active_domid = 'scheduler',
297                                 persistent_active=True,
298                                 )
299         main_stack.insert (resources_area)
300
301         # --------------------------------------------------------------------------
302         # USERS
303     
304         if do_query_users and query_user_all is not None:
305             tab_users = Tabs(
306                 page                = page,
307                 domid               = 'users',
308                 outline_complete    = True,
309                 togglable           = True,
310                 title               = 'Users',
311                 active_domid        = 'users-list',
312                 )
313             main_stack.insert(tab_users)
314     
315             tab_users.insert(QueryTable( 
316                 page        = page,
317                 title       = 'Users List',
318                 domid       = 'users-list',
319                 # tab's sons preferably turn this off
320                 togglable   = False,
321                 # this is the query at the core of the slice list
322                 query       = sq_user,
323                 query_all  = query_user_all,
324                 checkboxes  = True,
325                 datatables_options = { 
326                     'iDisplayLength' : 25,
327                     'bLengthChange'  : True,
328                     'bAutoWidth'     : True,
329                 },
330             ))
331
332 # DEMO    
333         # --------------------------------------------------------------------------
334         # MEASUREMENTS
335         measurements_stats_cpu = SliceStat(
336             title = "CPU Usage",
337             domid = 'resources-stats-cpu',
338             page  = page,
339             stats = 'slice',
340             key   = 'hrn',
341             query = 'none',
342             slicename = slicename,
343             o = 'cpu'
344         )
345         
346         measurements_stats_mem = SliceStat(
347             title = "Memory Usage",
348             domid = 'resources-stats-mem',
349             page  = page,
350             stats = 'slice',
351             key   = 'hrn',
352             query = 'none',
353             slicename = slicename,
354             o = 'mem'
355         )
356         
357         measurements_stats_asb = SliceStat(
358             title = "Traffic Sent",
359             domid = 'resources-stats-asb',
360             page  = page,
361             stats = 'slice',
362             key   = 'hrn',
363             query = 'none',
364             slicename = slicename,
365             o = 'asb'
366         )
367         
368         measurements_stats_arb = SliceStat(
369             title = "Traffic Received",
370             domid = 'resources-stats-arb',
371             page  = page,
372             stats = 'slice',
373             key   = 'hrn',
374             query = 'none',
375             slicename = slicename,
376             o = 'arb'
377         )
378
379         tab_measurements = Tabs ( page=page,
380                                 domid = "measurements",
381                                 togglable = True,
382                                 toggled = 'persistent',
383                                 title = "Measurements",
384                                 outline_complete=True,
385                                 sons = [ measurements_stats_cpu, measurements_stats_mem, measurements_stats_asb, measurements_stats_arb ],
386                                 active_domid = 'resources-stats-cpu',
387                                 persistent_active = True,
388                                 )
389         main_stack.insert (tab_measurements)
390         
391 #        tab_measurements = Tabs (
392 #            page                = page,
393 #            active_domid        = 'measurements-list',
394 #            outline_complete    = True,
395 #            togglable           = True,
396 #            title               = 'Measurements',
397 #            domid               = 'measurements',
398 #        )
399 #        main_stack.insert(tab_measurements)
400 #    
401 #        tab_measurements.insert(QueryTable( 
402 #            page        = page,
403 #            title       = 'Measurements',
404 #            domid       = 'measurements-list',
405 #            # tab's sons preferably turn this off
406 #            togglable   = False,
407 #            # this is the query at the core of the slice list
408 #            query       = sq_measurement,
409 #            # do NOT set checkboxes to False
410 #            # this table being otherwise empty, it just does not fly with dataTables
411 #            checkboxes  = True,
412 #            datatables_options = { 
413 #                'iDisplayLength' : 25,
414 #                'bLengthChange'  : True,
415 #                'bAutoWidth'     : True,
416 #            },
417 #        ))
418 #    
419 #        # --------------------------------------------------------------------------
420 #        # MESSAGES (we use transient=False for now)
421         if insert_messages:
422             main_stack.insert(Messages(
423                     page   = page,
424                     title  = "Runtime messages for slice %s"%slicename,
425                     domid  = "msgs-pre",
426                     levels = "ALL",
427                     # plain messages are probably less nice for production but more reliable for development for now
428                     transient = False,
429                     # these make sense only in non-transient mode..
430                     togglable = True,
431                     toggled = 'persistent',
432                     outline_complete = True,
433                     ))
434     
435         # variables that will get passed to the view-unfold1.html template
436         template_env = {}
437         
438         # define 'unfold_main' to the template engine - the main contents
439         template_env [ 'unfold_main' ] = main_stack.render(request)
440     
441         # more general variables expected in the template
442         template_env [ 'title' ] = '%(slicename)s'%locals()
443         # the menu items on the top
444         template_env [ 'topmenu_items' ] = topmenu_items_live('Slice', page) 
445         # so we can sho who is logged
446         template_env [ 'username' ] = the_user (request) 
447     
448         # don't forget to run the requests
449         page.expose_js_metadata()
450         # the prelude object in page contains a summary of the requirements() for all plugins
451         # define {js,css}_{files,chunks}
452         template_env.update(page.prelude_env())
453
454         return render_to_response ('view-unfold1.html',template_env,
455                                    context_instance=RequestContext(request))