Projet

Général

Profil

0001-hobo_deploy-handle-url-change-on-a-service-58908.patch

Emmanuel Cazenave, 28 mars 2022 11:52

Télécharger (30,4 ko)

Voir les différences:

Subject: [PATCH] hobo_deploy: handle url change on a service (#58908)

 .../management/commands/hobo_deploy.py        |  18 +-
 .../common/management/commands/hobo_deploy.py |  13 +-
 .../hobo/management/commands/hobo_deploy.py   |  36 +++-
 .../migrations/0025_legacy_urls.py            |  59 ++++++
 hobo/environment/models.py                    |  25 +++
 tests/test_hobo_deploy.py                     |   4 +-
 tests_authentic/test_hobo_deploy.py           | 178 ++++++++++++++++++
 tests_multipublik/conftest.py                 |   9 +-
 tests_multipublik/test_multipublik.py         | 116 ++++++++++++
 tests_schemas/legacy_urls_chrono_env.json     |  45 +++++
 tests_schemas/test_hobo_deploy.py             |  25 ++-
 11 files changed, 508 insertions(+), 20 deletions(-)
 create mode 100644 hobo/environment/migrations/0025_legacy_urls.py
 create mode 100644 tests_schemas/legacy_urls_chrono_env.json
hobo/agent/authentic2/management/commands/hobo_deploy.py
155 155
                        continue
156 156
                    metadata_text = metadata_response.text
157 157

  
158
                    provider, service_created = LibertyProvider.objects.get_or_create(
159
                        entity_id=sp_url, protocol_conformance=lasso.PROTOCOL_SAML_2_0
160
                    )
158
                    provider, service_created = None, False
159
                    for legacy_urls in service.get('legacy_urls', []):
160
                        try:
161
                            provider = LibertyProvider.objects.get(
162
                                entity_id=legacy_urls['saml-sp-metadata-url'],
163
                                protocol_conformance=lasso.PROTOCOL_SAML_2_0,
164
                            )
165
                            provider.entity_id = sp_url
166
                            break
167
                        except LibertyProvider.DoesNotExist:
168
                            pass
169
                    if not provider:
170
                        provider, service_created = LibertyProvider.objects.get_or_create(
171
                            entity_id=sp_url, protocol_conformance=lasso.PROTOCOL_SAML_2_0
172
                        )
161 173
                    provider.name = service['title']
162 174
                    provider.slug = service['slug']
163 175
                    provider.federation_source = 'hobo'
hobo/agent/common/management/commands/hobo_deploy.py
74 74
            # early exit, we don't redeploy secondary services
75 75
            return
76 76
        domain = urlparse.urlparse(self.me.get('base_url')).netloc.split(':')[0]
77
        legacy_domain = None
77 78

  
78 79
        try:
79 80
            tenant = TenantMiddleware.get_tenant_by_hostname(domain)
80 81
        except TenantNotFound:
81
            # create tenant for domain
82
            call_command('create_tenant', domain)
82
            # might be a domain change request
83
            for legacy_urls in self.me.get('legacy_urls', []):
84
                old_domain = urlparse.urlparse(legacy_urls['base_url']).netloc.split(':')[0]
85
                try:
86
                    tenant = TenantMiddleware.get_tenant_by_hostname(old_domain)
87
                    legacy_domain = old_domain
88
                    break
89
                except TenantNotFound:
90
                    pass
91
            call_command('create_tenant', domain, legacy_hostname=legacy_domain)
83 92
            tenant = TenantMiddleware.get_tenant_by_hostname(domain)
84 93

  
85 94
        timestamp = hobo_environment.get('timestamp')
hobo/agent/hobo/management/commands/hobo_deploy.py
5 5
from hobo.agent.common.management.commands import hobo_deploy
6 6
from hobo.deploy.signals import notify_agents
7 7
from hobo.environment.models import AVAILABLE_SERVICES, Hobo, Variable
8
from hobo.environment.utils import get_or_create_local_hobo
8 9
from hobo.multitenant.middleware import TenantMiddleware, TenantNotFound
9 10
from hobo.profile.models import AttributeDefinition
10 11

  
......
38 39
                if service_dict.get('secondary'):
39 40
                    continue
40 41
                if service_dict.get('base_url') == me['base_url']:
42
                    # URL might have changed, need to update local hobo
43
                    local_hobo = get_or_create_local_hobo()
44
                    if local_hobo and local_hobo.get_base_url_path() != service_dict.get('base_url'):
45
                        local_hobo.change_base_url(service_dict.get('base_url'))
46
                        local_hobo.save()
41 47
                    continue
42 48
                for service_klass in AVAILABLE_SERVICES:
43 49
                    if service_klass.Extra.service_id == service_dict.get('service-id'):
......
63 69
                    slug_prefix = '_%s_' % hobo_environment['variables']['ou-slug']
64 70

  
65 71
                service_slug = '%s%s' % (slug_prefix, service_dict['slug'])
66
                service, created = service_klass.objects.get_or_create(
67
                    base_url=service_dict['base_url'],
68
                    secondary=True,
69
                    defaults={
70
                        'title': service_dict['title'],
71
                        'slug': service_slug,
72
                        'secret_key': service_dict.get('secret_key'),
73
                    },
74
                )
72

  
73
                service, created = None, False
74
                for legacy_urls in service_dict.get('legacy_urls', []):
75
                    try:
76
                        service = service_klass.objects.get(base_url=legacy_urls['base_url'], secondary=True)
77
                        service.change_base_url(service_dict['base_url'])
78
                        break
79
                    except service_klass.DoesNotExist:
80
                        pass
81

  
82
                if not service:
83
                    service, created = service_klass.objects.get_or_create(
84
                        base_url=service_dict['base_url'],
85
                        secondary=True,
86
                        defaults={
87
                            'title': service_dict['title'],
88
                            'slug': service_slug,
89
                            'secret_key': service_dict.get('secret_key'),
90
                        },
91
                    )
92

  
75 93
                service.title = service_dict['title']
76 94
                service.secret_key = service_dict.get('secret_key')
77 95
                service.template_name = service_dict.get('template_name') or ''
hobo/environment/migrations/0025_legacy_urls.py
1
# Generated by Django 2.2.24 on 2021-12-02 13:55
2

  
3
import django.contrib.postgres.fields.jsonb
4
from django.db import migrations
5

  
6

  
7
class Migration(migrations.Migration):
8

  
9
    dependencies = [
10
        ('environment', '0024_remove_local_hobo'),
11
    ]
12

  
13
    operations = [
14
        migrations.AddField(
15
            model_name='authentic',
16
            name='legacy_urls',
17
            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
18
        ),
19
        migrations.AddField(
20
            model_name='bijoe',
21
            name='legacy_urls',
22
            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
23
        ),
24
        migrations.AddField(
25
            model_name='chrono',
26
            name='legacy_urls',
27
            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
28
        ),
29
        migrations.AddField(
30
            model_name='combo',
31
            name='legacy_urls',
32
            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
33
        ),
34
        migrations.AddField(
35
            model_name='fargo',
36
            name='legacy_urls',
37
            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
38
        ),
39
        migrations.AddField(
40
            model_name='hobo',
41
            name='legacy_urls',
42
            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
43
        ),
44
        migrations.AddField(
45
            model_name='passerelle',
46
            name='legacy_urls',
47
            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
48
        ),
49
        migrations.AddField(
50
            model_name='wcs',
51
            name='legacy_urls',
52
            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
53
        ),
54
        migrations.AddField(
55
            model_name='welco',
56
            name='legacy_urls',
57
            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
58
        ),
59
    ]
hobo/environment/models.py
19 19
import random
20 20
import re
21 21
import socket
22
import time
22 23

  
23 24
import requests
24 25
from django.conf import settings
25 26
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
26 27
from django.contrib.contenttypes.models import ContentType
28
from django.contrib.postgres.fields import JSONField
27 29
from django.core.cache import cache
28 30
from django.core.exceptions import ValidationError
29 31
from django.core.validators import URLValidator
......
104 106
    title = models.CharField(_('Title'), max_length=50)
105 107
    slug = models.SlugField(_('Slug'))
106 108
    base_url = models.CharField(_('Base URL'), max_length=200, validators=[URLValidator()])
109
    legacy_urls = JSONField(null=True, default=list, blank=True)
107 110
    secret_key = models.CharField(_('Secret Key'), max_length=60)
108 111
    template_name = models.CharField(_('Template'), max_length=60, blank=True)
109 112
    secondary = models.BooleanField(_('Secondary Service'), default=False)
......
159 162
            ]
