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