diff --git a/Makefile.local b/Makefile.local --- a/Makefile.local +++ b/Makefile.local @@ -3,5 +3,8 @@ run: # works with the default ~/.config/swh/webapp.yml file cd swh/web && python3 manage.py runserver +run-prod: + gunicorn3 swh.web.wsgi + doc: cd swh/web/api/templates/includes/ && pandoc -o apidoc-header.html apidoc-header.md diff --git a/resources/test/webapp.yml b/resources/test/webapp.yml --- a/resources/test/webapp.yml +++ b/resources/test/webapp.yml @@ -18,4 +18,12 @@ # Max revisions shown in a log max_log_revs: 25 -limiter_rate: '1000/min' +limiters: + cache_uri: http://127.0.0.1:11211 + limits: + swh_api: + limiter_rate: 1/m + exempted_networks: + - 127.0.0.0/8 + another_api: + limiter_rate: 2/m diff --git a/swh/web/common/throttling.py b/swh/web/common/throttling.py --- a/swh/web/common/throttling.py +++ b/swh/web/common/throttling.py @@ -26,11 +26,12 @@ 60 requests per minute for the 'swh_api' scope while exempting those comming from the 127.0.0.0/8 ip network. - limiters: - swh_api: - limiter_rate: 60/min - exempted_networks: - - 127.0.0.0/8 + throttling: + scopes: + swh_api: + limiter_rate: 60/min + exempted_networks: + - 127.0.0.0/8 """ scope = None @@ -38,9 +39,10 @@ def __init__(self): super().__init__() self.exempted_networks = None - limiters = get_config()['limiters'] - if self.scope in limiters: - networks = limiters[self.scope].get('exempted_networks') + scopes = get_config()['throttling']['scopes'] + scope = scopes.get(self.scope) + if scope: + networks = scope.get('exempted_networks') if networks: self.exempted_networks = [ipaddress.ip_network(network) for network in networks] diff --git a/swh/web/config.py b/swh/web/config.py --- a/swh/web/config.py +++ b/swh/web/config.py @@ -15,13 +15,17 @@ }), 'log_dir': ('string', '/tmp/swh/log'), 'debug': ('bool', False), - 'host': ('string', '127.0.0.1'), - 'port': ('int', 8000), + 'host': ('string', '127.0.0.1'), # development property + 'port': ('int', 5003), # development property 'secret_key': ('string', 'development key'), - 'limiters': ('dict', { - 'swh_api': { - 'limiter_rate': '60/min', - 'exempted_networks': ['127.0.0.0/8'] + 'throttling': ('dict', { + 'cache_uri': None, # production: memcached as cache (127.0.0.1:11211) + # development: in-memory cache so None + 'scopes': { + 'swh_api': [{ + 'limiter_rate': '120/h', + 'exempted_networks': ['127.0.0.0/8'] + }] } }) } diff --git a/swh/web/manage.py b/swh/web/manage.py old mode 100644 new mode 100755 --- a/swh/web/manage.py +++ b/swh/web/manage.py @@ -11,7 +11,8 @@ from swh.web import config if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "swh.web.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", + "swh.web.settings.development") try: from django.core.management.commands.runserver import ( Command as runserver diff --git a/swh/web/settings.py b/swh/web/settings/common.py rename from swh/web/settings.py rename to swh/web/settings/common.py --- a/swh/web/settings.py +++ b/swh/web/settings/common.py @@ -134,8 +134,10 @@ throttle_rates = {} -for limiter_scope, limiter_conf in swh_web_config['limiters'].items(): - throttle_rates[limiter_scope] = None if DEBUG else limiter_conf['limiter_rate'] # noqa +throttling = swh_web_config['throttling'] +for limiter_scope, limiter_conf in throttling['scopes'].items(): + limiter_rate = None if DEBUG else limiter_conf['limiter_rate'] + throttle_rates[limiter_scope] = limiter_rate REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( diff --git a/swh/web/settings/development.py b/swh/web/settings/development.py new file mode 100644 --- /dev/null +++ b/swh/web/settings/development.py @@ -0,0 +1,7 @@ +# Copyright (C) 2017 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + + +from .common import * # noqa diff --git a/swh/web/settings/production.py b/swh/web/settings/production.py new file mode 100644 --- /dev/null +++ b/swh/web/settings/production.py @@ -0,0 +1,15 @@ +# Copyright (C) 2017 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + + +from .common import * # noqa +from .common import swh_web_config + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + 'LOCATION': swh_web_config['throttling']['cache_uri'], + } +} diff --git a/swh/web/tests/__init__.py b/swh/web/tests/__init__.py --- a/swh/web/tests/__init__.py +++ b/swh/web/tests/__init__.py @@ -10,23 +10,28 @@ swh_web_config = get_config() -swh_web_config['debug'] = False - -swh_web_config['limiters'] = { - 'swh_api': { - 'limiter_rate': '60/min', - 'exempted_networks': ['127.0.0.0/8'] - }, - 'scope1': { - 'limiter_rate': '3/min' - }, - 'scope2': { - 'limiter_rate': '5/min', - 'exempted_networks': ['127.0.0.0/8'] +swh_web_config.update({ + 'debug': False, + 'secret_key': 'test', + 'throttling': { + 'cache_uri': None, + 'scopes': { + 'swh_api': { + 'limiter_rate': '60/min', + 'exempted_networks': ['127.0.0.0/8'] + }, + 'scope1': { + 'limiter_rate': '3/min' + }, + 'scope2': { + 'limiter_rate': '5/min', + 'exempted_networks': ['127.0.0.0/8'] + } + } } -} +}) -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "swh.web.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "swh.web.settings.development") django.setup() scope1_limiter_rate = 3 diff --git a/swh/web/wsgi.py b/swh/web/wsgi.py --- a/swh/web/wsgi.py +++ b/swh/web/wsgi.py @@ -16,6 +16,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "swh.web.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "swh.web.settings.production") application = get_wsgi_application()