160 163
        )
161 164
        as_dict['base_url'] = self.get_base_url_path()
165
        if self.legacy_urls:
166
            as_dict['legacy_urls'] = self.legacy_urls
162 167
        as_dict['service-id'] = self.Extra.service_id
163 168
        as_dict['service-label'] = force_text(self.Extra.service_label)
164 169
        as_dict['variables'] = dict(((v.name, v.json) for v in self.variables.all()))
......
294 299
            result[name] = value
295 300
        return result
296 301

  
302
    def change_base_url(self, base_url):
303
        service_dict = self.as_dict()
304
        timestamp = datetime.datetime.now()
305
        legacy_urls = {
306
            'base_url': service_dict['base_url'],
307
            'timestamp': str(time.mktime(timestamp.timetuple()) + timestamp.microsecond / 1e6),
308
        }
309
        for url_key in (
310
            'saml-sp-metadata-url',
311
            'saml-idp-metadata-url',
312
            'backoffice-menu-url',
313
            'provisionning-url',
314
        ):
315
            if url_key in service_dict:
316
                legacy_urls[url_key] = service_dict[url_key]
317
        if not self.legacy_urls:
318
            self.legacy_urls = []
319
        self.legacy_urls.insert(0, legacy_urls)
320
        self.base_url = base_url
