Projet

Général

Profil

0001-add-new-agent-task-to-provision-objects-to-tenants-f.patch

Benjamin Dauvergne, 12 septembre 2015 01:31

Télécharger (9,01 ko)

Voir les différences:

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.
 debian/agent/sudo-hobo-agent   |  5 +++
 debian/debian_config_common.py |  4 +++
 hobo/agent/authentic2/apps.py  | 73 ++++++++++++++++++++++++++++++++++++++++++
 hobo/agent/common/__init__.py  | 25 +++++++++++++++
 hobo/agent/worker/celery.py    |  8 +++++
 hobo/agent/worker/services.py  | 33 ++++++++++++++++---
 6 files changed, 144 insertions(+), 4 deletions(-)
debian/agent/sudo-hobo-agent
3 3
hobo-agent ALL=(combo)NOPASSWD:/usr/bin/combo-manage hobo_deploy * -
4 4
hobo-agent ALL=(passerelle)NOPASSWD:/usr/bin/passerelle-manage hobo_deploy * -
5 5
hobo-agent ALL=(fargo)NOPASSWD:/usr/bin/fargo-manage hobo_deploy * -
6
hobo-agent ALL=(wcs-au-quotidien)NOPASSWD:/usr/sbin/wcsctl -f /etc/wcs/wcs-au-quotidien.cfg hobo_notify -
7
hobo-agent ALL=(authentic-multitenant)NOPASSWD:/usr/bin/authentic2-multitenant-manage hobo_notify -
8
hobo-agent ALL=(combo)NOPASSWD:/usr/bin/combo-manage hobo_notify -
9
hobo-agent ALL=(passerelle)NOPASSWD:/usr/bin/passerelle-manage hobo_notify -
10
hobo-agent ALL=(fargo)NOPASSWD:/usr/bin/fargo-manage hobo_notify -
debian/debian_config_common.py
176 176
LANGUAGES = (('fr', u'Fran\xe7ais'),)
177 177
USE_L10N = True
178 178
USE_TZ = True
179

  
180
# Celery configuration
181
BROKER_URL = 'amqp://'
182
BROKER_TASK_EXPIRES = 120
hobo/agent/authentic2/apps.py
1
import json
2

  
1 3
from django.apps import AppConfig
4
from django.db.models.signals import post_save, post_delete
5
from django.db.models import Q
6
from django.conf import settings
7

  
8
from django_rbac.utils import get_role_model
9

  
10
from hobo.agent.common import notify_agents
11
from authentic2.utils import to_list
12
from authentic2.saml.models import LibertyProvider
13

  
14

  
15
def get_ou(role_or_through):
16
    if hasattr(role_or_through, 'ou'):
17
        return role_or_through.ou
18
    else:
19
        return role_or_through.role.ou
20

  
21

  
22
def get_audience(role_or_through):
23
    ou = get_ou(role_or_through)
24
    if ou:
25
        qs = LibertyProvider.objects.filter(ou=ou)
26
    else:
27
        qs = LibertyProvider.objects.filter(ou__isnull=True)
28
    return list(qs.values_list('entity_id', flat=True))
29

  
30

  
31
def get_related_roles(role_or_through):
32
    ou = get_ou(role_or_through)
33
    Role = get_role_model()
34
    qs = Role.objects.filter(admin_scope_id__isnull=True) \
35
        .prefetch_related('attributes')
36
    if ou:
37
        qs = qs.filter(ou=ou)
38
    else:
39
        qs = qs.filter(ou__isnull=True)
40
    for role in qs:
41
        role.emails = []
42
        role.emails_to_members = False
43
        for attribute in role.attributes.all():
44
            if attribute.name in ('emails', 'emails_to_members') and attribute.kind == 'json':
45
                setattr(role, attribute.name, json.loads(attribute.value))
46
    return qs
47

  
48

  
49
def notify_roles(sender, instance, **kwargs):
50
    notify_agents({
51
        '@type': 'provision',
52
        'audience': get_audience(instance),
53
        'full': True,
54
        'objects': [
55
            {
56
                '@type': 'role',
57
                'uuid': role.uuid,
58
                'name': role.name,
59
                'slug': role.slug,
60
                'description': role.description,
61
                'emails': role.emails,
62
                'emails_to_members': role.emails_to_members,
63
            } for role in get_related_roles(instance)
64
        ]
65
    })
66

  
2 67

  
3 68
class Authentic2AgentConfig(AppConfig):
4 69
    name = 'hobo.agent.authentic2'
5 70
    label = 'authentic2_agent'
6 71
    verbose_name = 'Authentic2 Agent'
72

  
73
    def ready(self):
