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