321

  
297 322

  
298 323
class Authentic(ServiceBase):
299 324
    use_as_idp_for_self = models.BooleanField(verbose_name=_('Use as IdP'), default=False)
tests/test_hobo_deploy.py
152 152
    mocked_get_tenant_by_hostname.side_effect = [TenantNotFound, tenant]
153 153
    with patch('hobo.agent.common.management.commands.hobo_deploy.call_command') as mocked_call_command:
154 154
        command.deploy(base_url, ENVIRONMENT, None)
155
    assert mocked_call_command.mock_calls == [call('create_tenant', 'combo.dev.publik.love')]
155
    assert mocked_call_command.mock_calls == [
156
        call('create_tenant', 'combo.dev.publik.love', legacy_hostname=None)
157
    ]
156 158
    assert_deployed()
157 159

  
158 160
    # already there (timestamp do not change)
tests_authentic/test_hobo_deploy.py
579 579
    export_ref = sort_and_remove_uuid(export_site())
580 580
    file_ref = sort_and_remove_uuid(json.loads(content))
581 581
    assert export_ref == file_ref
582

  
583

  
584
def test_hobo_deploy_with_legacy_urls(monkeypatch, tenant_base, mocker, skeleton_dir, tmp_path):
585
    from django.core.management import call_command
586

  
587
    from hobo.agent.authentic2.management.commands.hobo_deploy import Command as HoboDeployCommand
588

  
589
    requests_get = mocker.patch('requests.get')
