deactivated hide/show validation link in topmenu.py
[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, 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         page.expose_js_metadata()
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', '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_key = 'hrn'
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             googlemap_api_key = Config().googlemap_api_key(),
202             checkboxes = True,
203             # center on Paris
204             latitude   = 49.,
205             longitude  = 9,
206             zoom       = 4,
207         )
208
209         resources_as_3dmap = SensLabMap(
210             page       = page,
211             title      = '3D Map',
212             domid      = 'senslabmap',
213             query      = sq_resource,
214             query_all  = query_resource_all,
215         )
216
217         resources_as_list = QueryTable( 
218             page       = page,
219             domid      = 'resources-list',
220             title      = 'List view',
221             # this is the query at the core of the slice list
222             query      = sq_resource,
223             query_all  = query_resource_all,
224             # safer to use 'hrn' as the internal unique key for this plugin
225             #id_key     = main_query_key,
226             checkboxes = True,
227             datatables_options = { 
228                 'iDisplayLength': 25,
229                 'bLengthChange' : True,
230                 'bAutoWidth'    : True,
231                 },
232             )
233
234         if insert_grid:
235             resources_as_grid = QueryGrid( 
236                 page       = page,
237                 domid      = 'resources-grid',
238                 title      = 'Grid view',
239                 # this is the query at the core of the slice list
240                 query      = sq_resource,
241                 query_all  = query_resource_all,
242                 # safer to use 'hrn' as the internal unique key for this plugin
243                 id_key     = main_query_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         print 40*'+-',"resources_sons has",len(resources_sons),"son"
274
275         resources_area = Tabs ( page=page, 
276                                 domid="resources",
277                                 togglable=True,
278                                 title="Resources",
279                                 outline_complete=True,
280                                 sons= resources_sons,
281                                 active_domid = 'resources-map',
282                                 persistent_active=True,
283                                 )
284         main_stack.insert (resources_area)
285
286         # --------------------------------------------------------------------------
287         # USERS
288     
289         if do_query_users and query_user_all is not None:
290             tab_users = Tabs(
291                 page                = page,
292                 domid               = 'users',
293                 outline_complete    = True,
294                 togglable           = True,
295                 title               = 'Users',
296                 active_domid        = 'users-list',
297                 )
298             main_stack.insert(tab_users)
299     
300             tab_users.insert(QueryTable( 
301                 page        = page,
302                 title       = 'Users List',
303                 domid       = 'users-list',
304                 # tab's sons preferably turn this off
305                 togglable   = False,
306                 # this is the query at the core of the slice list
307                 query       = sq_user,
308                 query_all  = query_user_all,
309                 checkboxes  = True,
310                 datatables_options = { 
311                     'iDisplayLength' : 25,
312                     'bLengthChange'  : True,
313                     'bAutoWidth'     : True,
314                 },
315             ))
316
317 # DEMO    
318         # --------------------------------------------------------------------------
319         # MEASUREMENTS
320         measurements_stats_cpu = SliceStat(
321             title = "CPU Usage",
322             domid = 'resources-stats-cpu',
323             page  = page,
324             stats = 'slice',
325             key   = 'hrn',
326             query = 'none',
327             slicename = slicename,
328             o = 'cpu'
329         )
330         
331         measurements_stats_mem = SliceStat(
332             title = "Memory Usage",
333             domid = 'resources-stats-mem',
334             page  = page,
335             stats = 'slice',
336             key   = 'hrn',
337             query = 'none',
338             slicename = slicename,
339             o = 'mem'
340         )
341         
342         measurements_stats_asb = SliceStat(
343             title = "Traffic Sent",
344             domid = 'resources-stats-asb',
345             page  = page,
346             stats = 'slice',
347             key   = 'hrn',
348             query = 'none',
349             slicename = slicename,
350             o = 'asb'
351         )
352         
353         measurements_stats_arb = SliceStat(
354             title = "Traffic Received",
355             domid = 'resources-stats-arb',
356             page  = page,
357             stats = 'slice',
358             key   = 'hrn',
359             query = 'none',
360             slicename = slicename,
361             o = 'arb'
362         )
363
364         tab_measurements = Tabs ( page=page,
365                                 domid="measurements",
366                                 togglable=True,
367                                 toggled  = False,
368                                 title="Measurements",
369                                 outline_complete=True,
370                                 sons=[ measurements_stats_cpu, measurements_stats_mem, measurements_stats_asb, measurements_stats_arb ],
371                                 active_domid = 'measurements_stats_cpu',
372                                 )
373         main_stack.insert (tab_measurements)
374         
375 #        tab_measurements = Tabs (
376 #            page                = page,
377 #            active_domid        = 'measurements-list',
378 #            outline_complete    = True,
379 #            togglable           = True,
380 #            title               = 'Measurements',
381 #            domid               = 'measurements',
382 #        )
383 #        main_stack.insert(tab_measurements)
384 #    
385 #        tab_measurements.insert(QueryTable( 
386 #            page        = page,
387 #            title       = 'Measurements',
388 #            domid       = 'measurements-list',
389 #            # tab's sons preferably turn this off
390 #            togglable   = False,
391 #            # this is the query at the core of the slice list
392 #            query       = sq_measurement,
393 #            # do NOT set checkboxes to False
394 #            # this table being otherwise empty, it just does not fly with dataTables
395 #            checkboxes  = True,
396 #            datatables_options = { 
397 #                'iDisplayLength' : 25,
398 #                'bLengthChange'  : True,
399 #                'bAutoWidth'     : True,
400 #            },
401 #        ))
402 #    
403 #        # --------------------------------------------------------------------------
404 #        # MESSAGES (we use transient=False for now)
405         if insert_messages:
406             main_stack.insert(Messages(
407                     page   = page,
408                     title  = "Runtime messages for slice %s"%slicename,
409                     domid  = "msgs-pre",
410                     levels = "ALL",
411                     # plain messages are probably less nice for production but more reliable for development for now
412                     transient = False,
413                     # these make sense only in non-transient mode..
414                     togglable = True,
415                     toggled = 'persistent',
416                     outline_complete = True,
417                     ))
418     
419     
420         # variables that will get passed to the view-unfold1.html template
421         template_env = {}
422         
423         # define 'unfold_main' to the template engine - the main contents
424         template_env [ 'unfold_main' ] = main_stack.render(request)
425     
426         # more general variables expected in the template
427         template_env [ 'title' ] = '%(slicename)s'%locals()
428         # the menu items on the top
429         template_env [ 'topmenu_items' ] = topmenu_items('Slice', request) 
430         # so we can sho who is logged
431         template_env [ 'username' ] = the_user (request) 
432     
433         # don't forget to run the requests
434         page.expose_queries ()
435     
436         # xxx create another plugin with the same query and a different layout (with_datatables)
437         # show that it worls as expected, one single api call to backend and 2 refreshed views
438     
439         # the prelude object in page contains a summary of the requirements() for all plugins
440         # define {js,css}_{files,chunks}
441         prelude_env = page.prelude_env()
442         template_env.update(prelude_env)
443         result=render_to_response ('view-unfold1.html',template_env,
444                                    context_instance=RequestContext(request))
445         return result