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