590
    meta1 = '''<?xml version="1.0"?>
591
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
592
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
593
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
594
    entityID="http://passerelle.example.net/saml/metadata">
595
  <SPSSODescriptor
596
    AuthnRequestsSigned="true" WantAssertionsSigned="true"
597
    protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
598
    <KeyDescriptor use="signing">
599
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
600
        <KeyValue  xmlns="http://www.w3.org/2000/09/xmldsig#">
601
    <RSAKeyValue>
602
        <Modulus>nJpkBznHNbvE+RAC6mU+NPQnIWs8gFNCm6I3FPcUKYpaJbXaurJ4cJgvnaEiqIXPQDcbHxuLeCbYbId9yascWZirvQbh8d/r+Vv+24bPG++9gW+i3Nnz1VW8V+z0b+puHWvM/FjJjBNJgWkI38gaupz47U6/02CtWx00stitiwk=</Modulus>
603
        <Exponent>AQAB</Exponent>
604
    </RSAKeyValue>
605
</KeyValue>
606
      </ds:KeyInfo>
607
    </KeyDescriptor>
608
    <KeyDescriptor use="encryption">
609
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
610
        <KeyValue  xmlns="http://www.w3.org/2000/09/xmldsig#">
611
    <RSAKeyValue>
612
        <Modulus>3BxSiAzGvY1Yuqa31L7Zr2WHM/8cn5oX+Q6A2SYgzjuvAgnWyizN8YgW/fHR4G7MtkmZ5RFJLXfcSLwbUfpFHV6KO1ikbgViYuFempM+SWtjqEI7ribm9GaI5kUzHJZBrH3/Q9XAd9/GLLALxurGjbKDeLfc0D+7el26g4sYmA8=</Modulus>
613
        <Exponent>AQAB</Exponent>
614
    </RSAKeyValue>
615
</KeyValue>
616
      </ds:KeyInfo>
617
    </KeyDescriptor>
618

  
619
    <SingleLogoutService
620
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
621
      Location="http://passerelle.example.net/saml/singleLogout"
622
      ResponseLocation="http://passerelle.example.net/saml/singleLogoutReturn" />
623
    <SingleLogoutService
624
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
625
      Location="http://passerelle.example.net/saml/singleLogoutSOAP" />
626
    <ManageNameIDService
627
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
628
      Location="http://passerelle.example.net/saml/manageNameId"
629
      ResponseLocation="http://passerelle.example.net/saml/manageNameIdReturn" />
630
    <ManageNameIDService
631
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
632
      Location="http://passerelle.example.net/saml/manageNameIdSOAP" />
633
    <AssertionConsumerService isDefault="true" index="0"
634
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
635
      Location="http://passerelle.example.net/saml/assertionConsumerArtifact" />
636
    <AssertionConsumerService index="1"
637
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
638
      Location="http://passerelle.example.net/saml/assertionConsumerPost" />
639
    <AssertionConsumerService index="2"
640
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
641
      Location="http://passerelle.example.net/saml/assertionConsumerSOAP" />
642
    <AssertionConsumerService index="3"
643
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
644
      Location="http://passerelle.example.net/saml/assertionConsumerRedirect" />
645
  </SPSSODescriptor>
646
</EntityDescriptor>'''
647
    meta2 = meta1.replace('passerelle.example.net', 'new-passerelle.example.net')
648
    monkeypatch.setattr(HoboDeployCommand, 'backoff_factor', 0.0001)
649

  
650
    side_effect_iter = iter([meta1, meta2])
651

  
652
    def side_effect(*args, **kwargs):
653
        for v in side_effect_iter:
654
            m = mock.Mock()
655
            m.text = v
656
            return m
657

  
658
    requests_get.side_effect = side_effect
659

  
660
    def hobo_json(env_dict):
661
        with tempfile.NamedTemporaryFile(mode='w', dir=str(tmp_path), delete=False) as hobo_json:
662
            hobo_json_content = json.dumps(env_dict)
663
            hobo_json.write(hobo_json_content)
664
            return hobo_json.name
665

  
666
    env = {
667
        'services': [
668
            {
669
                'service-id': 'authentic',
670
                'slug': 'test',
671
                'title': 'Test',
672
                'this': True,
673
                'secret_key': '12345',
674
                'base_url': 'http://sso.example.net',
675
                'variables': {
676
                    'other_variable': 'bar',
677
                },
678
            },
679
            {
680
                'service-id': 'passerelle',
681
                'slug': 'passerelle',
682
                'title': u'Passerelle',
683
                'base_url': 'http://passerelle.example.net',
684
                'saml-sp-metadata-url': 'http://passerelle.example.net/saml/metadata',
685
            },
686
        ],
687
        'users': [],
688
        'profile': {'fields': []},
689
    }
690

  
691
    with mock.patch('hobo.agent.authentic2.provisionning.notify_agents'):
692
        call_command('hobo_deploy', 'http://sso.example.net', hobo_json(env))
693

  
694
    from hobo.multitenant.middleware import TenantMiddleware
695

  
696
    tenants = list(TenantMiddleware.get_tenants())
697
    assert len(tenants) == 1
698
    tenant = tenants[0]
699
    assert tenant.domain_url == 'sso.example.net'
700
    assert tenant.schema_name == 'sso_example_net'
701
    tenant_directory = tenant.get_directory()
702
    assert tenant_directory == os.path.join(tenant_base, tenant.domain_url)
