Commit 3e43c7db70021cf7a78677047aa0d15b1eeb0156
1 parent
721677c8
Exists in
master
and in
29 other branches
Refactored colab-admin command
Allow to run celery from colab-admin Signed-off-by: Sergio Oliveira <sergio@tracy.com.br>
Showing
12 changed files
with
272 additions
and
145 deletions
Show diff stats
README.rst
| ... | ... | @@ -64,7 +64,7 @@ To run Colab with development server you will have to: |
| 64 | 64 | |
| 65 | 65 | .. code-block:: |
| 66 | 66 | |
| 67 | - colab-init-config > /etc/colab/settings.yaml | |
| 67 | + colab-admin initconfig > /etc/colab/settings.yaml | |
| 68 | 68 | |
| 69 | 69 | 2- Edit the configuration file. Make sure you set everything you need including **database** credentials. |
| 70 | 70 | |
| ... | ... | @@ -92,4 +92,4 @@ How to run the tests |
| 92 | 92 | Follow the steps below: |
| 93 | 93 | |
| 94 | 94 | * Go to vagrant/colab/ |
| 95 | -* run: ./runtests.sh | |
| 96 | 95 | \ No newline at end of file |
| 96 | +* run: ./runtests.sh | ... | ... |
colab/management/__init__.py
| ... | ... | @@ -1,20 +0,0 @@ |
| 1 | - | |
| 2 | -import os | |
| 3 | - | |
| 4 | -from django.core.management import ManagementUtility | |
| 5 | - | |
| 6 | -from .initconfig import initconfig | |
| 7 | - | |
| 8 | - | |
| 9 | -def execute_from_command_line(argv=None): | |
| 10 | - """ | |
| 11 | - A simple method that runs a ManagementUtility. | |
| 12 | - """ | |
| 13 | - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "colab.settings") | |
| 14 | - | |
| 15 | - utility = ManagementUtility(argv) | |
| 16 | - utility.execute() | |
| 17 | - | |
| 18 | - | |
| 19 | -def run_colab_config(argv=None): | |
| 20 | - initconfig() |
| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | +from __future__ import absolute_import, unicode_literals | |
| 2 | + | |
| 3 | +from celery.bin import celery | |
| 4 | + | |
| 5 | +from colab.celery import app | |
| 6 | +from colab.queue.command import CeleryCommand | |
| 7 | + | |
| 8 | +base = celery.CeleryCommand(app=app) | |
| 9 | + | |
| 10 | + | |
| 11 | +# this is a reimplementation of the djcelery 'celery' command | |
| 12 | +# taken from Sentry | |
| 13 | +class Command(CeleryCommand): | |
| 14 | + """The celery command.""" | |
| 15 | + help = 'celery commands, see celery help' | |
| 16 | + options = (CeleryCommand.options | |
| 17 | + + base.get_options() | |
| 18 | + + base.preload_options) | |
| 19 | + | |
| 20 | + def run_from_argv(self, argv): | |
| 21 | + argv = self.handle_default_options(argv) | |
| 22 | + if self.requires_system_checks: | |
| 23 | + self.validate() | |
| 24 | + base.execute_from_commandline( | |
| 25 | + ['{0[0]} {0[1]}'.format(argv)] + argv[2:], | |
| 26 | + ) | ... | ... |
| ... | ... | @@ -0,0 +1,124 @@ |
| 1 | + | |
| 2 | +from django.core.management.base import BaseCommand | |
| 3 | +from django.utils.crypto import get_random_string | |
| 4 | + | |
| 5 | + | |
| 6 | +CONFIG_TEMPLATE = """ | |
| 7 | +## Set to false in production | |
| 8 | +DEBUG = True | |
| 9 | +TEMPLATE_DEBUG = True | |
| 10 | + | |
| 11 | +## System admins | |
| 12 | +ADMINS = [['John Foo', 'john@example.com'], ['Mary Bar', 'mary@example.com']] | |
| 13 | + | |
| 14 | +MANAGERS = ADMINS | |
| 15 | + | |
| 16 | +COLAB_FROM_ADDRESS = '"Colab" <noreply@example.com>' | |
| 17 | +SERVER_EMAIL = '"Colab" <noreply@example.com>' | |
| 18 | + | |
| 19 | +EMAIL_HOST = 'localhost' | |
| 20 | +EMAIL_PORT = 25 | |
| 21 | +EMAIL_SUBJECT_PREFIX = '[colab]' | |
| 22 | + | |
| 23 | +SECRET_KEY = '{secret_key}' | |
| 24 | + | |
| 25 | +ALLOWED_HOSTS = [ | |
| 26 | + 'localhost', | |
| 27 | +# 'example.com', | |
| 28 | +# 'example.org', | |
| 29 | +# 'example.net', | |
| 30 | +] | |
| 31 | + | |
| 32 | +### Uncomment to enable social networks fields profile | |
| 33 | +# SOCIAL_NETWORK_ENABLED = True | |
| 34 | + | |
| 35 | +## Database settings | |
| 36 | +## | |
| 37 | +## When DEBUG is True colab will create the DB on | |
| 38 | +## the repository root. In case of production settings | |
| 39 | +## (DEBUG False) the DB settings must be set. | |
| 40 | +## | |
| 41 | +# DATABASES = {{ | |
| 42 | +# 'default': {{ | |
| 43 | +# 'ENGINE': 'django.db.backends.sqlite3', | |
| 44 | +# 'NAME': '/path/to/colab.sqlite3', | |
| 45 | +# }} | |
| 46 | +# }} | |
| 47 | + | |
| 48 | +## Disable indexing | |
| 49 | +ROBOTS_NOINDEX = False | |
| 50 | + | |
| 51 | +LOGGING = {{ | |
| 52 | + 'version': 1, | |
| 53 | + | |
| 54 | + 'handlers': {{ | |
| 55 | + 'null': {{ | |
| 56 | + 'level': 'DEBUG', | |
| 57 | + 'class': 'logging.NullHandler', | |
| 58 | + }}, | |
| 59 | + }}, | |
| 60 | + | |
| 61 | + 'loggers': {{ | |
| 62 | + 'colab.mailman': {{ | |
| 63 | + 'handlers': ['null'], | |
| 64 | + 'propagate': False, | |
| 65 | + }}, | |
| 66 | + 'haystack': {{ | |
| 67 | + 'handlers': ['null'], | |
| 68 | + 'propagate': False, | |
| 69 | + }}, | |
| 70 | + 'pysolr': {{ | |
| 71 | + 'handlers': ['null'], | |
| 72 | + 'propagate': False, | |
| 73 | + }}, | |
| 74 | + }}, | |
| 75 | +}} | |
| 76 | + | |
| 77 | + | |
| 78 | +## Gitlab plugin - Put this in plugins.d/gitlab.py to actiate ## | |
| 79 | +# from django.utils.translation import ugettext_lazy as _ | |
| 80 | +# from colab.plugins.utils.menu import colab_url_factory | |
| 81 | +# | |
| 82 | +# name = 'colab.plugins.gitlab' | |
| 83 | +# verbose_name = 'Gitlab Proxy' | |
| 84 | +# | |
| 85 | +# upstream = 'localhost' | |
| 86 | +# #middlewares = [] | |
| 87 | +# | |
| 88 | +# urls = {{ | |
| 89 | +# 'include': 'colab.plugins.gitlab.urls', | |
| 90 | +# 'namespace': 'gitlab', | |
| 91 | +# 'prefix': 'gitlab', | |
| 92 | +# }} | |
| 93 | +# | |
| 94 | +# menu_title = _('Code') | |
| 95 | +# | |
| 96 | +# url = colab_url_factory('gitlab') | |
| 97 | +# | |
| 98 | +# menu_urls = ( | |
| 99 | +# url(display=_('Public Projects'), viewname='gitlab', | |
| 100 | +# kwargs={{'path': '/public/projects'}}, auth=False), | |
| 101 | +# url(display=_('Profile'), viewname='gitlab', | |
| 102 | +# kwargs={{'path': '/profile'}}, auth=True), | |
| 103 | +# url(display=_('New Project'), viewname='gitlab', | |
| 104 | +# kwargs={{'path': '/projects/new'}}, auth=True), | |
| 105 | +# url(display=_('Projects'), viewname='gitlab', | |
| 106 | +# kwargs={{'path': '/dashboard/projects'}}, auth=True), | |
| 107 | +# url(display=_('Groups'), viewname='gitlab', | |
| 108 | +# kwargs={{'path': '/profile/groups'}}, auth=True), | |
| 109 | +# url(display=_('Issues'), viewname='gitlab', | |
| 110 | +# kwargs={{'path': '/dashboard/issues'}}, auth=True), | |
| 111 | +# url(display=_('Merge Requests'), viewname='gitlab', | |
| 112 | +# kwargs={{'path': '/merge_requests'}}, auth=True), | |
| 113 | +# | |
| 114 | +# ) | |
| 115 | +""" | |
| 116 | + | |
| 117 | + | |
| 118 | +class Command(BaseCommand): | |
| 119 | + help = 'Returns an example config file for Colab' | |
| 120 | + | |
| 121 | + def handle(self, *args, **kwargs): | |
| 122 | + chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)' | |
| 123 | + secret_key = get_random_string(50, chars) | |
| 124 | + print(CONFIG_TEMPLATE.format(secret_key=secret_key)) | ... | ... |
colab/management/initconfig.py
| ... | ... | @@ -1,120 +0,0 @@ |
| 1 | - | |
| 2 | -from django.utils.crypto import get_random_string | |
| 3 | - | |
| 4 | - | |
| 5 | -CONFIG_TEMPLATE = """ | |
| 6 | -## Set to false in production | |
| 7 | -DEBUG = True | |
| 8 | -TEMPLATE_DEBUG = True | |
| 9 | - | |
| 10 | -## System admins | |
| 11 | -ADMINS = [['John Foo', 'john@example.com'], ['Mary Bar', 'mary@example.com']] | |
| 12 | - | |
| 13 | -MANAGERS = ADMINS | |
| 14 | - | |
| 15 | -COLAB_FROM_ADDRESS = '"Colab" <noreply@example.com>' | |
| 16 | -SERVER_EMAIL = '"Colab" <noreply@example.com>' | |
| 17 | - | |
| 18 | -EMAIL_HOST = 'localhost' | |
| 19 | -EMAIL_PORT = 25 | |
| 20 | -EMAIL_SUBJECT_PREFIX = '[colab]' | |
| 21 | - | |
| 22 | -SECRET_KEY = '{secret_key}' | |
| 23 | - | |
| 24 | -ALLOWED_HOSTS = [ | |
| 25 | - 'localhost', | |
| 26 | -# 'example.com', | |
| 27 | -# 'example.org', | |
| 28 | -# 'example.net', | |
| 29 | -] | |
| 30 | - | |
| 31 | -### Uncomment to enable social networks fields profile | |
| 32 | -# SOCIAL_NETWORK_ENABLED = True | |
| 33 | - | |
| 34 | -## Database settings | |
| 35 | -## | |
| 36 | -## When DEBUG is True colab will create the DB on | |
| 37 | -## the repository root. In case of production settings | |
| 38 | -## (DEBUG False) the DB settings must be set. | |
| 39 | -## | |
| 40 | -# DATABASES = {{ | |
| 41 | -# 'default': {{ | |
| 42 | -# 'ENGINE': 'django.db.backends.sqlite3', | |
| 43 | -# 'NAME': '/path/to/colab.sqlite3', | |
| 44 | -# }} | |
| 45 | -# }} | |
| 46 | - | |
| 47 | -## Disable indexing | |
| 48 | -ROBOTS_NOINDEX = False | |
| 49 | - | |
| 50 | -LOGGING = {{ | |
| 51 | - 'version': 1, | |
| 52 | - | |
| 53 | - 'handlers': {{ | |
| 54 | - 'null': {{ | |
| 55 | - 'level': 'DEBUG', | |
| 56 | - 'class': 'logging.NullHandler', | |
| 57 | - }}, | |
| 58 | - }}, | |
| 59 | - | |
| 60 | - 'loggers': {{ | |
| 61 | - 'colab.mailman': {{ | |
| 62 | - 'handlers': ['null'], | |
| 63 | - 'propagate': False, | |
| 64 | - }}, | |
| 65 | - 'haystack': {{ | |
| 66 | - 'handlers': ['null'], | |
| 67 | - 'propagate': False, | |
| 68 | - }}, | |
| 69 | - 'pysolr': {{ | |
| 70 | - 'handlers': ['null'], | |
| 71 | - 'propagate': False, | |
| 72 | - }}, | |
| 73 | - }}, | |
| 74 | -}} | |
| 75 | - | |
| 76 | - | |
| 77 | -## Gitlab plugin - Put this in plugins.d/gitlab.py to actiate ## | |
| 78 | -# from django.utils.translation import ugettext_lazy as _ | |
| 79 | -# from colab.plugins.utils.menu import colab_url_factory | |
| 80 | -# | |
| 81 | -# name = 'colab.plugins.gitlab' | |
| 82 | -# verbose_name = 'Gitlab Proxy' | |
| 83 | -# | |
| 84 | -# upstream = 'localhost' | |
| 85 | -# #middlewares = [] | |
| 86 | -# | |
| 87 | -# urls = {{ | |
| 88 | -# 'include': 'colab.plugins.gitlab.urls', | |
| 89 | -# 'namespace': 'gitlab', | |
| 90 | -# 'prefix': 'gitlab', | |
| 91 | -# }} | |
| 92 | -# | |
| 93 | -# menu_title = _('Code') | |
| 94 | -# | |
| 95 | -# url = colab_url_factory('gitlab') | |
| 96 | -# | |
| 97 | -# menu_urls = ( | |
| 98 | -# url(display=_('Public Projects'), viewname='gitlab', | |
| 99 | -# kwargs={{'path': '/public/projects'}}, auth=False), | |
| 100 | -# url(display=_('Profile'), viewname='gitlab', | |
| 101 | -# kwargs={{'path': '/profile'}}, auth=True), | |
| 102 | -# url(display=_('New Project'), viewname='gitlab', | |
| 103 | -# kwargs={{'path': '/projects/new'}}, auth=True), | |
| 104 | -# url(display=_('Projects'), viewname='gitlab', | |
| 105 | -# kwargs={{'path': '/dashboard/projects'}}, auth=True), | |
| 106 | -# url(display=_('Groups'), viewname='gitlab', | |
| 107 | -# kwargs={{'path': '/profile/groups'}}, auth=True), | |
| 108 | -# url(display=_('Issues'), viewname='gitlab', | |
| 109 | -# kwargs={{'path': '/dashboard/issues'}}, auth=True), | |
| 110 | -# url(display=_('Merge Requests'), viewname='gitlab', | |
| 111 | -# kwargs={{'path': '/merge_requests'}}, auth=True), | |
| 112 | -# | |
| 113 | -# ) | |
| 114 | -""" | |
| 115 | - | |
| 116 | - | |
| 117 | -def initconfig(): | |
| 118 | - chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)' | |
| 119 | - secret_key = get_random_string(50, chars) | |
| 120 | - print(CONFIG_TEMPLATE.format(secret_key=secret_key)) |
| ... | ... | @@ -0,0 +1,103 @@ |
| 1 | +from __future__ import absolute_import | |
| 2 | + | |
| 3 | +import celery | |
| 4 | +import os | |
| 5 | +import sys | |
| 6 | + | |
| 7 | +from django.core.management.base import BaseCommand | |
| 8 | + | |
| 9 | +DB_SHARED_THREAD = """\ | |
| 10 | +DatabaseWrapper objects created in a thread can only \ | |
| 11 | +be used in that same thread. The object with alias '%s' \ | |
| 12 | +was created in thread id %s and this is thread id %s.\ | |
| 13 | +""" | |
| 14 | + | |
| 15 | + | |
| 16 | +def patch_thread_ident(): | |
| 17 | + # monkey patch django. | |
| 18 | + # This patch make sure that we use real threads to get the ident which | |
| 19 | + # is going to happen if we are using gevent or eventlet. | |
| 20 | + # -- patch taken from gunicorn | |
| 21 | + if getattr(patch_thread_ident, 'called', False): | |
| 22 | + return | |
| 23 | + try: | |
| 24 | + from django.db.backends import BaseDatabaseWrapper, DatabaseError | |
| 25 | + | |
| 26 | + if 'validate_thread_sharing' in BaseDatabaseWrapper.__dict__: | |
| 27 | + import thread | |
| 28 | + _get_ident = thread.get_ident | |
| 29 | + | |
| 30 | + __old__init__ = BaseDatabaseWrapper.__init__ | |
| 31 | + | |
| 32 | + def _init(self, *args, **kwargs): | |
| 33 | + __old__init__(self, *args, **kwargs) | |
| 34 | + self._thread_ident = _get_ident() | |
| 35 | + | |
| 36 | + def _validate_thread_sharing(self): | |
| 37 | + if (not self.allow_thread_sharing | |
| 38 | + and self._thread_ident != _get_ident()): | |
| 39 | + raise DatabaseError( | |
| 40 | + DB_SHARED_THREAD % ( | |
| 41 | + self.alias, self._thread_ident, _get_ident()), | |
| 42 | + ) | |
| 43 | + | |
| 44 | + BaseDatabaseWrapper.__init__ = _init | |
| 45 | + BaseDatabaseWrapper.validate_thread_sharing = \ | |
| 46 | + _validate_thread_sharing | |
| 47 | + | |
| 48 | + patch_thread_ident.called = True | |
| 49 | + except ImportError: | |
| 50 | + pass | |
| 51 | +patch_thread_ident() | |
| 52 | + | |
| 53 | + | |
| 54 | +class CeleryCommand(BaseCommand): | |
| 55 | + options = BaseCommand.option_list | |
| 56 | + skip_opts = ['--app', '--loader', '--config'] | |
| 57 | + keep_base_opts = False | |
| 58 | + | |
| 59 | + def get_version(self): | |
| 60 | + return 'celery %s' % (celery.__version__) | |
| 61 | + | |
| 62 | + def execute(self, *args, **options): | |
| 63 | + broker = options.get('broker') | |
| 64 | + if broker: | |
| 65 | + self.set_broker(broker) | |
| 66 | + super(CeleryCommand, self).execute(*args, **options) | |
| 67 | + | |
| 68 | + def set_broker(self, broker): | |
| 69 | + os.environ['CELERY_BROKER_URL'] = broker | |
| 70 | + | |
| 71 | + def run_from_argv(self, argv): | |
| 72 | + self.handle_default_options(argv[2:]) | |
| 73 | + return super(CeleryCommand, self).run_from_argv(argv) | |
| 74 | + | |
| 75 | + def handle_default_options(self, argv): | |
| 76 | + acc = [] | |
| 77 | + broker = None | |
| 78 | + for i, arg in enumerate(argv): | |
| 79 | + if '--settings=' in arg: | |
| 80 | + _, settings_module = arg.split('=') | |
| 81 | + os.environ['DJANGO_SETTINGS_MODULE'] = settings_module | |
| 82 | + elif '--pythonpath=' in arg: | |
| 83 | + _, pythonpath = arg.split('=') | |
| 84 | + sys.path.insert(0, pythonpath) | |
| 85 | + elif '--broker=' in arg: | |
| 86 | + _, broker = arg.split('=') | |
| 87 | + elif arg == '-b': | |
| 88 | + broker = argv[i + 1] | |
| 89 | + else: | |
| 90 | + acc.append(arg) | |
| 91 | + if broker: | |
| 92 | + self.set_broker(broker) | |
| 93 | + return argv if self.keep_base_opts else acc | |
| 94 | + | |
| 95 | + def die(self, msg): | |
| 96 | + sys.stderr.write(msg) | |
| 97 | + sys.stderr.write('\n') | |
| 98 | + sys.exit() | |
| 99 | + | |
| 100 | + @property | |
| 101 | + def option_list(self): | |
| 102 | + return [x for x in self.options | |
| 103 | + if x._long_opts[0] not in self.skip_opts] | ... | ... |
colab/settings.py
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | + | |
| 2 | +import os | |
| 3 | + | |
| 4 | +from django.core.management import ManagementUtility | |
| 5 | + | |
| 6 | + | |
| 7 | +def execute_from_command_line(argv=None): | |
| 8 | + """ | |
| 9 | + A simple method that runs a ManagementUtility. | |
| 10 | + """ | |
| 11 | + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "colab.settings") | |
| 12 | + | |
| 13 | + utility = ManagementUtility(argv) | |
| 14 | + utility.execute() | ... | ... |
setup.py
| ... | ... | @@ -55,8 +55,7 @@ setup( |
| 55 | 55 | packages=find_packages(exclude=EXCLUDE_FROM_PACKAGES), |
| 56 | 56 | include_package_data=True, |
| 57 | 57 | entry_points={'console_scripts': [ |
| 58 | - 'colab-admin = colab.management:execute_from_command_line', | |
| 59 | - 'colab-init-config = colab.management:initconfig', | |
| 58 | + 'colab-admin = colab.utils.runner:execute_from_command_line', | |
| 60 | 59 | ]}, |
| 61 | 60 | zip_safe=False, |
| 62 | 61 | long_description=open('README.rst').read(), | ... | ... |
vagrant/provision.sh