74
        Role = get_role_model()
75
        post_save.connect(notify_roles, Role)
76
        post_delete.connect(notify_roles, Role)
77
        post_save.connect(notify_roles, Role.members.through)
78
        post_delete.connect(notify_roles, Role.members.through)
79
        settings.A2_MANAGER_ROLE_FORM_CLASS = 'hobo.agent.authentic2.role_forms.RoleForm'
hobo/agent/common/__init__.py
1
from celery import Celery
2
from kombu.common import Broadcast
3

  
4
from django.conf import settings
5
from django.db import connection
6

  
7

  
8
def notify_agents(data):
9
    '''Send notifications to all other tenants'''
10
    notification = {
11
        'tenant': connection.get_tenant().domain_url,
12
        'data': data,
13
    }
14
    with Celery('hobo', broker=settings.BROKER_URL) as app:
15
        app.conf.update(
16
            CELERY_TASK_SERIALIZER='json',
17
            CELERY_ACCEPT_CONTENT=['json'],
18
            CELERY_RESULT_SERIALIZER='json',
19
            CELERY_QUEUES=(Broadcast('broadcast_tasks'), )
20
        )
21
        # see called method in hobo.agent.worker.celery
22
        app.send_task('hobo-notify',
23
                      (notification,),
24
                      expires=settings.BROKER_TASK_EXPIRES,
25
                      queue='broadcast_tasks')
hobo/agent/worker/celery.py
13 13
    CELERY_QUEUES=(Broadcast('broadcast_tasks'), )
14 14
)
15 15

  
16

  
16 17
@app.task(name='hobo-deploy', bind=True)
17 18
def deploy(self, environment):
18 19
    services.deploy(environment)
20

  
21

  
22
@app.task(name='hobo-notify', bind=True, acks_late=True)
23
def hobo_notify(self, notification):
24
    assert 'tenant' in notification
25
    assert 'data' in notification
26
    services.notify(notification['data'])
hobo/agent/worker/services.py
1
import sys
1 2
import ConfigParser
2 3
import fnmatch
3 4
import json
......
19 20
        self.title = title
20 21
        self.secret_key = secret_key
21 22

  
22
    def is_for_us(self):
23
    @classmethod
24
    def is_for_us(cls, url):
23 25
        # This function checks if the requested service is to be hosted
24 26
        # on this server, and return True if appropriate.
25 27
        #
......
30 32
        # (ex: "! *.dev.au-quotidien.com").
31 33
        if not settings.AGENT_HOST_PATTERNS:
32 34
            return True
33
        patterns = settings.AGENT_HOST_PATTERNS.get(self.service_id)
35
        patterns = settings.AGENT_HOST_PATTERNS.get(cls.service_id)
34 36
        if patterns is None:
35 37
            return True
36
        parsed_url = urllib2.urlparse.urlsplit(self.base_url)
38
        parsed_url = urllib2.urlparse.urlsplit(url)
37 39
        netloc = parsed_url.netloc
38 40
        match = False
39 41
        for pattern in patterns:
......
55 57
                shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
56 58
        stdout = cmd_process.communicate(input=json.dumps(environment))
57 59

  
60
    @classmethod
61
    def notify(cls, data):
62
        for audience in data.get('audience', []):
63
            if cls.is_for_us(audience):
64
                break
65
        else:
66
            return
67
        cmd = cls.service_manage_cmd + ' hobo_notify -'
68
        try:
69
            cmd_process = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
70
                                           stdout=subprocess.PIPE, stderr=subprocess.PIPE)
71
        except OSError:
72
            return
73
        stdout, stderr = cmd_process.communicate(input=json.dumps(data))
74
        if cmd_process.returncode != 0:
75
            raise RuntimeError('command "%s" failed: %r %r' % (cmd, stdout, stderr))
76

  
58 77

  
59 78
class Passerelle(BaseService):
60 79
    service_id = 'passerelle'
......
106 125
        if not service_id in service_classes:
107 126
            continue
108 127
        service_obj = service_classes.get(service_id)(**service)
109
        if not service_obj.is_for_us():
128
        if not service_obj.is_for_us(service_obj.base_url):
110 129
            logger.debug('skipping as not for us: %r', service_obj)
111 130
            continue
112 131
        if service_obj.check_timestamp(hobo_timestamp):
113 132
            logger.debug('skipping uptodate site: %r', service_obj)
114 133
            continue
115 134
        service_obj.execute(environment)
135

  
136
def notify(data):
137
    for klassname, service in globals().items():
138
        if not hasattr(service, 'service_id'):
139
            continue
140
        service.notify(data)
116
-