applications: create roles in instance OU (#76273) #71

Merged
smihai merged 1 commits from wip/76273-applification-roles-in-ou into main 2023-10-03 10:24:30 +02:00
3 changed files with 40 additions and 3 deletions

View File

@ -458,13 +458,23 @@ class Version(models.Model):
if not service:
return
roles_api_url = urllib.parse.urljoin(service['url'], 'api/roles/?update_or_create=slug')
role_ou = None
provision_api_url = urllib.parse.urljoin(service['url'], 'api/provision/')
bdauvergne marked this conversation as resolved Outdated

Attention ça passe à côté du cas où l'installation se fait sur l'OU par défaut d'un déploiement multi-collectivités; i.e. il faudrait quand il y a des collectivités (mais pas de variable ou-slug), utiliser "default".

(je pense).

Attention ça passe à côté du cas où l'installation se fait sur l'OU par défaut d'un déploiement multi-collectivités; i.e. il faudrait quand il y a des collectivités (mais pas de variable ou-slug), utiliser "default". (je pense).

Attention ça passe à côté du cas où l'installation se fait sur l'OU par défaut d'un déploiement multi-collectivités; i.e. il faudrait quand il y a des collectivités (mais pas de variable ou-slug), utiliser "default".

En mode multi-collectivité il y a toujours la variable ou-slug de définie j'ai l'impression.
Lorsqu'il s'agit de l'instance principale la variable est lié aux services déployés.

> Attention ça passe à côté du cas où l'installation se fait sur l'OU par défaut d'un déploiement multi-collectivités; i.e. il faudrait quand il y a des collectivités (mais pas de variable ou-slug), utiliser "default". > En mode multi-collectivité il y a toujours la variable `ou-slug` de définie j'ai l'impression. Lorsqu'il s'agit de l'instance principale la variable est lié aux services déployés.

Ah oui mais ça fait moche je trouve d'attraper une variable qui ne correspond pas à l'instance en cours et d'ensuite "rattraper" les choses dans la boucle; je trouverais plus simple à comprendre le déroulé qui concentrerait ça en amont de la boucle, avec commentaire donc pour rappeler la situation.

        ou_slug_variable = Variable.objects.filter(name='ou-slug').first()
        role_ou = None
        if ou_slug_variable:
            roles_api_url += '&update_or_create=ou' 
            if ou_slug_variable.service:  # main instance (variable attached to the Hobo instances)
                 role_ou = 'default'
           else:
                 role_ou = ou_slug_variable.value
...
...
            if role_ou:
                  role_info['ou'] = role_ou
Ah oui mais ça fait moche je trouve d'attraper une variable qui ne correspond pas à l'instance en cours et d'ensuite "rattraper" les choses dans la boucle; je trouverais plus simple à comprendre le déroulé qui concentrerait ça en amont de la boucle, avec commentaire donc pour rappeler la situation. ``` ou_slug_variable = Variable.objects.filter(name='ou-slug').first() role_ou = None if ou_slug_variable: roles_api_url += '&update_or_create=ou' if ou_slug_variable.service: # main instance (variable attached to the Hobo instances) role_ou = 'default' else: role_ou = ou_slug_variable.value ... ... if role_ou: role_info['ou'] = role_ou ```
ou_slug_variable = Variable.objects.filter(name='ou-slug').first()
if ou_slug_variable:
bdauvergne marked this conversation as resolved Outdated

Il faut aussi passer update_or_create dans le cas de l'instance principale.

Il faut aussi passer update_or_create dans le cas de l'instance principale.

Il faut aussi passer update_or_create dans le cas de l'instance principale.

Sur l'instance principale la variable existe et donc update_or_create sera transmis. Ou je rate quelque chose.

> Il faut aussi passer update_or_create dans le cas de l'instance principale. Sur l'instance principale la variable existe et donc `update_or_create` sera transmis. Ou je rate quelque chose.

C'était le même commentaire que le précédent (sur ou_slug_variable pas défini sur l'instance principale) (il ne l'est pas mais on choppe la variable posée sur un des hobo secondaires, j'ai compris)

