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