Projet

Général

Profil

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

Emmanuel Cazenave, 16 février 2022 12:08

Télécharger (30,3 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 |  26 ++-
 .../hobo/management/commands/hobo_deploy.py   |  31 ++-
 .../migrations/0024_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, 515 insertions(+), 21 deletions(-)
 create mode 100644 hobo/environment/migrations/0024_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

  
77
        legacy_domain = None
78
        tenant_created = False
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)
92
            tenant_created = True
83 93
            tenant = TenantMiddleware.get_tenant_by_hostname(domain)
84 94

  
95
        if tenant_created and legacy_domain and self.me['service-id'] == 'hobo':
96
            # need to update local hobo
97
            with tenant_context(tenant):
98
                import hobo.environment.utils
99

  
100
                local_hobo = hobo.environment.utils.get_or_create_local_hobo()
101
                if local_hobo.get_base_url_path() != self.me['base_url']:
102
                    local_hobo.change_base_url(self.me['base_url'])
103
                    local_hobo.save()
104

  
85 105
        timestamp = hobo_environment.get('timestamp')
86 106
        tenant_hobo_json = os.path.join(tenant.get_directory(), 'hobo.json')
87 107
        if os.path.exists(tenant_hobo_json):
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

  
......
63 64
                    slug_prefix = '_%s_' % hobo_environment['variables']['ou-slug']
64 65

  
65 66
                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
                )
67

  
68
                service, created = None, False
69
                for legacy_urls in service_dict.get('legacy_urls', []):
70
                    try:
71
                        service = service_klass.objects.get(base_url=legacy_urls['base_url'], secondary=True)
72
                        service.change_base_url(service_dict['base_url'])
73
                        break
74
                    except service_klass.DoesNotExist:
75
                        pass
76

  
77
                if not service:
78
                    service, created = service_klass.objects.get_or_create(
79
                        base_url=service_dict['base_url'],
80
                        secondary=True,
81
                        defaults={
82
                            'title': service_dict['title'],
83
                            'slug': service_slug,
84
                            'secret_key': service_dict.get('secret_key'),
85
                        },
86
                    )
87

  
75 88
                service.title = service_dict['title']
76 89
                service.secret_key = service_dict.get('secret_key')
77 90
                service.template_name = service_dict.get('template_name') or ''
hobo/environment/migrations/0024_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', '0023_populate_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
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
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
-