Merge branch 'master' into scheduler
[myslice.git] / portal / sliceview.py
1 from django.template                 import RequestContext
2 from django.shortcuts                import render_to_response
3
4 from unfold.loginrequired            import LoginRequiredAutoLogoutView
5
6 from unfold.page                     import Page
7 from manifold.core.query             import Query, AnalyzedQuery
8
9 from ui.topmenu                      import topmenu_items, the_user
10
11 from plugins.raw                     import Raw
12 from plugins.stack                   import Stack
13 from plugins.tabs                    import Tabs
14 from plugins.querytable              import QueryTable 
15 from plugins.queryupdater            import QueryUpdater
16 from plugins.googlemap               import GoogleMap
17 from plugins.senslabmap              import SensLabMap
18 from plugins.scheduler               import Scheduler
19 from plugins.querycode               import QueryCode
20 from plugins.query_editor            import QueryEditor
21 from plugins.active_filters          import ActiveFilters
22 from plugins.quickfilter             import QuickFilter
23 from plugins.messages                import Messages
24 from plugins.slicestat               import SliceStat
25
26 from myslice.config                  import Config
27
28 tmp_default_slice='ple.upmc.myslicedemo'
29
30 # temporary : turn off the users part to speed things up
31 #do_query_users=True
32 do_query_users=False
33
34 insert_messages=False
35 #insert_messages=True
36
37 class SliceView (LoginRequiredAutoLogoutView):
38
39     def get (self,request, slicename=tmp_default_slice):
40     
41         page = Page(request)
42         page.add_css_files ('css/slice-view.css')
43         page.add_js_files  ( [ "js/common.functions.js" ] )
44         page.add_js_chunks ('$(function() { messages.debug("sliceview: jQuery version " + $.fn.jquery); });')
45         page.add_js_chunks ('$(function() { messages.debug("sliceview: users turned %s"); });'%("on" if do_query_users else "off"))
46         config=Config()
47         page.add_js_chunks ('$(function() { messages.debug("manifold URL %s"); });'%(config.manifold_url()))
48         page.expose_js_metadata()
49     
50         metadata = page.get_metadata()
51         resource_md = metadata.details_by_object('resource')
52         resource_fields = [column['name'] for column in resource_md['column']]
53     
54         user_md = metadata.details_by_object('user')
55         user_fields = ['user_hrn'] # [column['name'] for column in user_md['column']]
56     
57         # TODO The query to run is embedded in the URL
58         main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
59         main_query.select(
60                 'slice_hrn',
61                 'resource.hrn', 'resource.hostname', 'resource.type', 
62                 'resource.network_hrn',
63                 'lease.urn',
64                 'user.user_hrn',
65                 #'application.measurement_point.counter'
66         )
67     
68         query_resource_all = Query.get('resource').select(resource_fields)
69         if do_query_users:
70             query_user_all = Query.get('user').select(user_fields)
71     
72         aq = AnalyzedQuery(main_query, metadata=metadata)
73         page.enqueue_query(main_query, analyzed_query=aq)
74         page.enqueue_query(query_resource_all)
75         if do_query_users:
76             page.enqueue_query(query_user_all)
77     
78         # ... and for the relations
79         # XXX Let's hardcode resources for now
80         sq_resource    = aq.subquery('resource')
81         sq_user        = aq.subquery('user')
82         sq_lease       = aq.subquery('lease')
83         sq_measurement = aq.subquery('measurement')
84         
85     
86         # Prepare the display according to all metadata
87         # (some parts will be pending, others can be triggered by users).
88         # 
89         # For example slice measurements will not be requested by default...
90     
91         # Create the base layout (Stack)...
92         main_stack = Stack (
93             page=page,
94             title="Slice %s"%slicename,
95             sons=[],
96         )
97     
98         # ... responsible for the slice properties...
99     
100         # a nice header
101         main_stack.insert (
102             Raw (page=page,
103                  togglable=False, 
104                  toggled=True,
105                  html="<h2 class='well well-lg'> Slice %s</h2>"%slicename)
106         )
107     
108         # --------------------------------------------------------------------------
109         # QueryUpdater (Pending Operations)
110
111         main_stack.insert(QueryUpdater(
112             page                = page,
113             title               = 'Pending operations',
114             query               = main_query,
115             togglable           = True,
116             # start turned off, it will open up itself when stuff comes in
117             toggled             = False, 
118             domid               = 'pending',
119             outline_complete    = True,
120         ))
121
122         # --------------------------------------------------------------------------
123         # Filter Resources
124        
125         filter_query_editor = QueryEditor(
126             page  = page,
127             query = sq_resource, 
128             query_all = query_resource_all,
129             title = "Select Columns",
130             domid = 'select-columns',
131             )
132         filter_active_filters = ActiveFilters(
133             page  = page,
134             query = sq_resource,
135             title = "Active Filters",
136             )
137         filters_area = Stack(
138             page                = page,
139             title               = 'Filter Resources',
140             domid               = 'filters',
141             sons                = [filter_query_editor, filter_active_filters],
142             togglable           = True,
143             toggled             = 'persistent',
144             outline_complete    = True, 
145         )
146         main_stack.insert (filters_area)
147
148         # --------------------------------------------------------------------------
149         # RESOURCES
150         # the resources part is made of a Tabs (Geographic, List), 
151
152         resources_as_gmap = GoogleMap(
153             page       = page,
154             title      = 'Geographic view',
155             domid      = 'resources-map',
156             # tab's sons preferably turn this off
157             togglable  = False,
158             query      = sq_resource,
159             query_all  = query_resource_all,
160             googlemap_api_key = Config().googlemap_api_key(),
161             checkboxes = True,
162             # center on Paris
163             latitude   = 49.,
164             longitude  = 9,
165             zoom       = 4,
166         )
167
168         resources_as_3dmap = SensLabMap(
169             page       = page,
170             title      = '3D Map',
171             domid      = 'senslabmap',
172             query      = sq_resource,
173             query_all  = query_resource_all,
174         )
175
176         resources_as_list = QueryTable( 
177             page       = page,
178             domid      = 'resources-list',
179             title      = 'List view',
180             # this is the query at the core of the slice list
181             query      = sq_resource,
182             query_all  = query_resource_all,
183             checkboxes = True,
184             datatables_options = { 
185                 'iDisplayLength': 25,
186                 'bLengthChange' : True,
187                 'bAutoWidth'    : True,
188                 },
189             )
190
191         resources_as_scheduler = Scheduler(
192             page        = page,
193             title       = 'Scheduler',
194             domid       = 'scheduler',
195             query       = sq_resource,
196             query_all_resources = query_resource_all,
197             query_lease = sq_lease,
198         )
199
200        # with the new 'Filter' stuff on top, no need for anything but the querytable
201         resources_as_list_area = resources_as_list 
202
203         resources_area = Tabs ( page=page, 
204                                 domid="resources",
205                                 togglable=True,
206                                 title="Resources",
207                                 outline_complete=True,
208                                 sons=[ 
209                                        resources_as_scheduler,
210                                        #resources_as_gmap, 
211                                        #resources_as_3dmap,
212                                        resources_as_list_area, ],
213                                 active_domid = 'resources-map',
214                                 persistent_active=True,
215                                 )
216         main_stack.insert (resources_area)
217
218         # --------------------------------------------------------------------------
219         # USERS
220     
221         if do_query_users:
222             tab_users = Tabs(
223                 page                = page,
224                 domid               = 'users',
225                 outline_complete    = True,
226                 togglable           = True,
227                 title               = 'Users',
228                 active_domid        = 'users-list',
229                 )
230             main_stack.insert(tab_users)
231     
232             tab_users.insert(QueryTable( 
233                 page        = page,
234                 title       = 'Users List',
235                 domid       = 'users-list',
236                 # tab's sons preferably turn this off
237                 togglable   = False,
238                 # this is the query at the core of the slice list
239                 query       = sq_user,
240                 query_all  = query_user_all,
241                 checkboxes  = True,
242                 datatables_options = { 
243                     'iDisplayLength' : 25,
244                     'bLengthChange'  : True,
245                     'bAutoWidth'     : True,
246                 },
247             ))
248
249 # DEMO    
250         # --------------------------------------------------------------------------
251         # MEASUREMENTS
252         measurements_stats_cpu = SliceStat(
253             title = "CPU Usage",
254             domid = 'resources-stats-cpu',
255             page  = page,
256             stats = 'slice',
257             key   = 'hrn',
258             query = 'none',
259             slicename = slicename,
260             o = 'cpu'
261         )
262         
263         measurements_stats_mem = SliceStat(
264             title = "Memory Usage",
265             domid = 'resources-stats-mem',
266             page  = page,
267             stats = 'slice',
268             key   = 'hrn',
269             query = 'none',
270             slicename = slicename,
271             o = 'mem'
272         )
273         
274         measurements_stats_asb = SliceStat(
275             title = "Traffic Sent",
276             domid = 'resources-stats-asb',
277             page  = page,
278             stats = 'slice',
279             key   = 'hrn',
280             query = 'none',
281             slicename = slicename,
282             o = 'asb'
283         )
284         
285         measurements_stats_arb = SliceStat(
286             title = "Traffic Received",
287             domid = 'resources-stats-arb',
288             page  = page,
289             stats = 'slice',
290             key   = 'hrn',
291             query = 'none',
292             slicename = slicename,
293             o = 'arb'
294         )
295
296         tab_measurements = Tabs ( page=page,
297                                 domid="measurements",
298                                 togglable=True,
299                                 toggled  = False,
300                                 title="Measurements",
301                                 outline_complete=True,
302                                 sons=[ measurements_stats_cpu, measurements_stats_mem, measurements_stats_asb, measurements_stats_arb ],
303                                 active_domid = 'measurements_stats_cpu',
304                                 )
305         main_stack.insert (tab_measurements)
306         
307 #        tab_measurements = Tabs (
308 #            page                = page,
309 #            active_domid        = 'measurements-list',
310 #            outline_complete    = True,
311 #            togglable           = True,
312 #            title               = 'Measurements',
313 #            domid               = 'measurements',
314 #        )
315 #        main_stack.insert(tab_measurements)
316 #    
317 #        tab_measurements.insert(QueryTable( 
318 #            page        = page,
319 #            title       = 'Measurements',
320 #            domid       = 'measurements-list',
321 #            # tab's sons preferably turn this off
322 #            togglable   = False,
323 #            # this is the query at the core of the slice list
324 #            query       = sq_measurement,
325 #            # do NOT set checkboxes to False
326 #            # this table being otherwise empty, it just does not fly with dataTables
327 #            checkboxes  = True,
328 #            datatables_options = { 
329 #                'iDisplayLength' : 25,
330 #                'bLengthChange'  : True,
331 #                'bAutoWidth'     : True,
332 #            },
333 #        ))
334 #    
335 #        # --------------------------------------------------------------------------
336 #        # MESSAGES (we use transient=False for now)
337         if insert_messages:
338             main_stack.insert(Messages(
339                     page   = page,
340                     title  = "Runtime messages for slice %s"%slicename,
341                     domid  = "msgs-pre",
342                     levels = "ALL",
343                     # plain messages are probably less nice for production but more reliable for development for now
344                     transient = False,
345                     # these make sense only in non-transient mode..
346                     togglable = True,
347                     toggled = 'persistent',
348                     outline_complete = True,
349                     ))
350     
351     
352         # variables that will get passed to the view-unfold1.html template
353         template_env = {}
354         
355         # define 'unfold_main' to the template engine - the main contents
356         template_env [ 'unfold_main' ] = main_stack.render(request)
357     
358         # more general variables expected in the template
359         template_env [ 'title' ] = '%(slicename)s'%locals()
360         # the menu items on the top
361         template_env [ 'topmenu_items' ] = topmenu_items('Slice', request) 
362         # so we can sho who is logged
363         template_env [ 'username' ] = the_user (request) 
364     
365         # don't forget to run the requests
366         page.expose_queries ()
367     
368         # xxx create another plugin with the same query and a different layout (with_datatables)
369         # show that it worls as expected, one single api call to backend and 2 refreshed views
370     
371         # the prelude object in page contains a summary of the requirements() for all plugins
372         # define {js,css}_{files,chunks}
373         prelude_env = page.prelude_env()
374         template_env.update(prelude_env)
375         result=render_to_response ('view-unfold1.html',template_env,
376                                    context_instance=RequestContext(request))
377         return result