C'était le même commentaire que le précédent (sur ou_slug_variable pas défini sur l'instance principale) (il ne l'est pas mais on choppe la variable posée sur un des hobo secondaires, j'ai compris)
roles_api_url += '&update_or_create=ou'
if ou_slug_variable.service: # variable on main instance has service defined
role_ou = 'default'
else:
role_ou = ou_slug_variable.value
with tarfile.open(fileobj=tar_io) as tar:
manifest = json.loads(tar.extractfile('manifest.json').read().decode())
for element in manifest.get('elements'):
if element.get('type') != 'roles':
continue
role_info = json.loads(tar.extractfile('%s/%s' % (element['type'], element['slug'])).read())
if role_ou:
role_info['ou'] = role_ou
# create or update
response = requests.post(roles_api_url, json=role_info)
if not response.ok:

View File

@ -53,13 +53,13 @@ class Requests(RequestsSession):
scheme, netloc, path, params, query, fragment = urllib.parse.urlparse(url)
url = urllib.parse.urlunparse(('', '', path, params, query, fragment))
query_params = dict(urllib.parse.parse_qsl(query))
query_params = urllib.parse.parse_qs(query)
smihai marked this conversation as resolved Outdated

parse_qs renvoie déjà un dict.

parse_qs renvoie déjà un dict.

parse_qs renvoie déjà un dict.

Yep, retiré le dict.

> parse_qs renvoie déjà un dict. Yep, retiré le `dict`.
query_params['orig'] = remote_service.get('orig')
remote_service_base_url = remote_service.get('url')
scheme, netloc, dummy, params, _, fragment = urllib.parse.urlparse(remote_service_base_url)
query = urlencode(query_params)
query = urlencode(query_params, doseq=True)
url = urllib.parse.urlunparse((scheme, netloc, path, params, query, fragment))
return super().request(method, url, **kwargs)

View File

@ -7,6 +7,7 @@ import tarfile
import httmock
import pytest
from django.contrib.contenttypes.models import ContentType
from httmock import HTTMock
from pyquery import PyQuery
from test_manager import login
@ -1321,7 +1322,7 @@ def app_bundle_roles():
def test_deploy_application_roles(app, admin_user, settings, app_bundle_roles):
Authentic.objects.create(base_url='https://idp.example.invalid', slug='idp', title='Foobar')
Wcs.objects.create(base_url='https://wcs.example.invalid', slug='foobar', title='Foobar')
wcs = Wcs.objects.create(base_url='https://wcs.example.invalid', slug='foobar', title='Foobar')
settings.KNOWN_SERVICES = {
'authentic': {
@ -1410,6 +1411,32 @@ def test_deploy_application_roles(app, admin_user, settings, app_bundle_roles):
assert job.status == 'failed'
assert job.exception == 'Failed to provision role test-role (500)'
# test import on a specific service OU
v = Variable.objects.create(name='ou-slug', label='OU', value='service-ou')
Application.objects.all().delete()
resp = app.get('/applications/')
resp = resp.click('Install')
resp.form['bundle'] = Upload('app.tar', app_bundle_roles, 'application/x-tar')
with HTTMock(httmock.remember_called(mocked_http)):
resp.form.submit().follow()
# ou must be specified when calling authentic API
assert mocked_http.call['requests'][0].url.startswith(
'https://idp.example.invalid/api/roles/?update_or_create=slug&update_or_create=ou'
)
assert b'"ou": "service-ou"' in mocked_http.call['requests'][0].body
# test import on a default OU
Application.objects.all().delete()
resp = app.get('/applications/')
resp = resp.click('Install')
resp.form['bundle'] = Upload('app.tar', app_bundle_roles, 'application/x-tar')
v.service_type = ContentType.objects.get_for_model(Wcs)
v.service_pk = wcs.id
v.save()
with HTTMock(httmock.remember_called(mocked_http)):
resp.form.submit().follow()
assert b'"ou": "default"' in mocked_http.call['requests'][0].body
def test_job_status_page(app, admin_user, settings):
Wcs.objects.create(base_url='https://wcs.example.invalid', slug='foobar', title='Foobar')