(wip)
[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             checkboxes = True,
161             # center on Paris
162             latitude   = 49.,
163             longitude  = 9,
164             zoom       = 4,
165         )
166
167         resources_as_3dmap = SensLabMap(
168             page       = page,
169             title      = '3D Map',
170             domid      = 'senslabmap',
171             query      = sq_resource,
172             query_all  = query_resource_all,
173         )
174
175         resources_as_list = QueryTable( 
176             page       = page,
177             domid      = 'resources-list',
178             title      = 'List view',
179             # this is the query at the core of the slice list
180             query      = sq_resource,
181             query_all  = query_resource_all,
182             checkboxes = True,
183             datatables_options = { 
184                 'iDisplayLength': 25,
185                 'bLengthChange' : True,
186                 'bAutoWidth'    : True,
187                 },
188             )
189
190         resources_as_scheduler = Scheduler(
191             page        = page,
192             title       = 'Scheduler',
193             domid       = 'scheduler',
194             query       = sq_resource,
195             query_lease = sq_lease,
196         )
197
198        # with the new 'Filter' stuff on top, no need for anything but the querytable
199         resources_as_list_area = resources_as_list 
200
201         resources_area = Tabs ( page=page, 
202                                 domid="resources",
203                                 togglable=True,
204                                 title="Resources",
205                                 outline_complete=True,
206                                 sons=[ 
207                                        resources_as_scheduler,
208                                        #resources_as_gmap, 
209                                        #resources_as_3dmap,
210                                        resources_as_list_area, ],
211                                 active_domid = 'resources-map',
212                                 )
213         main_stack.insert (resources_area)
214
215         # --------------------------------------------------------------------------
216         # USERS
217     
218         if do_query_users:
219             tab_users = Tabs(
220                 page                = page,
221                 domid               = 'users',
222                 outline_complete    = True,
223                 togglable           = True,
224                 title               = 'Users',
225                 active_domid        = 'users-list',
226                 )
227             main_stack.insert(tab_users)
228     
229             tab_users.insert(QueryTable( 
230                 page        = page,
231                 title       = 'Users List',
232                 domid       = 'users-list',
233                 # tab's sons preferably turn this off
234                 togglable   = False,
235                 # this is the query at the core of the slice list
236                 query       = sq_user,
237                 query_all  = query_user_all,
238                 checkboxes  = True,
239                 datatables_options = { 
240                     'iDisplayLength' : 25,
241                     'bLengthChange'  : True,
242                     'bAutoWidth'     : True,
243                 },
244             ))
245
246 # DEMO    
247         # --------------------------------------------------------------------------
248         # MEASUREMENTS
249         measurements_stats_cpu = SliceStat(
250             title = "CPU Usage",
251             domid = 'resources-stats-cpu',
252             page  = page,
253             stats = 'slice',
254             key   = 'hrn',
255             query = 'none',
256             slicename = slicename,
257             o = 'cpu'
258         )
259         
260         measurements_stats_mem = SliceStat(
261             title = "Memory Usage",
262             domid = 'resources-stats-mem',
263             page  = page,
264             stats = 'slice',
265             key   = 'hrn',
266             query = 'none',
267             slicename = slicename,
268             o = 'mem'
269         )
270         
271         measurements_stats_asb = SliceStat(
272             title = "Traffic Sent",
273             domid = 'resources-stats-asb',
274             page  = page,
275             stats = 'slice',
276             key   = 'hrn',
277             query = 'none',
278             slicename = slicename,
279             o = 'asb'
280         )
281         
282         measurements_stats_arb = SliceStat(
283             title = "Traffic Received",
284             domid = 'resources-stats-arb',
285             page  = page,
286             stats = 'slice',
287             key   = 'hrn',
288             query = 'none',
289             slicename = slicename,
290             o = 'arb'
291         )
292
293         tab_measurements = Tabs ( page=page,
294                                 domid="measurements",
295                                 togglable=True,
296                                 toggled  = False,
297                                 title="Measurements",
298                                 outline_complete=True,
299                                 sons=[ measurements_stats_cpu, measurements_stats_mem, measurements_stats_asb, measurements_stats_arb ],
300                                 active_domid = 'measurements_stats_cpu',
301                                 )
302         main_stack.insert (tab_measurements)
303         
304 #        tab_measurements = Tabs (
305 #            page                = page,
306 #            active_domid        = 'measurements-list',
307 #            outline_complete    = True,
308 #            togglable           = True,
309 #            title               = 'Measurements',
310 #            domid               = 'measurements',
311 #        )
312 #        main_stack.insert(tab_measurements)
313 #    
314 #        tab_measurements.insert(QueryTable( 
315 #            page        = page,
316 #            title       = 'Measurements',
317 #            domid       = 'measurements-list',
318 #            # tab's sons preferably turn this off
319 #            togglable   = False,
320 #            # this is the query at the core of the slice list
321 #            query       = sq_measurement,
322 #            # do NOT set checkboxes to False
323 #            # this table being otherwise empty, it just does not fly with dataTables
324 #            checkboxes  = True,
325 #            datatables_options = { 
326 #                'iDisplayLength' : 25,
327 #                'bLengthChange'  : True,
328 #                'bAutoWidth'     : True,
329 #            },
330 #        ))
331 #    
332 #        # --------------------------------------------------------------------------
333 #        # MESSAGES (we use transient=False for now)
334         if insert_messages:
335             main_stack.insert(Messages(
336                     page   = page,
337                     title  = "Runtime messages for slice %s"%slicename,
338                     domid  = "msgs-pre",
339                     levels = "ALL",
340                     # plain messages are probably less nice for production but more reliable for development for now
341                     transient = False,
342                     # these make sense only in non-transient mode..
343                     togglable = True,
344                     toggled = 'persistent',
345                     outline_complete = True,
346                     ))
347     
348     
349         # variables that will get passed to the view-unfold1.html template
350         template_env = {}
351         
352         # define 'unfold_main' to the template engine - the main contents
353         template_env [ 'unfold_main' ] = main_stack.render(request)
354     
355         # more general variables expected in the template
356         template_env [ 'title' ] = '%(slicename)s'%locals()
357         # the menu items on the top
358         template_env [ 'topmenu_items' ] = topmenu_items('Slice', request) 
359         # so we can sho who is logged
360         template_env [ 'username' ] = the_user (request) 
361     
362         # don't forget to run the requests
363         page.expose_queries ()
364     
365         # xxx create another plugin with the same query and a different layout (with_datatables)
366         # show that it worls as expected, one single api call to backend and 2 refreshed views
367     
368         # the prelude object in page contains a summary of the requirements() for all plugins
369         # define {js,css}_{files,chunks}
370         prelude_env = page.prelude_env()
371         template_env.update(prelude_env)
372         result=render_to_response ('view-unfold1.html',template_env,
373                                    context_instance=RequestContext(request))
374         return result