703
    assert os.path.exists(os.path.join(tenant_directory, 'saml.crt'))
704
    assert os.path.exists(os.path.join(tenant_directory, 'saml.key'))
705

  
706
    from tenant_schemas.utils import tenant_context
707

  
708
    with tenant_context(tenant):
709
        # SAML checks
710
        from authentic2.saml.models import LibertyProvider
711

  
712
        assert LibertyProvider.objects.count() == 1
713
        provider = LibertyProvider.objects.first()
714
        provider_id = provider.pk
715
        assert provider.entity_id == 'http://passerelle.example.net/saml/metadata'
716
        assert provider.metadata == meta1
717

  
718
    new_env = {
719
        'services': [
720
            {
721
                'service-id': 'authentic',
722
                'slug': 'test',
723
                'title': 'Test',
724
                'this': True,
725
                'secret_key': '12345',
726
                'base_url': 'http://sso.example.net',
727
                'variables': {
728
                    'other_variable': 'bar',
729
                },
730
            },
731
            {
732
                'service-id': 'passerelle',
733
                'slug': 'passerelle',
734
                'title': u'Passerelle',
735
                'base_url': 'http://new-passerelle.example.net',
736
                'saml-sp-metadata-url': 'http://new-passerelle.example.net/saml/metadata',
737
                'legacy_urls': [
738
                    {
739
                        'base_url': 'http://passerelle.example.net',
740
                        'saml-sp-metadata-url': 'http://passerelle.example.net/saml/metadata',
741
                    }
742
                ],
743
            },
744
        ],
745
        'users': [],
746
        'profile': {'fields': []},
747
    }
748

  
749
    with mock.patch('hobo.agent.authentic2.provisionning.notify_agents'):
750
        call_command('hobo_deploy', '--ignore-timestamp', 'http://sso.example.net', hobo_json(new_env))
751
    # check that liberty provider is updated
752
    with tenant_context(tenant):
753
        from authentic2.saml.models import LibertyProvider
754

  
755
        assert LibertyProvider.objects.count() == 1
756
        provider = LibertyProvider.objects.first()
757
        assert provider.metadata == meta2
758
        assert provider.entity_id == 'http://new-passerelle.example.net/saml/metadata'
759
        assert provider.pk == provider_id
tests_multipublik/conftest.py
21 21
        t.create_schema()
22 22
        return t
23 23

  
24
    tenants = [make_tenant('tenant1.example.net')]
24
    tenants = [
25
        make_tenant('tenant1.example.net'),
26
        make_tenant('hobo2.example.net'),
27
        make_tenant('hobo3.example.net'),
28
    ]
25 29

  
26 30
    def fin():
27 31
        from django.db import connection
28 32

  
29 33
        connection.set_schema_to_public()
30 34
        for t in tenants:
31
            t.delete(True)
35
            if os.path.exists(t.get_directory()):
36
                t.delete(True)
32 37
        shutil.rmtree(base)
33 38

  
34 39
    request.addfinalizer(fin)
tests_multipublik/test_multipublik.py
345 345
    with tenant_context(hobo2):
346 346
        assert Combo.objects.filter(secondary=True).count() == 1
347 347
        assert Combo.objects.filter(secondary=False).count() == 1
348

  
349
    # URL change in interco portal
350
    with tenant_context(hobo1):
351
        combo = Combo.objects.get(slug='portal')
352
        assert combo.base_url == 'https://combo1.example.net/'
353
        combo.change_base_url('https://new-combo1.example.net')
354
        combo.save()
355

  
356
        # check the interco hobo json
357
        hobo_json = get_hobo_json()
358
        for service in hobo_json['services']:
359
            if service['slug'] == 'portal':
360
                assert service['base_url'] == 'https://new-combo1.example.net/'
361
                assert len(service['legacy_urls']) == 1
362
                assert service['legacy_urls'][0]['base_url'] == 'https://combo1.example.net/'
363
                break
364
        else:
365
            assert False, "no portal found"
366

  
367
    # inform coll2 about interco environment
368
    HoboDeployCommand().handle(hobo2.base_url, get_hobo_json_filename(hobo1))
369
    with tenant_context(hobo2):
370
        # no extra combo created in coll 2
