From e97460eaa1a5f47e60de15813d5452649b853e43 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Wed, 9 Sep 2015 09:28:15 +0200 Subject: [PATCH] add new agent task to provision objects to tenants (fixes #8217) First use is to connect it to post_save, post_delete signal on Role model of authentic, to propagate roles to tenants. --- hobo/agent/authentic2/apps.py | 39 +++++++++++++++++++++++++++++++++++++++ hobo/agent/common/__init__.py | 25 +++++++++++++++++++++++++ hobo/agent/worker/celery.py | 7 +++++++ hobo/agent/worker/services.py | 21 +++++++++++++++++++++ hobo/agent/worker/settings.py | 2 ++ 5 files changed, 94 insertions(+) diff --git a/hobo/agent/authentic2/apps.py b/hobo/agent/authentic2/apps.py index 0996c09..8eae23b 100644 --- a/hobo/agent/authentic2/apps.py +++ b/hobo/agent/authentic2/apps.py @@ -1,6 +1,45 @@ from django.apps import AppConfig +from django.db.models import post_save, post_delete + +from django_rbac.utils import get_role_model, get_role_parenting_model + +from hobo.agent.common import notify_agents +from authentic2.utils import to_list +from authentic2.saml.models import LibertyProvider + + +@to_list +def get_audience(): + for provider in LibertyProvider.objects.all(): + yield provider.entity_id + + +def notify_roles(sender, instance, **kwargs): + notify_agents({ + '@type': 'provision', + 'audience': get_audience(), + 'full': True, + 'objects': [ + { + '@type': 'role', + 'uuid': role.uuid, + 'name': role.name, + 'slug': role.slug, + 'description': role.description, + } for role in sender.objects.all() + ] + }) + class Authentic2AgentConfig(AppConfig): name = 'hobo.agent.authentic2' label = 'authentic2_agent' verbose_name = 'Authentic2 Agent' + + def ready(self): + Role = get_role_model() + RoleParenting = get_role_parenting_model() + post_save.connect(notify_roles, Role) + post_delete.connect(notify_roles, Role) + post_save.connect(notify_roles, RoleParenting) + post_delete.connect(notify_roles, RoleParenting) diff --git a/hobo/agent/common/__init__.py b/hobo/agent/common/__init__.py index e69de29..5b50cc6 100644 --- a/hobo/agent/common/__init__.py +++ b/hobo/agent/common/__init__.py @@ -0,0 +1,25 @@ +from celery import Celery +from kombu.common import Broadcast + +from django.conf import settings +from django.db import connection + + +def notify_agents(data): + '''Send notifications to all other tenants''' + notification = { + 'tenant': connection.get_tenant().domain_url, + 'data': data, + } + with Celery('hobo', broker=settings.BROKER_URL) as app: + app.conf.update( + CELERY_TASK_SERIALIZER='json', + CELERY_ACCEPT_CONTENT=['json'], + CELERY_RESULT_SERIALIZER='json', + CELERY_QUEUES=(Broadcast('broadcast_tasks'), ) + ) + # see called method in hobo.agent.worker.celery + app.send_task('hobo-notify', + (notification,), + expires=settings.BROKER_TASK_EXPIRES, + queue='broadcast_tasks') diff --git a/hobo/agent/worker/celery.py b/hobo/agent/worker/celery.py index 3db4b0d..47428ef 100644 --- a/hobo/agent/worker/celery.py +++ b/hobo/agent/worker/celery.py @@ -13,6 +13,13 @@ app.conf.update( CELERY_QUEUES=(Broadcast('broadcast_tasks'), ) ) + @app.task(name='hobo-deploy', bind=True) def deploy(self, environment): services.deploy(environment) + + +@app.task(name='hobo-notify', bind=True, acks_late=True) +def hobo_notify(self, data): + # do something with data + services.notify(data) diff --git a/hobo/agent/worker/services.py b/hobo/agent/worker/services.py index 01cfff9..abe8614 100644 --- a/hobo/agent/worker/services.py +++ b/hobo/agent/worker/services.py @@ -55,6 +55,10 @@ class BaseService(object): shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) stdout = cmd_process.communicate(input=json.dumps(environment)) + @classmethod + def notify(cls, data): + pass + class Passerelle(BaseService): service_id = 'passerelle' @@ -65,6 +69,17 @@ class Wcs(BaseService): service_id = 'wcs' service_manage_cmd = settings.WCS_MANAGE_COMMAND + @classmethod + def notify(cls, data): + if not os.path.exists(settings.WCS_MANAGE_COMMAND): + continue + what = settings.WCS_MANAGE_COMMAND + ' notify -' + cmd_process = subprocess.Popen(what, shell=True, stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + cmd_process.communicate(input=json.dumps(data)) + if cmd_process.returncode != 0: + raise RuntimeError('command "%s" failed' % what) + class Authentic(BaseService): service_id = 'authentic' @@ -113,3 +128,9 @@ def deploy(environment): logger.debug('skipping uptodate site: %r', service_obj) continue service_obj.execute(environment) + +def notify(data): + for klassname, service in globals().items(): + if not hasattr(service, 'notify'): + continue + service.notify(data) diff --git a/hobo/agent/worker/settings.py b/hobo/agent/worker/settings.py index 7d26df0..c8ba92d 100644 --- a/hobo/agent/worker/settings.py +++ b/hobo/agent/worker/settings.py @@ -24,6 +24,8 @@ PASSERELLE_MANAGE_COMMAND = '/usr/lib/passerelle/manage.py' FARGO_MANAGE_COMMAND = '/usr/bin/fargo-manage' WELCO_MANAGE_COMMAND = '/usr/bin/welco-manage' +NOTIFY_COMMANDS = ['/usr/sbin/wcsctl'] + local_settings_file = os.environ.get('HOBO_AGENT_SETTINGS_FILE', os.path.join(os.path.dirname(__file__), 'local_settings.py')) if os.path.exists(local_settings_file): -- 2.1.4