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