371
        assert Combo.objects.filter().count() == 2
372
        # interco portal url changed
373
        combo = Combo.objects.get(slug='_interco_portal')
374
        assert combo.base_url == 'https://new-combo1.example.net/'
375
        assert len(combo.legacy_urls) == 1
376
        assert combo.legacy_urls[0]['base_url'] == 'https://combo1.example.net/'
377

  
378
    # inform coll2 about interco environment a second time, check that nothing changes
379
    HoboDeployCommand().handle(hobo2.base_url, get_hobo_json_filename(hobo1))
380
    with tenant_context(hobo2):
381
        assert Combo.objects.filter().count() == 2
382
        combo = Combo.objects.get(slug='_interco_portal')
383
        assert combo.base_url == 'https://new-combo1.example.net/'
384
        assert len(combo.legacy_urls) == 1
385
        assert combo.legacy_urls[0]['base_url'] == 'https://combo1.example.net/'
386

  
387
    # URL change in coll2 portal
388
    with tenant_context(hobo2):
389
        combo = Combo.objects.get(slug='portal')
390
        assert combo.base_url == 'https://combo2.example.net/'
391
        combo.change_base_url('https://new-combo2.example.net')
392
        combo.save()
393

  
394
        # check the coll2 hobo json
395
        hobo_json = get_hobo_json()
396
        for service in hobo_json['services']:
397
            if service['slug'] == 'portal':
398
                assert service['base_url'] == 'https://new-combo2.example.net/'
399
                assert len(service['legacy_urls']) == 1
400
                assert service['legacy_urls'][0]['base_url'] == 'https://combo2.example.net/'
401
                break
402
        else:
403
            assert False, "no portal found"
404

  
405
    # inform interco about coll2 environment
406
    HoboDeployCommand().handle(hobo1.base_url, get_hobo_json_filename(hobo2))
407
    with tenant_context(hobo1):
408
        # no extra combo created in interco
409
        assert Combo.objects.filter().count() == 3
410
        # coll2 portal url changed
411
        combo = Combo.objects.get(slug='_hobo-coll2_portal')
412
        assert combo.base_url == 'https://new-combo2.example.net/'
413
        assert len(combo.legacy_urls) == 1
414
        assert combo.legacy_urls[0]['base_url'] == 'https://combo2.example.net/'
415

  
416
    # URL change on the primary hobo
417
    with tenant_context(hobo1):
418
        hobo = Hobo.objects.get(slug='hobo')
419
        assert hobo.base_url == 'https://tenant1.example.net/'
420
        hobo.change_base_url('https://new-tenant1.example.net')
421
        hobo.save()
422

  
423
        # check the interco hobo json
424
        hobo_json = get_hobo_json()
425
        for service in hobo_json['services']:
426
            if service['slug'] == 'hobo':
427
                assert service['base_url'] == 'https://new-tenant1.example.net/'
428
                assert len(service['legacy_urls']) == 1
429
                assert service['legacy_urls'][0]['base_url'] == 'https://tenant1.example.net/'
430
                break
431
        else:
432
            assert False, 'no hobo found'
433

  
434
    # inform coll2 about interco environment
435
    HoboDeployCommand().handle(hobo2.base_url, get_hobo_json_filename(hobo1))
436
    with tenant_context(hobo2):
437
        # no extra hobo created in coll 2
438
        assert Hobo.objects.count() == 3
439
        # interco hobo url changed
440
        hobo = Hobo.objects.get(slug='_interco_hobo')
441
        assert hobo.base_url == 'https://new-tenant1.example.net/'
442
        assert len(hobo.legacy_urls) == 1
443
        assert hobo.legacy_urls[0]['base_url'] == 'https://tenant1.example.net/'
444

  
445
    # URL change on coll2 hobo (initiated by the interco tenant)
446
    with tenant_context(hobo1):
447
        hobo2 = Hobo.objects.get(slug='hobo-coll2')
448
        assert hobo2.base_url == 'https://hobo2.example.net/'
449
        hobo2.change_base_url('https://new-hobo2.example.net')
450
        hobo2.save()
451

  
452
    # inform coll2 about interco environment
453
    HoboDeployCommand().handle(hobo2.base_url, get_hobo_json_filename(hobo1))
