Projet

Général

Profil

0001-provisionning-log-received-provisionning-messages-an.patch

Benjamin Dauvergne, 13 septembre 2021 18:16

Télécharger (13,1 ko)

Voir les différences:

Subject: [PATCH] provisionning: log received provisionning messages and
 actions (#56907)

 .../common/management/commands/hobo_notify.py |  5 +
 hobo/multitenant/utils.py                     | 15 ++-
 hobo/provisionning/middleware.py              |  6 +-
 hobo/provisionning/utils.py                   | 97 ++++++++++++++-----
 4 files changed, 96 insertions(+), 27 deletions(-)
hobo/agent/common/management/commands/hobo_notify.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import json
18
import logging
18 19
import os
19 20
import sys
20 21

  
......
24 25
from hobo.multitenant.middleware import TenantMiddleware
25 26
from hobo.provisionning.utils import NotificationProcessing, TryAgain
26 27

  
28
logger = logging.getLogger(__name__)
29

  
27 30

  
28 31
class Command(BaseCommand, NotificationProcessing):
29 32
    requires_system_checks = False
......
60 63
        if entity_id not in audience:
61 64
            return
62 65
        object_type = notification['objects']['@type']
66
        msg = 'received request for %sing %%d %%s objects (Celery)' % action
67
        logger.info(msg, len(notification['objects']['data']), object_type)
63 68
        for i in range(20):
64 69
            try:
65 70
                getattr(cls, 'provision_' + object_type)(
hobo/multitenant/utils.py
12 12
        return
13 13
    logger = logging.getLogger(__name__)
14 14

  
15
    existing_pks = user.groups.values_list('pk', flat=True)
16
    for role in Role.objects.filter(uuid__in=uuids).exclude(pk__in=existing_pks):
15
    existing_pks = set(user.groups.values_list('pk', flat=True))
16
    uuids = set(uuids)
17
    not_found = uuids.copy()
18
    for role in Role.objects.filter(uuid__in=uuids):
19
        not_found.discard(role.uuid)
20
        if role.pk in existing_pks:
21
            continue
17 22
        user.groups.through.objects.get_or_create(group=role, user=user)
18
        logger.info(u'adding role %s to %s (%s)', role, user, user.pk)
23
        logger.info('adding role %s to %s (%s)', role, user, user.pk)
19 24
    qs = user.groups.through.objects.filter(user=user, group__role__isnull=False).exclude(
20 25
        group__role__uuid__in=uuids
21 26
    )
......
26 31
        except DatabaseError:
27 32
            pass
28 33
        else:
29
            logger.info(u'removed role %s from %s (%s)', rel.group, user, user.pk)
34
            logger.info('removed role %s from %s (%s)', rel.group, user, user.pk)
35
    for uuid in not_found:
36
        logger.warning('role %s of user %s does not exist', uuid, user)
hobo/provisionning/middleware.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import json
18
import logging
18 19
import sys
19 20

  
20 21
from django.conf import settings
......
27 28
from hobo.provisionning.utils import NotificationProcessing, TryAgain
28 29
from hobo.rest_authentication import PublikAuthentication, PublikAuthenticationFailed
29 30

  
31
logger = logging.getLogger(__name__)
32

  
30 33

  
31 34
class ProvisionningMiddleware(MiddlewareMixin, NotificationProcessing):
32 35
    def process_request(self, request):
......
54 57
        full = notification['full'] if 'full' in notification else False
55 58
        data = notification['objects']['data']
56 59

  
60
        msg = 'received request for %sing %%d %%s objects (HTTP)' % action
61
        logger.info(msg, len(notification['objects']['data']), object_type)
57 62
        if 'uwsgi' in sys.modules:
58 63
            from hobo.provisionning.spooler import provision
59 64

  
......
69 74
            )
70 75
        else:
71 76
            self.provision(object_type=object_type, issuer=issuer, action=action, data=data, full=full)
72

  
73 77
        return JsonResponse({'err': 0})
74 78

  
75 79
    def hobo_specific_setup(self):
hobo/provisionning/utils.py
26 26
from hobo.agent.common.models import Role
27 27
from hobo.multitenant.utils import provision_user_groups
28 28

  
29
logger = logging.getLogger(__name__)
30

  
29 31

  
30 32
class TryAgain(Exception):
31 33
    pass
32 34

  
33 35

  
36
def user_str(user):
37
    '''Compute a string representation of user'''
38
    s = ''
39
    if user.first_name or user.last_name:
40
        s += '"'
41
        if user.first_name:
42
            s += user.first_name
43
        if user.first_name and user.last_name:
44
            s += ' '
45
        if user.last_name:
46
            s += user.last_name
47
        s += '" '
48
    if user.email:
49
        s += user.email + ' '
50
    s += user.username
51
    return s
52

  
53

  
34 54
class NotificationProcessing:
35 55
    @classmethod
36 56
    def check_valid_notification(cls, notification):
......
72 92
            try:
73 93
                with atomic():
74 94
                    if action == 'provision':
95
                        new = False
96
                        updated = set()
97
                        attributes = {
98
                            'first_name': o['first_name'][:30],
99
                            'last_name': o['last_name'][:150],
100
                            'email': o['email'][:254],
101
                            'username': o['uuid'][:150],
102
                            'is_superuser': o['is_superuser'],
103
                            'is_staff': o['is_superuser'],
104
                            'is_active': o.get('is_active', True),
105
                        }
75 106
                        assert cls.check_valid_user(o)
76 107
                        try:
77 108
                            mellon_user = UserSAMLIdentifier.objects.get(issuer=issuer, name_id=o['uuid'])
......
83 114
                                )
