|
@@ -1,51 +1,4 @@
|
1
|
|
-# -*- coding: utf-8 -*-
|
2
|
|
-import os
|
3
|
1
|
import os.path
|
4
|
|
-import warnings
|
5
|
|
-
|
6
|
|
-##@brief File designed to be executed by an UWSGI process in order to
|
7
|
|
-#run a multisite instance process
|
8
|
|
-#
|
9
|
|
-#@warning In this module we have to be VERY carrefull about module exposure !
|
10
|
|
-#in fact here we will go through every context at least once and the globals
|
11
|
|
-#will be shared all among the module. So ANY exposed module will be accessible
|
12
|
|
-#for a short time outside its context !! A good way be protected about that
|
13
|
|
-#is to del(globals()[exposed_module_name]) after use. But it's really not
|
14
|
|
-#sure that this way of doing is a real safe protection !
|
15
|
|
-#
|
16
|
|
-#@par Expected context when called
|
17
|
|
-#- cwd has to be the lodelsites directory (the directory containing the
|
18
|
|
-#conf.d folder)
|
19
|
|
-#
|
20
|
|
-#This file is divided in two blocks :
|
21
|
|
-#
|
22
|
|
-#@par Run at load
|
23
|
|
-#The main function will be called at import.
|
24
|
|
-#This piece of code handles :
|
25
|
|
-#- loading the lodelsites site (the site that handles sites ;) )
|
26
|
|
-#- fetch the list of handled lodel sites
|
27
|
|
-#- loading the whole list of lodel sites
|
28
|
|
-#
|
29
|
|
-#@par WSGI processing
|
30
|
|
-#The other functions are here to handles WSGI request. The entry function
|
31
|
|
-#is application(), following the PEP 3333 specifications
|
32
|
|
-
|
33
|
|
-#
|
34
|
|
-# Constants declarations
|
35
|
|
-#
|
36
|
|
-
|
37
|
|
-##@brief basename of multisite process conf folder
|
38
|
|
-#@todo find a better place to declare it
|
39
|
|
-SERVER_CONFD = 'server.conf.d' #Should be accessible elsewhere
|
40
|
|
-##@brief basename of lodelsites site conf folder
|
41
|
|
-#@todo find a better place to declare it
|
42
|
|
-LODELSITES_CONFD = 'lodelsites.conf.d' #Should be accessible elsewhere
|
43
|
|
-
|
44
|
|
-##@brief A cache allowing a fast application exposure
|
45
|
|
-#
|
46
|
|
-#This dict contains reference on interface module of each handled site in
|
47
|
|
-#order to quickly call the application (PEP 3333) function of concerned site
|
48
|
|
-FAST_APP_EXPOSAL_CACHE = dict()
|
49
|
2
|
|
50
|
3
|
try:
|
51
|
4
|
from lodel.context import LodelContext
|
|
@@ -54,192 +7,18 @@ except ImportError:
|
54
|
7
|
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
55
|
8
|
from lodel.context import LodelContext, ContextError
|
56
|
9
|
|
57
|
|
-import os.path
|
58
|
|
-import lodel.buildconf #safe even outside contexts
|
59
|
|
-
|
|
10
|
+LodelContext.init(LodelContext.MULTISITE)
|
60
|
11
|
|
61
|
|
-##@brief Function that will run at import time
|
62
|
|
-#
|
63
|
|
-#Handles lodelsites site loading, handled site list fecth & load
|
64
|
|
-#@note called at end of file
|
65
|
|
-#
|
66
|
|
-#@todo evaluate if it is safe to assume that lodelsites_datapath = os.getcwd()
|
67
|
|
-#@todo get rid of hardcoded stuff (like shortname fieldname)
|
68
|
|
-#@todo use the dyncode getter when it will be available (replaced by
|
69
|
|
-#the string SUPERDYNCODE_ACCESSOR.Lodelsite for the moment)
|
70
|
|
-def main():
|
71
|
|
- LodelContext.init(LodelContext.MULTISITE)
|
72
|
|
- #Set current context to reserved loader context
|
73
|
|
- LodelContext.set(None)
|
74
|
|
- LodelContext.expose_modules(globals(), {
|
75
|
|
- 'lodel.logger': 'logger',
|
76
|
|
- 'lodel.exceptions': ['LodelFatalError'],
|
77
|
|
- })
|
78
|
|
-
|
79
|
|
- CONFDIR = os.path.join(os.getcwd(), SERVER_CONFD)
|
80
|
|
- if not os.path.isdir(CONFDIR):
|
81
|
|
- logger.critical('Multisite process bootstraping fails : unable to \
|
82
|
|
-find the %s folder' % SERVER_CONFD)
|
83
|
|
-
|
84
|
|
- #Settings bootstraping for mutlisite process
|
85
|
|
- LodelContext.expose_modules(globals(), {
|
86
|
|
- 'lodel.settings.settings': [('Settings', 'settings')],
|
87
|
|
- 'lodel.plugins.multisite.confspecs': 'multisite_confspecs'})
|
88
|
|
- settings(CONFDIR, mutisite_confspecs.LODEL2_CONFSPECS)
|
89
|
|
- #Loading settings
|
90
|
|
- del(globals()['settings']) #useless but may be safer
|
91
|
|
- #Exposing "real" settings object in loader context
|
92
|
|
- LodelContext.expose_modules(globals(), {
|
93
|
|
- 'lodel.settings': ['Settings']})
|
94
|
|
- #Fetching lodelsites informations
|
95
|
|
- lodelsites_name = Settings.sites_handler_name
|
96
|
|
- #Following path construction is kind of dirty ! We should be able
|
97
|
|
- #to assume that the lodelsites_datapath == os.getcwd()....
|
98
|
|
- lodelsites_datapath = os.path.join(LODEL2VARDIR, lodelsites_name)
|
99
|
|
- #loading lodelsites site
|
100
|
|
- load_site(lodelsites_datapath, LODELSITES_CONFD)
|
101
|
|
-
|
102
|
|
- #Fetching handled sites list
|
103
|
|
- #WARNING ! Here we assert that context name == basename(lodelsites_datapath)
|
104
|
|
- LodelContext.set(lodelsites_name)
|
105
|
|
- #in lodelsites context
|
106
|
|
- Lodelsite_leo = SUPERDYNCODE_ACCESSOR.Lodelsite #hardcoded leo name
|
107
|
|
- LodelContext.expose_modules(globals(), {
|
108
|
|
- 'lodel.leapi.query': ['LeGetQuery'],
|
109
|
|
- })
|
110
|
|
- #the line bellow you will find another harcoded thing : the shortname
|
111
|
|
- #fieldname for a lodelsite
|
112
|
|
- handled_sites = LeGetQuery(lodelsite_leo, query_filters = [],
|
113
|
|
- field_list = ['shortname'])
|
114
|
|
- #Now that we have the handled sitenames list we can go back to
|
115
|
|
- #loader context and clean it
|
116
|
|
- LodelContext.set(None)
|
117
|
|
- for mname in ['LeGetQuery', 'Settings']:
|
118
|
|
- del(globals()[mname])
|
119
|
|
- #Loading handled sites
|
120
|
|
- for handled_sitename in [s['shortname'] for s in handled_sites]:
|
121
|
|
- datapath = os.path.join(lodelsites_datapath, handled_sitename)
|
122
|
|
- site_load(datapath) #using default conf.d configuration dirname
|
123
|
|
-
|
124
|
|
-
|
125
|
|
-##@brief Load a site
|
126
|
|
-#
|
127
|
|
-#Apply a common (as MONOSITE) loading process to a site :
|
128
|
|
-#1. Conf preload
|
129
|
|
-#2. Plugins preload
|
130
|
|
-#3. Conf loading
|
131
|
|
-#4. starting plugins & hooks
|
132
|
|
-#@warning At this point we need a uniq identifier for the site (using it
|
133
|
|
-#as key for contexts & FAST_APP_EXPOSAL_CACHE). To achieve this we use
|
134
|
|
-#the data_path basename. It should works for handled sites and for the
|
135
|
|
-#lodelsites instance
|
136
|
|
-#@param data_path str : path to the datas directory (containing the confdir)
|
137
|
|
-#@param confdir_basename str : the basename of the site confdir
|
138
|
|
-#
|
139
|
|
-#@todo For now the interface plugin name for sites is hardcoded (set to
|
140
|
|
-#webui). It HAS TO be loaded from settings. But it is a bit complicated,
|
141
|
|
-#we have to get the plugin's module name abstracted from context :
|
142
|
|
-#lodel.something but if we ask directly to Plugin class the module name
|
143
|
|
-#it will return something like : lodelsites.sitename.something...
|
144
|
|
-#
|
145
|
|
-#@todo there is a quick & dirty workarround with comments saying that it
|
146
|
|
-#avoid context escape via hooks. We have to understand why and how and then
|
147
|
|
-#replace the workarround by a real solution !
|
148
|
|
-def site_load(data_path, confdir_basename = 'conf.d'):
|
149
|
|
- #args check
|
150
|
|
- if confdir_basename != os.path.basename(confdir_basename):
|
151
|
|
- LodelFatalError('Bad argument given to site_load(). This really \
|
152
|
|
-sux !')
|
153
|
|
- #Determining uniq sitename from data_path
|
154
|
|
- data_path = data_path.rstrip('/') #else basename returns ''
|
155
|
|
- ctx_name = os.path.basename(data_path)
|
156
|
|
- #Immediately switching to the context
|
157
|
|
- LodelContext.set(ctx_name)
|
158
|
|
- os.chdir(data_path) #Now the confdir is ./$condir_basename
|
159
|
|
- #Loading settings for current site
|
160
|
|
- LodelContext.expose_modules(globals(), {
|
161
|
|
- 'lodel.settings.settings': [('Settings', 'settings_preloader')]})
|
162
|
|
- if settings_preloader.started():
|
163
|
|
- msg = 'Settings seems to be allready started for "%s". \
|
164
|
|
-This should not append !' % ctx_name
|
165
|
|
- #switch back to loader context in order to log & raise
|
166
|
|
- LodelContext.set(None)
|
167
|
|
- logger.critical(msg)
|
168
|
|
- raise LodelFatalError(msg)
|
169
|
|
- settings(os.path.join('./', confdir_basename))
|
170
|
|
- #
|
171
|
|
- #Loading hooks & plugins
|
172
|
|
- #
|
173
|
|
- LodelContext.expose_modules(globals(), {
|
174
|
|
- 'lodel.plugin': ['Plugin', 'LodelHook'],
|
175
|
|
- 'lodel.logger': 'logger',
|
176
|
|
- 'lodel.plugin.core_hooks': 'core_hooks',
|
177
|
|
- 'lodel.plugin.core_scripts': 'core_scripts'
|
178
|
|
- })
|
179
|
|
- Plugin.load_all() #Then all plugins & hooks are loaded
|
180
|
|
- #triggering dyncode datasource instanciations
|
181
|
|
- LodelHook.call_hook('lodel2_plugins_loaded', '__main__', None)
|
182
|
|
- #triggering boostrapped hook
|
183
|
|
- LodelHook.call_hook('lodel2_bootstraped', '__main__', None)
|
184
|
|
- #Populating FAST_APP_EXPOSAL_CACHE
|
185
|
|
- #
|
186
|
|
- #WARNING !!!! Hardcoded interface name ! Here we have to find the
|
187
|
|
- #interface plugin name in order to populate the cache properly
|
188
|
|
- FAST_APP_EXPOSAL_CACHE[ctx_name] = LodelContext.module(
|
189
|
|
- 'lodel.plugins.webui.run')
|
190
|
|
- #a dirty & quick attempt to fix context unwanted exite via
|
191
|
|
- #hooks
|
192
|
|
- for name in ( 'LodelHook', 'core_hooks', 'core_scripts',
|
193
|
|
- 'Settings', 'settings', 'logger', 'Plugin'):
|
194
|
|
- del(globals()[name])
|
195
|
|
- #site fully loaded, switching back to loader context
|
196
|
|
- LodelContext.set(None)
|
197
|
|
- #lodel2 multisite instances are loaded and ready to run
|
198
|
|
-
|
199
|
|
-
|
200
|
|
-##@brief Utility function to return quickly an error
|
201
|
|
-def http_error(env, start_response, status = '500 internal server error', \
|
202
|
|
- extra = None):
|
203
|
|
- headers = [('Content-type', 'text/plain; charset=utf-8')]
|
204
|
|
- start_response(status, headers)
|
205
|
|
- msg = status
|
206
|
|
- if extra is not None:
|
207
|
|
- msg = extra
|
208
|
|
- return [msg.encode('utf-8')]
|
209
|
|
-
|
210
|
|
-
|
211
|
|
-##@brief utility function to extract site id from an url
|
212
|
|
-#@param url str :
|
213
|
|
-def site_id_from_url(url):
|
214
|
|
- res = ''
|
215
|
|
- for c in url[1:]:
|
216
|
|
- if c == '/':
|
217
|
|
- break
|
218
|
|
- res += c
|
219
|
|
- if len(res) == 0:
|
220
|
|
- return None
|
221
|
|
- return res
|
|
12
|
+import lodel.buildconf #safe even outside contexts
|
|
13
|
+from lodel.plugins.multisite.loader_utils import main, site_load, FAST_APP_EXPOSAL_CACHE
|
222
|
14
|
|
223
|
|
-##@brief This method is run in a child process by the handler
|
224
|
|
-def application(env, start_response):
|
225
|
|
- #Attempt to load a context
|
226
|
|
- site_id = site_id_from_url(env['PATH_INFO'])
|
227
|
|
- if site_id is None:
|
228
|
|
- #It can be nice to provide a list of instances here
|
229
|
|
- return http_error(env, start_response, '404 Not Found')
|
230
|
|
- try:
|
231
|
|
- LodelContext.set(site_id)
|
232
|
|
- #We are in the good context
|
|
15
|
+main() #multisite bootstraping
|
233
|
16
|
|
234
|
|
- except ContextError as e:
|
235
|
|
- print(e)
|
236
|
|
- return http_error(env, start_response, '404 Not found',
|
237
|
|
- "No site named '%s'" % site_id)
|
238
|
|
- #Calling webui
|
239
|
|
- return FAST_APP_EXPOSAL_CACHE[site_id].application(env, start_response)
|
240
|
|
- #LodelContext.expose_modules(globals(), {
|
241
|
|
- # 'lodel.plugins.webui.run': ['application']})
|
242
|
|
- #return application(env, start_response)
|
|
17
|
+import code
|
|
18
|
+print("""
|
|
19
|
+ Running interactive python in Lodel2 multisite instance env.
|
243
|
20
|
|
244
|
|
-#calling the main function
|
245
|
|
-main()
|
|
21
|
+ Note : you are in LOAD_CTX environnment.
|
|
22
|
+ use lodel.context.Lodelcontext.set(CONTEXT_NAME) to switch
|
|
23
|
+""")
|
|
24
|
+code.interact(local=locals())
|