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