454

  
455
    hobo2 = TenantMiddleware.get_tenant_by_hostname('new-hobo2.example.net')
456
    with tenant_context(hobo2):
457
        # no extra hobo created in coll 2
458
        assert Hobo.objects.count() == 3
459
        # coll2 hobo url changed
460
        hobo = Hobo.objects.get(slug='hobo')
461
        assert hobo.base_url == 'https://new-hobo2.example.net/'
462
        assert len(hobo.legacy_urls) == 1
463
        assert hobo.legacy_urls[0]['base_url'] == 'https://hobo2.example.net/'
tests_schemas/legacy_urls_chrono_env.json
1
{
2
    "services": [
3
	{
4
	    "service-id": "chrono",
5
	    "base_url": "https://new-chrono.dev.publik.love/",
6
	    "slug": "agendas",
7
	    "title": "CHRONO",
8
	    "secret_key": "123",
9
	    "template_name": "import_me",
10
            "legacy_urls": [
11
                {
12
                    "base_url": "https://chrono.dev.publik.love/"
13
                }
14
            ]
15
	},
16
	{
17
	    "service-id": "wcs",
18
	    "base_url": "https://wcs.dev.publik.love/",
19
	    "slug": "eservices",
20
	    "title": "WCS"
21
	},
22
	{
23
	    "service-id": "hobo",
24
	    "base_url": "https://hobo.dev.publik.love/",
25
	    "slug": "hobo",
26
	    "title": "HOBO",
27
	    "secret_key": "123"
28
	},
29
	{
30
	    "service-id": "combo",
31
	    "base_url": "https://combo.dev.publik.love/",
32
	    "slug": "portal",
33
	    "title": "COMBO",
34
	    "secret_key": "123",
35
	    "template_name": "import_me"
36
	},
37
	{
38
	    "service-id": "authentic",
39
	    "base_url": "https://authentic.dev.publik.love/",
40
	    "slug": "idp",
41
	    "title": "A2",
42
	    "secret_key": "123"
43
	}
44
    ]
45
}
tests_schemas/test_hobo_deploy.py
1 1
import os
2 2

  
3 3
import mock
4
import pytest
4 5
from django.core.management import call_command, get_commands, load_command_class
5 6
from tenant_schemas.utils import tenant_context
6 7

  
7 8
from hobo.environment.models import Variable
8
from hobo.multitenant.middleware import TenantMiddleware
9
from hobo.multitenant.middleware import TenantMiddleware, TenantNotFound
9 10

  
10 11

  
11 12
def assert_deployed(domain):
......
26 27
    command = load_command_class('hobo.agent.common', 'hobo_deploy')
27 28
    domain = 'chrono.dev.publik.love'
28 29

  
29
    def my_call_command(command, parameter):
30
    def my_call_command(command, parameter, **kwargs):
30 31
        if command == 'import_template':
31 32
            my_call_command.import_template_was_called = True
32 33
            return
33
        call_command(command, parameter)
34
        call_command(command, parameter, **kwargs)
34 35

  
35 36
    mocked_get_commands.return_value = ['import_template']
36 37
    mocked_call_command.side_effect = my_call_command
......
77 78
# fails to simulate call from bijoe agent, that overload deploy_specifics()
78 79
# $ bijoe-mange hobo-deploy
79 80
# here, because this code is not implemented here
81

  
82

  
83
def test_deploy_with_legacy_urls(db):
84
    command = load_command_class('hobo.agent.common', 'hobo_deploy')
85
    domain = 'chrono.dev.publik.love'
86
    command.handle('https://%s/' % domain, 'tests_schemas/env.json')
87
    assert_deployed(domain)
88
    tenant_directory = TenantMiddleware.get_tenant_by_hostname(domain).get_directory()
89

  
90
    # change domain
91
    new_domain = 'new-chrono.dev.publik.love'
92
    command.handle('https://%s/' % new_domain, 'tests_schemas/legacy_urls_chrono_env.json')
93
    assert_deployed(new_domain)
94

  
95
    # check old tenant is gone
96
    with pytest.raises(TenantNotFound):
97
        TenantMiddleware.get_tenant_by_hostname(domain)
98
    assert not os.path.exists(tenant_directory)
80
-