84 115
                            except User.DoesNotExist:
85 116
                                # temp user object
86
                                random_uid = str(random.randint(1, 10000000000000))
87
                                user = User.objects.create(username=random_uid)
117
                                user = User.objects.create(**attributes)
118
                                new = True
88 119
                            mellon_user = UserSAMLIdentifier.objects.create(
89 120
                                user=user, issuer=issuer, name_id=o['uuid']
90 121
                            )
91
                        user.first_name = o['first_name'][:30]
92
                        user.last_name = o['last_name'][:150]
93
                        user.email = o['email'][:254]
94
                        user.username = o['uuid'][:150]
95
                        user.is_superuser = o['is_superuser']
96
                        user.is_staff = o['is_superuser']
97
                        user.is_active = o.get('is_active', True)
98
                        user.save()
122
                        if not new:
123
                            for key in attributes:
124
                                if getattr(user, key) != attributes[key]:
125
                                    setattr(user, key, attributes[key])
126
                                    updated.add(key)
127
                            if updated:
128
                                user.save()
129
                        if new:
130
                            logger.info('provisionned new user %s', user_str(user))
131
                        if updated:
132
                            logger.info('updated user %s(%s)', user_str(user), updated)
99 133
                        role_uuids = [role['uuid'] for role in o.get('roles', [])]
100 134
                        provision_user_groups(user, role_uuids)
101 135
                    elif action == 'deprovision':
......
104 138
            except IntegrityError:
105 139
                raise TryAgain
106 140
        if full and action == 'provision':
107
            for usi in UserSAMLIdentifier.objects.exclude(name_id__in=uuids):
141
            qs = UserSAMLIdentifier.objects.exclude(name_id__in=uuids)
142
            for user in qs:
143
                logger.info('deprovisionning user %s', user_str(user))
144
            for usi in qs:
108 145
                usi.user.delete()
109 146
        elif action == 'deprovision':
110
            for user in User.objects.filter(saml_identifiers__name_id__in=uuids):
147
            qs = User.objects.filter(saml_identifiers__name_id__in=uuids)
148
            for user in qs:
149
                logger.info('deprovisionning user %s', user_str(user))
150
            for user in qs:
111 151
                user.delete()
112 152

  
113 153
    group_name_max_length = Group._meta.get_field('name').max_length
......
125 165

  
126 166
    @classmethod
127 167
    def provision_role(cls, issuer, action, data, full=False):
128
        logger = logging.getLogger(__name__)
129 168
        uuids = set()
130 169
        for o in data:
131 170
            assert 'uuid' in o
132 171
            uuids.add(o['uuid'])
133 172
            if action == 'provision':
173
                created = False
174
                save = False
134 175
                assert cls.check_valid_role(o)
135 176
                role_name = cls.truncate_role_name(o['name'])
136 177
                try:
137 178
                    role = Role.objects.get(uuid=o['uuid'])
138
                    created = False
139 179
                except Role.DoesNotExist:
140 180
                    try:
141 181
                        with atomic():
......
144 184
                                defaults={
145 185
                                    'uuid': o['uuid'],
146 186
                                    'description': o['description'],
147
                                    'details': o.get('details', u''),
187
                                    'details': o.get('details', ''),
148 188
                                    'emails': o.get('emails', []),
149 189
                                    'emails_to_members': o.get('emails_to_members', True),
150 190
                                },
151 191
                            )
152 192
                    except IntegrityError:
153 193
                        # Can happen if uuid and name already exist
154
                        logger.error(u'cannot provision role "%s" (%s)', o['name'], o['uuid'])
194
                        logger.error('cannot provision role "%s" (%s)', o['name'], o['uuid'])
155 195
                        continue
156 196
                if not created:
157
                    save = False
158 197
                    if role.name != role_name:
159 198
                        role.name = role_name
160 199
                        save = True
......
164 203
                    if role.description != o['description']:
165 204
                        role.description = o['description']
166 205
                        save = True
167
                    if role.details != o.get('details', u''):
168
                        role.details = o.get('details', u'')
206
                    if role.details != o.get('details', ''):
207
                        role.details = o.get('details', '')
169 208
                        save = True
170 209
                    if role.emails != o.get('emails', []):
171 210
                        role.emails = o.get('emails', [])
......
179 218
                                role.save()
180 219
                        except IntegrityError:
181 220
                            # Can happen if uuid and name already exist
182
                            logger.error(u'cannot provision role "%s" (%s)', o['name'], o['uuid'])
221
                            logger.error('cannot provision role "%s" (%s)', o['name'], o['uuid'])
183 222
                            continue
223
                if created:
224
                    logger.info('provisionned new role %s (%s)', o['name'], o['uuid'])
225
                if save:
226
                    logger.info('updated role %s (%s)', o['name'], o['uuid'])
184 227
        if full and action == 'provision':
185
            for role in Role.objects.exclude(uuid__in=uuids):
228
            qs = Role.objects.exclude(uuid__in=uuids)
229
            logger.info(
230
                'deprovisionning roles %s',
231
                ', '.join('%s (%s)' % (name, uuid) for name, uuid in qs.values_list('name', 'uuid')),
232
            )
233
            for role in qs:
186 234
                role.delete()
187 235
        elif action == 'deprovision':
188
            for role in Role.objects.filter(uuid__in=uuids):
236
            qs = Role.objects.filter(uuid__in=uuids)
237
            logger.info(
238
                'deprovisionning roles %s',
239
                ', '.join('%s (%s)' % (name, uuid) for name, uuid in qs.values_list('name', 'uuid')),
240
            )
241
            for role in qs:
189 242
                role.delete()
190 243

  
191 244
    @classmethod
192
-