Projet

Général

Profil

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

Emmanuel Cazenave, 20 janvier 2022 18:10

Télécharger (31,1 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   |  35 +++-
 .../migrations/0023_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         | 120 +++++++++++-
 tests_schemas/legacy_urls_chrono_env.json     |  45 +++++
 tests_schemas/test_hobo_deploy.py             |  25 ++-
 11 files changed, 509 insertions(+), 22 deletions(-)
 create mode 100644 hobo/environment/migrations/0023_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 emitter 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
                else:
82
                    service, created = service_klass.objects.get_or_create(
83
                        base_url=service_dict['base_url'],
84
                        secondary=True,
85
                        defaults={
86
                            'title': service_dict['title'],
87
                            'slug': service_slug,
88
                            'secret_key': service_dict.get('secret_key'),
89
                        },
90
                    )
91

  
75 92
                service.title = service_dict['title']
76 93
                service.secret_key = service_dict.get('secret_key')
77 94
                service.template_name = service_dict.get('template_name') or ''
hobo/environment/migrations/0023_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', '0022_emitter'),
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
564 564
    export_ref = sort_and_remove_uuid(export_site())
565 565
    file_ref = sort_and_remove_uuid(json.loads(content))
566 566
    assert export_ref == file_ref
567

  
568

  
569
def test_hobo_deploy_with_legacy_urls(monkeypatch, tenant_base, mocker, skeleton_dir, tmp_path):
570
    from django.core.management import call_command
571

  
572
    from hobo.agent.authentic2.management.commands.hobo_deploy import Command as HoboDeployCommand
573

  
574
    requests_get = mocker.patch('requests.get')
575
    meta1 = '''<?xml version="1.0"?>
576
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
577
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
578
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
579
    entityID="http://passerelle.example.net/saml/metadata">
580
  <SPSSODescriptor
581
    AuthnRequestsSigned="true" WantAssertionsSigned="true"
582
    protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
583
    <KeyDescriptor use="signing">
584
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
585
        <KeyValue  xmlns="http://www.w3.org/2000/09/xmldsig#">
586
    <RSAKeyValue>
587
        <Modulus>nJpkBznHNbvE+RAC6mU+NPQnIWs8gFNCm6I3FPcUKYpaJbXaurJ4cJgvnaEiqIXPQDcbHxuLeCbYbId9yascWZirvQbh8d/r+Vv+24bPG++9gW+i3Nnz1VW8V+z0b+puHWvM/FjJjBNJgWkI38gaupz47U6/02CtWx00stitiwk=</Modulus>
588
        <Exponent>AQAB</Exponent>
589
    </RSAKeyValue>
590
</KeyValue>
591
      </ds:KeyInfo>
592
    </KeyDescriptor>
593
    <KeyDescriptor use="encryption">
594
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
595
        <KeyValue  xmlns="http://www.w3.org/2000/09/xmldsig#">
596
    <RSAKeyValue>
597
        <Modulus>3BxSiAzGvY1Yuqa31L7Zr2WHM/8cn5oX+Q6A2SYgzjuvAgnWyizN8YgW/fHR4G7MtkmZ5RFJLXfcSLwbUfpFHV6KO1ikbgViYuFempM+SWtjqEI7ribm9GaI5kUzHJZBrH3/Q9XAd9/GLLALxurGjbKDeLfc0D+7el26g4sYmA8=</Modulus>
598
        <Exponent>AQAB</Exponent>
599
    </RSAKeyValue>
600
</KeyValue>
601
      </ds:KeyInfo>
602
    </KeyDescriptor>
603

  
604
    <SingleLogoutService
605
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
606
      Location="http://passerelle.example.net/saml/singleLogout"
607
      ResponseLocation="http://passerelle.example.net/saml/singleLogoutReturn" />
608
    <SingleLogoutService
609
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
610
      Location="http://passerelle.example.net/saml/singleLogoutSOAP" />
611
    <ManageNameIDService
612
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
613
      Location="http://passerelle.example.net/saml/manageNameId"
614
      ResponseLocation="http://passerelle.example.net/saml/manageNameIdReturn" />
615
    <ManageNameIDService
616
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
617
      Location="http://passerelle.example.net/saml/manageNameIdSOAP" />
618
    <AssertionConsumerService isDefault="true" index="0"
619
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
620
      Location="http://passerelle.example.net/saml/assertionConsumerArtifact" />
621
    <AssertionConsumerService index="1"
622
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
623
      Location="http://passerelle.example.net/saml/assertionConsumerPost" />
624
    <AssertionConsumerService index="2"
625
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
626
      Location="http://passerelle.example.net/saml/assertionConsumerSOAP" />
627
    <AssertionConsumerService index="3"
628
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
629
      Location="http://passerelle.example.net/saml/assertionConsumerRedirect" />
630
  </SPSSODescriptor>
631
</EntityDescriptor>'''
632
    meta2 = meta1.replace('passerelle.example.net', 'new-passerelle.example.net')
633
    monkeypatch.setattr(HoboDeployCommand, 'backoff_factor', 0.0001)
634

  
635
    side_effect_iter = iter([meta1, meta2])
636

  
637
    def side_effect(*args, **kwargs):
638
        for v in side_effect_iter:
639
            m = mock.Mock()
640
            m.text = v
641
            return m
642

  
643
    requests_get.side_effect = side_effect
644

  
645
    def hobo_json(env_dict):
646
        with tempfile.NamedTemporaryFile(mode='w', dir=str(tmp_path), delete=False) as hobo_json:
647
            hobo_json_content = json.dumps(env_dict)
648
            hobo_json.write(hobo_json_content)
649
            return hobo_json.name
650

  
651
    env = {
652
        'services': [
653
            {
654
                'service-id': 'authentic',
655
                'slug': 'test',
656
                'title': 'Test',
657
                'this': True,
658
                'secret_key': '12345',
659
                'base_url': 'http://sso.example.net',
660
                'variables': {
661
                    'other_variable': 'bar',
662
                },
663
            },
664
            {
665
                'service-id': 'passerelle',
666
                'slug': 'passerelle',
667
                'title': u'Passerelle',
668
                'base_url': 'http://passerelle.example.net',
669
                'saml-sp-metadata-url': 'http://passerelle.example.net/saml/metadata',
670
            },
671
        ],
672
        'users': [],
673
        'profile': {'fields': []},
674
    }
675

  
676
    with mock.patch('hobo.agent.authentic2.provisionning.notify_agents'):
677
        call_command('hobo_deploy', 'http://sso.example.net', hobo_json(env))
678

  
679
    from hobo.multitenant.middleware import TenantMiddleware
680

  
681
    tenants = list(TenantMiddleware.get_tenants())
682
    assert len(tenants) == 1
683
    tenant = tenants[0]
684
    assert tenant.domain_url == 'sso.example.net'
685
    assert tenant.schema_name == 'sso_example_net'
686
    tenant_directory = tenant.get_directory()
687
    assert tenant_directory == os.path.join(tenant_base, tenant.domain_url)
688
    assert os.path.exists(os.path.join(tenant_directory, 'saml.crt'))
689
    assert os.path.exists(os.path.join(tenant_directory, 'saml.key'))
690

  
691
    from tenant_schemas.utils import tenant_context
692

  
693
    with tenant_context(tenant):
694
        # SAML checks
695
        from authentic2.saml.models import LibertyProvider
696

  
697
        assert LibertyProvider.objects.count() == 1
698
        provider = LibertyProvider.objects.first()
699
        provider_id = provider.pk
700
        assert provider.entity_id == 'http://passerelle.example.net/saml/metadata'
701
        assert provider.metadata == meta1
702

  
703
    new_env = {
704
        'services': [
705
            {
706
                'service-id': 'authentic',
707
                'slug': 'test',
708
                'title': 'Test',
709
                'this': True,
710
                'secret_key': '12345',
711
                'base_url': 'http://sso.example.net',
712
                'variables': {
713
                    'other_variable': 'bar',
714
                },
715
            },
716
            {
717
                'service-id': 'passerelle',
718
                'slug': 'passerelle',
719
                'title': u'Passerelle',
720
                'base_url': 'http://new-passerelle.example.net',
721
                'saml-sp-metadata-url': 'http://new-passerelle.example.net/saml/metadata',
722
                'legacy_urls': [
723
                    {
724
                        'base_url': 'http://passerelle.example.net',
725
                        'saml-sp-metadata-url': 'http://passerelle.example.net/saml/metadata',
726
                    }
727
                ],
728
            },
729
        ],
730
        'users': [],
731
        'profile': {'fields': []},
732
    }
733

  
734
    with mock.patch('hobo.agent.authentic2.provisionning.notify_agents'):
735
        call_command('hobo_deploy', '--ignore-timestamp', 'http://sso.example.net', hobo_json(new_env))
736
    # check that liberty provider is updated
737
    with tenant_context(tenant):
738
        from authentic2.saml.models import LibertyProvider
739

  
740
        assert LibertyProvider.objects.count() == 1
741
        provider = LibertyProvider.objects.first()
742
        assert provider.metadata == meta2
743
        assert provider.entity_id == 'http://new-passerelle.example.net/saml/metadata'
744
        assert provider.pk == provider_id
tests_multipublik/conftest.py
23 23
        t.create_schema()
24 24
        return t
25 25

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

  
28 32
    def fin():
29 33
        from django.db import connection
30 34

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

  
36 41
    request.addfinalizer(fin)
tests_multipublik/test_multipublik.py
47 47
        assert combo.base_url == 'http://combo1.example.net/'
48 48
        assert combo.secondary is True
49 49

  
50
        assert Hobo.objects.count() == 2
50
        assert Hobo.objects.count() == 3
51 51
        # interco hobo
52 52
        hobo = Hobo.objects.get(slug='_interco_hobo')
53 53
        assert hobo.title == 'Hobo'
......
112 112
        assert combo.base_url == 'http://combo1.example.net/'
113 113
        assert combo.secondary is True
114 114

  
115
        assert Hobo.objects.count() == 2
115
        assert Hobo.objects.count() == 3
116 116
        # interco hobo
117 117
        hobo = Hobo.objects.get(slug='_interco_hobo')
118 118
        assert hobo.title == 'Hobo'
......
155 155
    with tenant_context(hobo2):
156 156
        assert Combo.objects.filter(secondary=True).count() == 1
157 157
        assert Combo.objects.filter(secondary=False).count() == 1
158

  
159
    # URL change in interco portal
160
    with tenant_context(hobo1):
161
        combo = Combo.objects.get(slug='portal')
162
        assert combo.base_url == 'http://combo1.example.net/'
163
        combo.change_base_url('http://new-combo1.example.net')
164
        combo.save()
165

  
166
        # check the interco hobo json
167
        hobo_json = get_hobo_json()
168
        for service in hobo_json['services']:
169
            if service['slug'] == 'portal':
170
                assert service['base_url'] == 'http://new-combo1.example.net/'
171
                assert len(service['legacy_urls']) == 1
172
                assert service['legacy_urls'][0]['base_url'] == 'http://combo1.example.net/'
173
                break
174
        else:
175
            assert False, "no portal found"
176

  
177
    # inform coll2 about interco environment
178
    HoboDeployCommand().handle(hobo2.base_url, get_hobo_json_filename(hobo1))
179
    with tenant_context(hobo2):
180
        # no extra combo created in coll 2
181
        assert Combo.objects.filter().count() == 2
182
        # interco portal url changed
183
        combo = Combo.objects.get(slug='_interco_portal')
184
        assert combo.base_url == 'http://new-combo1.example.net/'
185
        assert len(combo.legacy_urls) == 1
186
        assert combo.legacy_urls[0]['base_url'] == 'http://combo1.example.net/'
187

  
188
    # inform coll2 about interco environment a second time, check that nothing changes
189
    HoboDeployCommand().handle(hobo2.base_url, get_hobo_json_filename(hobo1))
190
    with tenant_context(hobo2):
191
        assert Combo.objects.filter().count() == 2
192
        combo = Combo.objects.get(slug='_interco_portal')
193
        assert combo.base_url == 'http://new-combo1.example.net/'
194
        assert len(combo.legacy_urls) == 1
195
        assert combo.legacy_urls[0]['base_url'] == 'http://combo1.example.net/'
196

  
197
    # URL change in coll2 portal
198
    with tenant_context(hobo2):
199
        combo = Combo.objects.get(slug='portal')
200
        assert combo.base_url == 'http://combo2.example.net/'
201
        combo.change_base_url('http://new-combo2.example.net')
202
        combo.save()
203

  
204
        # check the coll2 hobo json
205
        hobo_json = get_hobo_json()
206
        for service in hobo_json['services']:
207
            if service['slug'] == 'portal':
208
                assert service['base_url'] == 'http://new-combo2.example.net/'
209
                assert len(service['legacy_urls']) == 1
210
                assert service['legacy_urls'][0]['base_url'] == 'http://combo2.example.net/'
211
                break
212
        else:
213
            assert False, "no portal found"
214

  
215
    # inform interco about coll2 environment
216
    HoboDeployCommand().handle(hobo1.base_url, get_hobo_json_filename(hobo2))
217
    with tenant_context(hobo1):
218
        # no extra combo created in interco
219
        assert Combo.objects.filter().count() == 3
220
        # coll2 portal url changed
221
        combo = Combo.objects.get(slug='_hobo-coll2_portal')
222
        assert combo.base_url == 'http://new-combo2.example.net/'
223
        assert len(combo.legacy_urls) == 1
224
        assert combo.legacy_urls[0]['base_url'] == 'http://combo2.example.net/'
225

  
226
    # URL change on the primary hobo
227
    with tenant_context(hobo1):
228
        hobo = Hobo.objects.get(slug='hobo')
229
        assert hobo.base_url == 'http://tenant1.example.net/'
230
        hobo.change_base_url('http://new-tenant1.example.net')
231
        hobo.save()
232

  
233
        # check the interco hobo json
234
        hobo_json = get_hobo_json()
235
        for service in hobo_json['services']:
236
            if service['slug'] == 'hobo':
237
                assert service['base_url'] == 'http://new-tenant1.example.net/'
238
                assert len(service['legacy_urls']) == 1
239
                assert service['legacy_urls'][0]['base_url'] == 'http://tenant1.example.net/'
240
                break
241
        else:
242
            assert False, 'no hobo found'
243

  
244
    # inform coll2 about interco environment
245
    HoboDeployCommand().handle(hobo2.base_url, get_hobo_json_filename(hobo1))
246
    with tenant_context(hobo2):
247
        # no extra hobo created in coll 2
248
        assert Hobo.objects.count() == 3
249
        # interco hobo url changed
250
        hobo = Hobo.objects.get(slug='_interco_hobo')
251
        assert hobo.base_url == 'http://new-tenant1.example.net/'
252
        assert len(hobo.legacy_urls) == 1
253
        assert hobo.legacy_urls[0]['base_url'] == 'http://tenant1.example.net/'
254

  
255
    # URL change on coll2 hobo (initiated by the interco tenant)
256
    with tenant_context(hobo1):
257
        hobo2 = Hobo.objects.get(slug='hobo-coll2')
258
        assert hobo2.base_url == 'http://hobo2.example.net/'
259
        hobo2.change_base_url('http://new-hobo2.example.net')
260
        hobo2.save()
261

  
262
    # inform coll2 about interco environment
263
    HoboDeployCommand().handle(hobo2.base_url, get_hobo_json_filename(hobo1))
264

  
265
    hobo2 = TenantMiddleware.get_tenant_by_hostname('new-hobo2.example.net')
266
    with tenant_context(hobo2):
267
        # no extra hobo created in coll 2
268
        assert Hobo.objects.count() == 3
269
        # coll2 hobo url changed
270
        hobo = Hobo.objects.get(slug='hobo')
271
        assert hobo.base_url == 'http://new-hobo2.example.net/'
272
        assert len(hobo.legacy_urls) == 1
273
        assert hobo.legacy_urls[0]['base_url'] == 'http://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
-