##// END OF EJS Templates
elasticsearch: inform about multiple ES nodes
ergo -
r6:4ee08856
parent child Browse files
Show More
@@ -1,285 +1,286 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # App Enlight Enterprise Edition, including its added features, Support
18 # App Enlight Enterprise Edition, including its added features, Support
19 # services, and proprietary license terms, please see
19 # services, and proprietary license terms, please see
20 # https://rhodecode.com/licenses/
20 # https://rhodecode.com/licenses/
21
21
22 import datetime
22 import datetime
23 import logging
23 import logging
24 import pyelasticsearch
24 import pyelasticsearch
25 import redis
25 import redis
26 import os
26 import os
27 from pkg_resources import iter_entry_points
27 from pkg_resources import iter_entry_points
28
28
29 import appenlight.lib.jinja2_filters as jinja2_filters
29 import appenlight.lib.jinja2_filters as jinja2_filters
30 import appenlight.lib.encryption as encryption
30 import appenlight.lib.encryption as encryption
31
31
32 from authomatic.providers import oauth2, oauth1
32 from authomatic.providers import oauth2, oauth1
33 from authomatic import Authomatic
33 from authomatic import Authomatic
34 from pyramid.config import Configurator, PHASE3_CONFIG
34 from pyramid.config import Configurator, PHASE3_CONFIG
35 from pyramid.authentication import AuthTktAuthenticationPolicy
35 from pyramid.authentication import AuthTktAuthenticationPolicy
36 from pyramid.authorization import ACLAuthorizationPolicy
36 from pyramid.authorization import ACLAuthorizationPolicy
37 from pyramid_mailer.mailer import Mailer
37 from pyramid_mailer.mailer import Mailer
38 from pyramid.renderers import JSON
38 from pyramid.renderers import JSON
39 from pyramid_redis_sessions import session_factory_from_settings
39 from pyramid_redis_sessions import session_factory_from_settings
40 from pyramid.settings import asbool, aslist
40 from pyramid.settings import asbool, aslist
41 from pyramid.security import AllPermissionsList
41 from pyramid.security import AllPermissionsList
42 from pyramid_authstack import AuthenticationStackPolicy
42 from pyramid_authstack import AuthenticationStackPolicy
43 from redlock import Redlock
43 from redlock import Redlock
44 from sqlalchemy import engine_from_config
44 from sqlalchemy import engine_from_config
45
45
46 from appenlight.celery import configure_celery
46 from appenlight.celery import configure_celery
47 from appenlight.lib import cache_regions
47 from appenlight.lib import cache_regions
48 from appenlight.lib.ext_json import json
48 from appenlight.lib.ext_json import json
49 from appenlight.security import groupfinder, AuthTokenAuthenticationPolicy
49 from appenlight.security import groupfinder, AuthTokenAuthenticationPolicy
50
50
51 json_renderer = JSON(serializer=json.dumps, indent=4)
51 json_renderer = JSON(serializer=json.dumps, indent=4)
52
52
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55
55
56 def datetime_adapter(obj, request):
56 def datetime_adapter(obj, request):
57 return obj.isoformat()
57 return obj.isoformat()
58
58
59
59
60 def all_permissions_adapter(obj, request):
60 def all_permissions_adapter(obj, request):
61 return '__all_permissions__'
61 return '__all_permissions__'
62
62
63
63
64 json_renderer.add_adapter(datetime.datetime, datetime_adapter)
64 json_renderer.add_adapter(datetime.datetime, datetime_adapter)
65 json_renderer.add_adapter(AllPermissionsList, all_permissions_adapter)
65 json_renderer.add_adapter(AllPermissionsList, all_permissions_adapter)
66
66
67
67
68 def main(global_config, **settings):
68 def main(global_config, **settings):
69 """ This function returns a Pyramid WSGI application.
69 """ This function returns a Pyramid WSGI application.
70 """
70 """
71 auth_tkt_policy = AuthTktAuthenticationPolicy(
71 auth_tkt_policy = AuthTktAuthenticationPolicy(
72 settings['authtkt.secret'],
72 settings['authtkt.secret'],
73 hashalg='sha512',
73 hashalg='sha512',
74 callback=groupfinder,
74 callback=groupfinder,
75 max_age=2592000,
75 max_age=2592000,
76 secure=asbool(settings.get('authtkt.secure', 'false')))
76 secure=asbool(settings.get('authtkt.secure', 'false')))
77 auth_token_policy = AuthTokenAuthenticationPolicy(
77 auth_token_policy = AuthTokenAuthenticationPolicy(
78 callback=groupfinder
78 callback=groupfinder
79 )
79 )
80 authorization_policy = ACLAuthorizationPolicy()
80 authorization_policy = ACLAuthorizationPolicy()
81 authentication_policy = AuthenticationStackPolicy()
81 authentication_policy = AuthenticationStackPolicy()
82 authentication_policy.add_policy('auth_tkt', auth_tkt_policy)
82 authentication_policy.add_policy('auth_tkt', auth_tkt_policy)
83 authentication_policy.add_policy('auth_token', auth_token_policy)
83 authentication_policy.add_policy('auth_token', auth_token_policy)
84 # set crypto key
84 # set crypto key
85 encryption.ENCRYPTION_SECRET = settings.get('encryption_secret')
85 encryption.ENCRYPTION_SECRET = settings.get('encryption_secret')
86 # import this later so encyption key can be monkeypatched
86 # import this later so encyption key can be monkeypatched
87 from appenlight.models import DBSession, register_datastores
87 from appenlight.models import DBSession, register_datastores
88 # update config with cometd info
88 # update config with cometd info
89 settings['cometd_servers'] = {'server': settings['cometd.server'],
89 settings['cometd_servers'] = {'server': settings['cometd.server'],
90 'secret': settings['cometd.secret']}
90 'secret': settings['cometd.secret']}
91
91
92 # Create the Pyramid Configurator.
92 # Create the Pyramid Configurator.
93 settings['_mail_url'] = settings['mailing.app_url']
93 settings['_mail_url'] = settings['mailing.app_url']
94 config = Configurator(settings=settings,
94 config = Configurator(settings=settings,
95 authentication_policy=authentication_policy,
95 authentication_policy=authentication_policy,
96 authorization_policy=authorization_policy,
96 authorization_policy=authorization_policy,
97 root_factory='appenlight.security.RootFactory',
97 root_factory='appenlight.security.RootFactory',
98 default_permission='view')
98 default_permission='view')
99 config.set_default_csrf_options(require_csrf=True, header='X-XSRF-TOKEN')
99 config.set_default_csrf_options(require_csrf=True, header='X-XSRF-TOKEN')
100 config.add_view_deriver('appenlight.predicates.csrf_view',
100 config.add_view_deriver('appenlight.predicates.csrf_view',
101 name='csrf_view')
101 name='csrf_view')
102
102
103
104 # later, when config is available
103 # later, when config is available
105 dogpile_config = {'url': settings['redis.url'],
104 dogpile_config = {'url': settings['redis.url'],
106 "redis_expiration_time": 86400,
105 "redis_expiration_time": 86400,
107 "redis_distributed_lock": True}
106 "redis_distributed_lock": True}
108 cache_regions.regions = cache_regions.CacheRegions(dogpile_config)
107 cache_regions.regions = cache_regions.CacheRegions(dogpile_config)
109 config.registry.cache_regions = cache_regions.regions
108 config.registry.cache_regions = cache_regions.regions
110 engine = engine_from_config(settings, 'sqlalchemy.',
109 engine = engine_from_config(settings, 'sqlalchemy.',
111 json_serializer=json.dumps)
110 json_serializer=json.dumps)
112 DBSession.configure(bind=engine)
111 DBSession.configure(bind=engine)
113
112
114 # json rederer that serializes datetime
113 # json rederer that serializes datetime
115 config.add_renderer('json', json_renderer)
114 config.add_renderer('json', json_renderer)
116 config.set_request_property('appenlight.lib.request.es_conn', 'es_conn')
115 config.set_request_property('appenlight.lib.request.es_conn', 'es_conn')
117 config.set_request_property('appenlight.lib.request.get_user', 'user',
116 config.set_request_property('appenlight.lib.request.get_user', 'user',
118 reify=True)
117 reify=True)
119 config.set_request_property('appenlight.lib.request.get_csrf_token',
118 config.set_request_property('appenlight.lib.request.get_csrf_token',
120 'csrf_token', reify=True)
119 'csrf_token', reify=True)
121 config.set_request_property('appenlight.lib.request.safe_json_body',
120 config.set_request_property('appenlight.lib.request.safe_json_body',
122 'safe_json_body', reify=True)
121 'safe_json_body', reify=True)
123 config.set_request_property('appenlight.lib.request.unsafe_json_body',
122 config.set_request_property('appenlight.lib.request.unsafe_json_body',
124 'unsafe_json_body', reify=True)
123 'unsafe_json_body', reify=True)
125 config.add_request_method('appenlight.lib.request.add_flash_to_headers',
124 config.add_request_method('appenlight.lib.request.add_flash_to_headers',
126 'add_flash_to_headers')
125 'add_flash_to_headers')
127
126
128 config.include('pyramid_redis_sessions')
127 config.include('pyramid_redis_sessions')
129 config.include('pyramid_tm')
128 config.include('pyramid_tm')
130 config.include('pyramid_jinja2')
129 config.include('pyramid_jinja2')
131 config.include('appenlight_client.ext.pyramid_tween')
130 config.include('appenlight_client.ext.pyramid_tween')
132 config.include('ziggurat_foundations.ext.pyramid.sign_in')
131 config.include('ziggurat_foundations.ext.pyramid.sign_in')
133 config.registry.es_conn = pyelasticsearch.ElasticSearch(
132 es_server_list = aslist(settings['elasticsearch.nodes'])
134 aslist(settings['elasticsearch.nodes']))
133 redis_url = settings['redis.url']
135 config.registry.redis_conn = redis.StrictRedis.from_url(
134 log.info('Elasticsearch server list: {}'.format(es_server_list))
136 settings['redis.url'])
135 log.info('Redis server: {}'.format(redis_url))
136 config.registry.es_conn = pyelasticsearch.ElasticSearch(es_server_list)
137 config.registry.redis_conn = redis.StrictRedis.from_url(redis_url)
137
138
138 config.registry.redis_lockmgr = Redlock([settings['redis.redlock.url'], ],
139 config.registry.redis_lockmgr = Redlock([settings['redis.redlock.url'], ],
139 retry_count=0, retry_delay=0)
140 retry_count=0, retry_delay=0)
140 # mailer
141 # mailer
141 config.registry.mailer = Mailer.from_settings(settings)
142 config.registry.mailer = Mailer.from_settings(settings)
142
143
143 # Configure sessions
144 # Configure sessions
144 session_factory = session_factory_from_settings(settings)
145 session_factory = session_factory_from_settings(settings)
145 config.set_session_factory(session_factory)
146 config.set_session_factory(session_factory)
146
147
147 # Configure renderers and event subscribers
148 # Configure renderers and event subscribers
148 config.add_jinja2_extension('jinja2.ext.loopcontrols')
149 config.add_jinja2_extension('jinja2.ext.loopcontrols')
149 config.add_jinja2_search_path('appenlight:templates')
150 config.add_jinja2_search_path('appenlight:templates')
150 # event subscribers
151 # event subscribers
151 config.add_subscriber("appenlight.subscribers.application_created",
152 config.add_subscriber("appenlight.subscribers.application_created",
152 "pyramid.events.ApplicationCreated")
153 "pyramid.events.ApplicationCreated")
153 config.add_subscriber("appenlight.subscribers.add_renderer_globals",
154 config.add_subscriber("appenlight.subscribers.add_renderer_globals",
154 "pyramid.events.BeforeRender")
155 "pyramid.events.BeforeRender")
155 config.add_subscriber('appenlight.subscribers.new_request',
156 config.add_subscriber('appenlight.subscribers.new_request',
156 'pyramid.events.NewRequest')
157 'pyramid.events.NewRequest')
157 config.add_view_predicate('context_type_class',
158 config.add_view_predicate('context_type_class',
158 'appenlight.predicates.contextTypeClass')
159 'appenlight.predicates.contextTypeClass')
159
160
160 register_datastores(es_conn=config.registry.es_conn,
161 register_datastores(es_conn=config.registry.es_conn,
161 redis_conn=config.registry.redis_conn,
162 redis_conn=config.registry.redis_conn,
162 redis_lockmgr=config.registry.redis_lockmgr)
163 redis_lockmgr=config.registry.redis_lockmgr)
163
164
164 # base stuff and scan
165 # base stuff and scan
165
166
166 # need to ensure webassets exists otherwise config.override_asset()
167 # need to ensure webassets exists otherwise config.override_asset()
167 # throws exception
168 # throws exception
168 if not os.path.exists(settings['webassets.dir']):
169 if not os.path.exists(settings['webassets.dir']):
169 os.mkdir(settings['webassets.dir'])
170 os.mkdir(settings['webassets.dir'])
170 config.add_static_view(path='appenlight:webassets',
171 config.add_static_view(path='appenlight:webassets',
171 name='static', cache_max_age=3600)
172 name='static', cache_max_age=3600)
172 config.override_asset(to_override='appenlight:webassets/',
173 config.override_asset(to_override='appenlight:webassets/',
173 override_with=settings['webassets.dir'])
174 override_with=settings['webassets.dir'])
174
175
175 config.include('appenlight.views')
176 config.include('appenlight.views')
176 config.include('appenlight.views.admin')
177 config.include('appenlight.views.admin')
177 config.scan(ignore=['appenlight.migrations',
178 config.scan(ignore=['appenlight.migrations',
178 'appenlight.scripts',
179 'appenlight.scripts',
179 'appenlight.tests'])
180 'appenlight.tests'])
180
181
181 # authomatic social auth
182 # authomatic social auth
182 authomatic_conf = {
183 authomatic_conf = {
183 # callback http://yourapp.com/social_auth/twitter
184 # callback http://yourapp.com/social_auth/twitter
184 'twitter': {
185 'twitter': {
185 'class_': oauth1.Twitter,
186 'class_': oauth1.Twitter,
186 'consumer_key': settings.get('authomatic.pr.twitter.key', 'X'),
187 'consumer_key': settings.get('authomatic.pr.twitter.key', 'X'),
187 'consumer_secret': settings.get('authomatic.pr.twitter.secret',
188 'consumer_secret': settings.get('authomatic.pr.twitter.secret',
188 'X'),
189 'X'),
189 },
190 },
190 # callback http://yourapp.com/social_auth/facebook
191 # callback http://yourapp.com/social_auth/facebook
191 'facebook': {
192 'facebook': {
192 'class_': oauth2.Facebook,
193 'class_': oauth2.Facebook,
193 'consumer_key': settings.get('authomatic.pr.facebook.app_id', 'X'),
194 'consumer_key': settings.get('authomatic.pr.facebook.app_id', 'X'),
194 'consumer_secret': settings.get('authomatic.pr.facebook.secret',
195 'consumer_secret': settings.get('authomatic.pr.facebook.secret',
195 'X'),
196 'X'),
196 'scope': ['email'],
197 'scope': ['email'],
197 },
198 },
198 # callback http://yourapp.com/social_auth/google
199 # callback http://yourapp.com/social_auth/google
199 'google': {
200 'google': {
200 'class_': oauth2.Google,
201 'class_': oauth2.Google,
201 'consumer_key': settings.get('authomatic.pr.google.key', 'X'),
202 'consumer_key': settings.get('authomatic.pr.google.key', 'X'),
202 'consumer_secret': settings.get(
203 'consumer_secret': settings.get(
203 'authomatic.pr.google.secret', 'X'),
204 'authomatic.pr.google.secret', 'X'),
204 'scope': ['profile', 'email'],
205 'scope': ['profile', 'email'],
205 },
206 },
206 'github': {
207 'github': {
207 'class_': oauth2.GitHub,
208 'class_': oauth2.GitHub,
208 'consumer_key': settings.get('authomatic.pr.github.key', 'X'),
209 'consumer_key': settings.get('authomatic.pr.github.key', 'X'),
209 'consumer_secret': settings.get(
210 'consumer_secret': settings.get(
210 'authomatic.pr.github.secret', 'X'),
211 'authomatic.pr.github.secret', 'X'),
211 'scope': ['repo', 'public_repo', 'user:email'],
212 'scope': ['repo', 'public_repo', 'user:email'],
212 'access_headers': {'User-Agent': 'AppEnlight'},
213 'access_headers': {'User-Agent': 'AppEnlight'},
213 },
214 },
214 'bitbucket': {
215 'bitbucket': {
215 'class_': oauth1.Bitbucket,
216 'class_': oauth1.Bitbucket,
216 'consumer_key': settings.get('authomatic.pr.bitbucket.key', 'X'),
217 'consumer_key': settings.get('authomatic.pr.bitbucket.key', 'X'),
217 'consumer_secret': settings.get(
218 'consumer_secret': settings.get(
218 'authomatic.pr.bitbucket.secret', 'X')
219 'authomatic.pr.bitbucket.secret', 'X')
219 }
220 }
220 }
221 }
221 config.registry.authomatic = Authomatic(
222 config.registry.authomatic = Authomatic(
222 config=authomatic_conf, secret=settings['authomatic.secret'])
223 config=authomatic_conf, secret=settings['authomatic.secret'])
223
224
224 # resource type information
225 # resource type information
225 config.registry.resource_types = ['resource', 'application']
226 config.registry.resource_types = ['resource', 'application']
226
227
227 # plugin information
228 # plugin information
228 config.registry.appenlight_plugins = {}
229 config.registry.appenlight_plugins = {}
229
230
230 def register_appenlight_plugin(config, plugin_name, plugin_config):
231 def register_appenlight_plugin(config, plugin_name, plugin_config):
231 def register():
232 def register():
232 log.warning('Registering plugin: {}'.format(plugin_name))
233 log.warning('Registering plugin: {}'.format(plugin_name))
233 if plugin_name not in config.registry.appenlight_plugins:
234 if plugin_name not in config.registry.appenlight_plugins:
234 config.registry.appenlight_plugins[plugin_name] = {
235 config.registry.appenlight_plugins[plugin_name] = {
235 'javascript': None,
236 'javascript': None,
236 'static': None,
237 'static': None,
237 'css': None,
238 'css': None,
238 'top_nav': None,
239 'top_nav': None,
239 'celery_tasks': None,
240 'celery_tasks': None,
240 'celery_beats': None,
241 'celery_beats': None,
241 'fulltext_indexer': None,
242 'fulltext_indexer': None,
242 'sqlalchemy_migrations': None,
243 'sqlalchemy_migrations': None,
243 'default_values_setter': None,
244 'default_values_setter': None,
244 'resource_types': [],
245 'resource_types': [],
245 'url_gen': None
246 'url_gen': None
246 }
247 }
247 config.registry.appenlight_plugins[plugin_name].update(
248 config.registry.appenlight_plugins[plugin_name].update(
248 plugin_config)
249 plugin_config)
249 # inform AE what kind of resource types we have available
250 # inform AE what kind of resource types we have available
250 # so we can avoid failing when a plugin is removed but data
251 # so we can avoid failing when a plugin is removed but data
251 # is still present in the db
252 # is still present in the db
252 if plugin_config.get('resource_types'):
253 if plugin_config.get('resource_types'):
253 config.registry.resource_types.extend(
254 config.registry.resource_types.extend(
254 plugin_config['resource_types'])
255 plugin_config['resource_types'])
255
256
256 config.action('appenlight_plugin={}'.format(plugin_name), register)
257 config.action('appenlight_plugin={}'.format(plugin_name), register)
257
258
258 config.add_directive('register_appenlight_plugin',
259 config.add_directive('register_appenlight_plugin',
259 register_appenlight_plugin)
260 register_appenlight_plugin)
260
261
261 for entry_point in iter_entry_points(group='appenlight.plugins'):
262 for entry_point in iter_entry_points(group='appenlight.plugins'):
262 plugin = entry_point.load()
263 plugin = entry_point.load()
263 plugin.includeme(config)
264 plugin.includeme(config)
264
265
265 # include other appenlight plugins explictly if needed
266 # include other appenlight plugins explictly if needed
266 includes = aslist(settings.get('appenlight.includes', []))
267 includes = aslist(settings.get('appenlight.includes', []))
267 for inc in includes:
268 for inc in includes:
268 config.include(inc)
269 config.include(inc)
269
270
270 # run this after everything registers in configurator
271 # run this after everything registers in configurator
271
272
272 def pre_commit():
273 def pre_commit():
273 jinja_env = config.get_jinja2_environment()
274 jinja_env = config.get_jinja2_environment()
274 jinja_env.filters['tojson'] = json.dumps
275 jinja_env.filters['tojson'] = json.dumps
275 jinja_env.filters['toJSONUnsafe'] = jinja2_filters.toJSONUnsafe
276 jinja_env.filters['toJSONUnsafe'] = jinja2_filters.toJSONUnsafe
276
277
277 config.action(None, pre_commit, order=PHASE3_CONFIG + 999)
278 config.action(None, pre_commit, order=PHASE3_CONFIG + 999)
278
279
279 def wrap_config_celery():
280 def wrap_config_celery():
280 configure_celery(config.registry)
281 configure_celery(config.registry)
281
282
282 config.action(None, wrap_config_celery, order=PHASE3_CONFIG + 999)
283 config.action(None, wrap_config_celery, order=PHASE3_CONFIG + 999)
283
284
284 app = config.make_wsgi_app()
285 app = config.make_wsgi_app()
285 return app
286 return app
General Comments 0
You need to be logged in to leave comments. Login now