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