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