~abentley/juju-ci-tools/client-from-config-4

« back to all changes in this revision

Viewing changes to tests/test_deploy_stack.py

  • Committer: Aaron Bentley
  • Date: 2016-03-02 16:04:04 UTC
  • mto: This revision was merged to the branch mainline in revision 1307.
  • Revision ID: aaron.bentley@canonical.com-20160302160404-0l1z6lb3oanrgvxo
assess_heterogeneous_control does not tear down with inappropriate client.

Show diffs side-by-side

added added

removed removed

Lines of Context:
65
65
)
66
66
from tests import (
67
67
    FakeHomeTestCase,
68
 
    temp_os_env,
69
68
    use_context,
70
69
)
71
 
from tests.test_jujupy import (
 
70
from test_jujupy import (
72
71
    assert_juju_call,
73
 
    fake_juju_client,
74
 
    fake_juju_client_optional_jes,
 
72
    FakeJujuClient,
75
73
    FakePopen,
76
74
    observable_temp_file,
77
75
)
140
138
             "ReturnCode": 255,
141
139
             "Stderr": "Permission denied (publickey,password)"}])
142
140
        with patch.object(client, 'get_juju_output', autospec=True,
143
 
                          return_value=response_ok) as gjo_mock:
 
141
                          return_value=response_ok):
144
142
            responses = assess_juju_run(client)
145
143
            for machine in responses:
146
144
                self.assertFalse(machine.get('ReturnCode', False))
147
145
                self.assertIn(machine.get('MachineId'), ["1", "2"])
148
146
            self.assertEqual(len(responses), 2)
149
 
        gjo_mock.assert_called_once_with(
150
 
            'run', '--format', 'json', '--application',
151
 
            'dummy-source,dummy-sink', 'uname')
152
147
        with patch.object(client, 'get_juju_output', autospec=True,
153
 
                          return_value=response_err) as gjo_mock:
 
148
                          return_value=response_err):
154
149
            with self.assertRaises(ValueError):
155
150
                responses = assess_juju_run(client)
156
 
        gjo_mock.assert_called_once_with(
157
 
            'run', '--format', 'json', '--application',
158
 
            'dummy-source,dummy-sink', 'uname')
159
151
 
160
152
    def test_safe_print_status(self):
161
153
        env = JujuData('foo', {'type': 'nonlocal'})
162
154
        client = EnvJujuClient(env, None, None)
163
 
        error = subprocess.CalledProcessError(1, 'status', 'status error')
164
 
        with patch.object(client, 'juju', autospec=True,
165
 
                          side_effect=[error]) as mock:
166
 
            with patch.object(client, 'iter_model_clients',
167
 
                              return_value=[client]) as imc_mock:
168
 
                safe_print_status(client)
 
155
        with patch.object(
 
156
                client, 'juju', autospec=True,
 
157
                side_effect=subprocess.CalledProcessError(
 
158
                    1, 'status', 'status error')
 
159
        ) as mock:
 
160
            safe_print_status(client)
169
161
        mock.assert_called_once_with('show-status', ('--format', 'yaml'))
170
 
        imc_mock.assert_called_once_with()
171
162
 
172
163
    def test_update_env(self):
173
164
        env = SimpleEnvironment('foo', {'type': 'paas'})
196
187
    def test_dump_juju_timings(self):
197
188
        env = JujuData('foo', {'type': 'bar'})
198
189
        client = EnvJujuClient(env, None, None)
199
 
        client._backend.juju_timings = {("juju", "op1"): [1],
200
 
                                        ("juju", "op2"): [2]}
 
190
        client.juju_timings = {("juju", "op1"): [1], ("juju", "op2"): [2]}
201
191
        expected = {"juju op1": [1], "juju op2": [2]}
202
192
        with temp_dir() as fake_dir:
203
193
            dump_juju_timings(client, fake_dir)
442
432
                '10.10.0.1',
443
433
                'sudo chmod -Rf go+r /var/log/cloud-init*.log'
444
434
                ' /var/log/juju/*.log'
445
 
                ' /var/lib/juju/containers/juju-*-lxc-*/'
446
 
                ' /var/log/lxd/juju-*'
447
 
                ' /var/log/lxd/lxd.log'
448
 
                ' /var/log/syslog'
449
 
                ' /var/log/mongodb/mongodb.log'
450
 
                ' /etc/network/interfaces'
451
 
                ' /home/ubuntu/ifconfig.log'
452
 
                ),),
 
435
                ' /var/lib/juju/containers/juju-*-lxc-*/'),),
453
436
            cc_mock.call_args_list[0][0])
454
437
        self.assertEqual(
455
438
            (get_timeout_prefix(120) + (
456
 
                'ssh',
457
 
                '-o', 'User ubuntu',
458
 
                '-o', 'UserKnownHostsFile /dev/null',
459
 
                '-o', 'StrictHostKeyChecking no',
460
 
                '-o', 'PasswordAuthentication no',
461
 
                '10.10.0.1',
462
 
                'ifconfig > /home/ubuntu/ifconfig.log'),),
463
 
            cc_mock.call_args_list[1][0])
464
 
        self.assertEqual(
465
 
            (get_timeout_prefix(120) + (
466
439
                'scp', '-rC',
467
440
                '-o', 'User ubuntu',
468
441
                '-o', 'UserKnownHostsFile /dev/null',
471
444
                '10.10.0.1:/var/log/cloud-init*.log',
472
445
                '10.10.0.1:/var/log/juju/*.log',
473
446
                '10.10.0.1:/var/lib/juju/containers/juju-*-lxc-*/',
474
 
                '10.10.0.1:/var/log/lxd/juju-*',
475
 
                '10.10.0.1:/var/log/lxd/lxd.log',
476
 
                '10.10.0.1:/var/log/syslog',
477
 
                '10.10.0.1:/var/log/mongodb/mongodb.log',
478
 
                '10.10.0.1:/etc/network/interfaces',
479
 
                '10.10.0.1:/home/ubuntu/ifconfig.log',
480
447
                '/foo'),),
481
 
            cc_mock.call_args_list[2][0])
 
448
            cc_mock.call_args_list[1][0])
482
449
 
483
450
    def test_copy_remote_logs_windows(self):
484
451
        remote = remote_from_address('10.10.0.1', series="win2012hvr2")
502
469
        with patch('subprocess.check_output', side_effect=remote_op) as co:
503
470
            with patch('deploy_stack.wait_for_port', autospec=True):
504
471
                copy_remote_logs(remote_from_address('10.10.0.1'), '/foo')
505
 
        self.assertEqual(3, co.call_count)
 
472
        self.assertEqual(2, co.call_count)
506
473
        self.assertEqual(
507
474
            ["DEBUG ssh -o 'User ubuntu' -o 'UserKnownHostsFile /dev/null' "
508
475
             "-o 'StrictHostKeyChecking no' -o 'PasswordAuthentication no' "
509
476
             "10.10.0.1 'sudo chmod -Rf go+r /var/log/cloud-init*.log "
510
 
             "/var/log/juju/*.log /var/lib/juju/containers/juju-*-lxc-*/ "
511
 
             "/var/log/lxd/juju-* "
512
 
             "/var/log/lxd/lxd.log "
513
 
             "/var/log/syslog "
514
 
             "/var/log/mongodb/mongodb.log "
515
 
             "/etc/network/interfaces "
516
 
             "/home/ubuntu/ifconfig.log'",
 
477
             "/var/log/juju/*.log /var/lib/juju/containers/juju-*-lxc-*/'",
517
478
             'WARNING Could not allow access to the juju logs:',
518
479
             'WARNING None',
519
 
             "DEBUG ssh -o 'User ubuntu' -o 'UserKnownHostsFile /dev/null' "
520
 
             "-o 'StrictHostKeyChecking no' -o 'PasswordAuthentication no' "
521
 
             "10.10.0.1 'ifconfig > /home/ubuntu/ifconfig.log'",
522
 
             'WARNING Could not capture ifconfig state:',
523
 
             'WARNING None', 'WARNING Could not retrieve some or all logs:',
524
 
             'WARNING CalledProcessError()',
525
 
             ],
 
480
             'WARNING Could not retrieve some or all logs:',
 
481
             'WARNING CalledProcessError()'],
526
482
            self.log_stream.getvalue().splitlines())
527
483
 
528
484
    def test_get_machines_for_logs(self):
647
603
 
648
604
    def test_deploy_dummy_stack_sets_centos_constraints(self):
649
605
        env = JujuData('foo', {'type': 'maas'})
650
 
        client = EnvJujuClient(env, '2.0.0', '/foo/juju')
 
606
        client = EnvJujuClient(env, None, '/foo/juju')
651
607
        with patch('subprocess.check_call', autospec=True) as cc_mock:
652
608
            with patch.object(EnvJujuClient, 'wait_for_started'):
653
609
                with patch('deploy_stack.get_random_string',
654
610
                           return_value='fake-token', autospec=True):
655
 
                    deploy_dummy_stack(client, 'centos')
 
611
                    deploy_dummy_stack(client, 'local:centos/foo')
656
612
        assert_juju_call(self, cc_mock, client,
657
613
                         ('juju', '--show-log', 'set-model-constraints', '-m',
658
 
                          'foo:foo', 'tags=MAAS_NIC_1'), 0)
 
614
                          'foo', 'tags=MAAS_NIC_1'), 0)
659
615
 
660
616
    def test_assess_juju_relations(self):
661
617
        env = JujuData('foo', {'type': 'nonlocal'})
669
625
                               autospec=True) as ct_mock:
670
626
                        assess_juju_relations(client)
671
627
        assert_juju_call(self, cc_mock, client, (
672
 
            'juju', '--show-log', 'set-config', '-m', 'foo:foo',
673
 
            'dummy-source', 'token=fake-token'), 0)
 
628
            'juju', '--show-log', 'set-config', '-m', 'foo', 'dummy-source',
 
629
            'token=fake-token'), 0)
674
630
        ct_mock.assert_called_once_with(client, 'fake-token')
675
631
 
676
 
    def test_deploy_dummy_stack_centos(self):
677
 
        client = fake_juju_client()
678
 
        client.bootstrap()
679
 
        with patch.object(client, 'deploy', autospec=True) as dp_mock:
680
 
            with temp_os_env('JUJU_REPOSITORY', '/tmp/repo'):
681
 
                deploy_dummy_stack(client, 'centos7')
682
 
        calls = [
683
 
            call('/tmp/repo/charms-centos/dummy-source', series='centos7'),
684
 
            call('/tmp/repo/charms-centos/dummy-sink', series='centos7')]
685
 
        self.assertEqual(dp_mock.mock_calls, calls)
686
 
 
687
 
    def test_deploy_dummy_stack_win(self):
688
 
        client = fake_juju_client()
689
 
        client.bootstrap()
690
 
        with patch.object(client, 'deploy', autospec=True) as dp_mock:
691
 
            with temp_os_env('JUJU_REPOSITORY', '/tmp/repo'):
692
 
                deploy_dummy_stack(client, 'win2012hvr2')
693
 
        calls = [
694
 
            call('/tmp/repo/charms-win/dummy-source', series='win2012hvr2'),
695
 
            call('/tmp/repo/charms-win/dummy-sink', series='win2012hvr2')]
696
 
        self.assertEqual(dp_mock.mock_calls, calls)
697
 
 
698
632
    def test_deploy_dummy_stack(self):
699
633
        env = JujuData('foo', {'type': 'nonlocal'})
700
 
        client = EnvJujuClient(env, '2.0.0', '/foo/juju')
 
634
        client = EnvJujuClient(env, None, '/foo/juju')
701
635
        status = yaml.safe_dump({
702
636
            'machines': {'0': {'agent-state': 'started'}},
703
637
            'services': {
720
654
                with patch('deploy_stack.get_random_string',
721
655
                           return_value='fake-token', autospec=True):
722
656
                    with patch('sys.stdout', autospec=True):
723
 
                        with temp_os_env('JUJU_REPOSITORY', '/tmp/repo'):
724
 
                            deploy_dummy_stack(client, 'bar-')
725
 
        assert_juju_call(self, cc_mock, client, (
726
 
            'juju', '--show-log', 'deploy', '-m', 'foo:foo',
727
 
            '/tmp/repo/charms/dummy-source', '--series', 'bar-'), 0)
728
 
        assert_juju_call(self, cc_mock, client, (
729
 
            'juju', '--show-log', 'deploy', '-m', 'foo:foo',
730
 
            '/tmp/repo/charms/dummy-sink', '--series', 'bar-'), 1)
731
 
        assert_juju_call(self, cc_mock, client, (
732
 
            'juju', '--show-log', 'add-relation', '-m', 'foo:foo',
 
657
                        deploy_dummy_stack(client, 'bar-')
 
658
        assert_juju_call(self, cc_mock, client, (
 
659
            'juju', '--show-log', 'deploy', '-m', 'foo', 'bar-dummy-source'),
 
660
            0)
 
661
        assert_juju_call(self, cc_mock, client, (
 
662
            'juju', '--show-log', 'deploy', '-m', 'foo', 'bar-dummy-sink'), 1)
 
663
        assert_juju_call(self, cc_mock, client, (
 
664
            'juju', '--show-log', 'add-relation', '-m', 'foo',
733
665
            'dummy-source', 'dummy-sink'), 2)
734
666
        assert_juju_call(self, cc_mock, client, (
735
 
            'juju', '--show-log', 'expose', '-m', 'foo:foo', 'dummy-sink'), 3)
 
667
            'juju', '--show-log', 'expose', '-m', 'foo', 'dummy-sink'), 3)
736
668
        self.assertEqual(cc_mock.call_count, 4)
737
669
        self.assertEqual(
738
670
            [
739
 
                call('show-status', '--format', 'yaml', controller=False)
 
671
                call('show-status', '--format', 'yaml'),
740
672
            ],
741
673
            gjo_mock.call_args_list)
742
674
 
743
 
        client = client.clone(version='1.25.0')
744
 
        with patch.object(client, 'get_juju_output', side_effect=output,
745
 
                          autospec=True) as gjo_mock:
746
 
            with patch('subprocess.check_call', autospec=True) as cc_mock:
747
 
                with patch('deploy_stack.get_random_string',
748
 
                           return_value='fake-token', autospec=True):
749
 
                    with patch('sys.stdout', autospec=True):
750
 
                        with temp_os_env('JUJU_REPOSITORY', '/tmp/repo'):
751
 
                            deploy_dummy_stack(client, 'bar-')
752
 
        assert_juju_call(self, cc_mock, client, (
753
 
            'juju', '--show-log', 'deploy', '-m', 'foo:foo',
754
 
            'local:bar-/dummy-source', '--series', 'bar-'), 0)
755
 
        assert_juju_call(self, cc_mock, client, (
756
 
            'juju', '--show-log', 'deploy', '-m', 'foo:foo',
757
 
            'local:bar-/dummy-sink', '--series', 'bar-'), 1)
758
 
 
759
675
 
760
676
def fake_SimpleEnvironment(name):
761
677
    return SimpleEnvironment(name, {})
767
683
 
768
684
class FakeBootstrapManager:
769
685
 
770
 
    def __init__(self, client, keep_env=False):
 
686
    def __init__(self, client):
771
687
        self.client = client
772
688
        self.tear_down_client = client
773
689
        self.entered_top = False
779
695
        self.torn_down = False
780
696
        self.permanent = False
781
697
        self.known_hosts = {'0': '0.example.org'}
782
 
        self.keep_env = keep_env
783
698
 
784
699
    @contextmanager
785
700
    def top_context(self):
793
708
    def bootstrap_context(self, machines):
794
709
        initial_home = self.client.env.juju_home
795
710
        self.client.env.environment = self.client.env.environment + '-temp'
796
 
        self.client.env.controller.name = self.client.env.environment
797
711
        try:
798
712
            self.entered_bootstrap = True
799
713
            self.client.env.juju_home = os.path.join(initial_home, 'isolated')
800
 
            self.client.bootstrap()
801
714
            yield
802
715
        finally:
803
716
            self.exited_bootstrap = True
810
723
            self.entered_runtime = True
811
724
            yield
812
725
        finally:
813
 
            if not self.keep_env:
814
 
                self.tear_down()
 
726
            self.tear_down()
815
727
            self.exited_runtime = True
816
728
 
817
729
    def tear_down(self):
818
 
        tear_down_meth = getattr(
819
 
            self.tear_down_client, 'destroy_environment',
820
 
            self.tear_down_client.kill_controller)
821
 
        tear_down_meth()
822
 
        self.torn_down = True
 
730
        self.tear_down_client.destroy_environment()
 
731
        self.tear_down_client.torn_down = True
823
732
 
824
733
    @contextmanager
825
734
    def booted_context(self, upload_tools):
836
745
    def ds_cxt(self):
837
746
        env = JujuData('foo', {})
838
747
        client = fake_EnvJujuClient(env)
839
 
        bc_cxt = patch('deploy_stack.client_from_config',
 
748
        bc_cxt = patch('jujupy.EnvJujuClient.by_version',
840
749
                       return_value=client)
841
750
        fc_cxt = patch('jujupy.SimpleEnvironment.from_config',
842
751
                       return_value=env)
922
831
                   autospec=True):
923
832
            with patch('deploy_stack._deploy_job', autospec=True) as ds_mock:
924
833
                deploy_job()
925
 
        ds_mock.assert_called_once_with(args, 'windows', 'trusty')
 
834
        ds_mock.assert_called_once_with(args, 'local:windows/', 'trusty')
926
835
 
927
836
    def test_deploy_job_changes_series_with_centos(self):
928
837
        args = Namespace(
935
844
                   autospec=True):
936
845
            with patch('deploy_stack._deploy_job', autospec=True) as ds_mock:
937
846
                deploy_job()
938
 
        ds_mock.assert_called_once_with(args, 'centos', 'trusty')
 
847
        ds_mock.assert_called_once_with(args, 'local:centos/', 'trusty')
939
848
 
940
849
 
941
850
class TestTestUpgrade(FakeHomeTestCase):
944
853
        'juju', '--show-log', 'run', '-e', 'foo', '--format', 'json',
945
854
        '--service', 'dummy-source,dummy-sink', 'uname')
946
855
    STATUS = (
947
 
        'juju', '--show-log', 'show-status', '-m', 'foo:foo',
948
 
        '--format', 'yaml')
949
 
    GET_ENV = ('juju', '--show-log', 'get-model-config', '-m', 'foo:foo',
 
856
        'juju', '--show-log', 'show-status', '-m', 'foo', '--format', 'yaml')
 
857
    GET_ENV = ('juju', '--show-log', 'get-model-config', '-m', 'foo',
950
858
               'tools-metadata-url')
951
859
 
952
860
    @classmethod
986
894
            assess_upgrade(old_client, '/bar/juju')
987
895
        new_client = EnvJujuClient(env, None, '/bar/juju')
988
896
        assert_juju_call(self, cc_mock, new_client, (
989
 
            'juju', '--show-log', 'upgrade-juju', '-m', 'foo:foo', '--version',
 
897
            'juju', '--show-log', 'upgrade-juju', '-m', 'foo', '--version',
990
898
            '2.0-alpha3'), 0)
991
899
        self.assertEqual(cc_mock.call_count, 1)
992
900
        assert_juju_call(self, co_mock, new_client, self.GET_ENV, 0)
1015
923
            bootstrap_host='example.org', machine=['example.com'],
1016
924
            series='angsty', agent_url='qux', agent_stream='escaped',
1017
925
            region='eu-west-northwest-5', logs='pine', keep_env=True)
1018
 
        with patch('deploy_stack.client_from_config') as fc_mock:
1019
 
            bs_manager = BootstrapManager.from_args(args)
1020
 
        fc_mock.assert_called_once_with('foo', 'bar', debug=True)
 
926
        with patch.object(SimpleEnvironment, 'from_config') as fc_mock:
 
927
            with patch.object(EnvJujuClient, 'by_version') as bv_mock:
 
928
                bs_manager = BootstrapManager.from_args(args)
 
929
        fc_mock.assert_called_once_with('foo')
 
930
        bv_mock.assert_called_once_with(fc_mock.return_value, 'bar',
 
931
                                        debug=True)
1021
932
        self.assertEqual('baz', bs_manager.temp_env_name)
1022
 
        self.assertIs(fc_mock.return_value, bs_manager.client)
1023
 
        self.assertIs(fc_mock.return_value, bs_manager.tear_down_client)
 
933
        self.assertIs(bv_mock.return_value, bs_manager.client)
 
934
        self.assertIs(bv_mock.return_value, bs_manager.tear_down_client)
1024
935
        self.assertEqual('example.org', bs_manager.bootstrap_host)
1025
936
        self.assertEqual(['example.com'], bs_manager.machines)
1026
937
        self.assertEqual('angsty', bs_manager.series)
1044
955
                agent_stream=None, region=None, log_dir=None, keep_env=None)
1045
956
 
1046
957
    def test_aws_machines_updates_bootstrap_host(self):
1047
 
        client = fake_juju_client()
 
958
        client = FakeJujuClient()
1048
959
        client.env.config['type'] = 'manual'
1049
960
        bs_manager = BootstrapManager(
1050
961
            'foobar', client, client, None, [], None, None, None, None,
1062
973
            bootstrap_host=None, machine=['example.com'],
1063
974
            series='angsty', agent_url='qux', agent_stream='escaped',
1064
975
            region='eu-west-northwest-5', logs='pine', keep_env=True)
1065
 
        with patch('deploy_stack.client_from_config'):
1066
 
            bs_manager = BootstrapManager.from_args(args)
 
976
        with patch.object(SimpleEnvironment, 'from_config'):
 
977
            with patch.object(EnvJujuClient, 'by_version'):
 
978
                bs_manager = BootstrapManager.from_args(args)
1067
979
        self.assertIs(None, bs_manager.bootstrap_host)
1068
980
        self.assertEqual({}, bs_manager.known_hosts)
1069
981
 
1070
982
    def make_client(self):
1071
983
        client = MagicMock()
1072
 
        client.env = SimpleEnvironment(
1073
 
            'foo', {'type': 'baz'}, use_context(self, temp_dir()))
 
984
        client.env.environment = 'foo'
1074
985
        client.is_jes_enabled.return_value = False
 
986
        client.env.config = {'type': 'baz'}
1075
987
        client.get_matching_agent_version.return_value = '3.14'
 
988
        client.env.juju_home = use_context(self, temp_dir())
1076
989
        client.get_cache_path.return_value = get_cache_path(
1077
990
            client.env.juju_home)
1078
991
        return client
1079
992
 
1080
993
    def test_bootstrap_context_tear_down(self):
1081
 
        client = fake_juju_client()
 
994
        client = FakeJujuClient()
1082
995
        client.env.juju_home = use_context(self, temp_dir())
1083
996
        initial_home = client.env.juju_home
1084
997
        bs_manager = BootstrapManager(
1180
1093
            self.assertEqual(orig_home, get_juju_home())
1181
1094
 
1182
1095
    def test_bootstrap_context_calls_update_env(self):
1183
 
        client = fake_juju_client()
 
1096
        client = FakeJujuClient()
1184
1097
        client.env.juju_home = use_context(self, temp_dir())
1185
1098
        ue_mock = use_context(
1186
1099
            self, patch('deploy_stack.update_env', wraps=update_env))
1201
1114
            'bootstrap.example.org', 22, timeout=120)
1202
1115
 
1203
1116
    def test_bootstrap_context_calls_update_env_omit(self):
1204
 
        client = fake_juju_client()
 
1117
        client = FakeJujuClient()
1205
1118
        client.env.juju_home = use_context(self, temp_dir())
1206
1119
        ue_mock = use_context(
1207
1120
            self, patch('deploy_stack.update_env', wraps=update_env))
1241
1154
                bs_manager.tear_down()
1242
1155
        self.assertEqual('barfoo', tear_down_client.env.juju_home)
1243
1156
 
1244
 
    def test_dump_all_no_jes_one_model(self):
1245
 
        client = fake_juju_client()
1246
 
        client.bootstrap()
1247
 
        with temp_dir() as log_dir:
1248
 
            bs_manager = BootstrapManager(
1249
 
                'foobar', client, client,
1250
 
                None, [], None, None, None, None, log_dir, False,
1251
 
                False, jes_enabled=False)
1252
 
            with patch('deploy_stack.dump_env_logs_known_hosts'):
1253
 
                with patch.object(client, 'iter_model_clients') as imc_mock:
1254
 
                    bs_manager.dump_all_logs()
1255
 
        self.assertEqual(0, imc_mock.call_count)
1256
 
 
1257
 
    def test_dump_all_multi_model(self):
1258
 
        client = fake_juju_client()
1259
 
        client.bootstrap()
1260
 
        with temp_dir() as log_dir:
1261
 
            bs_manager = BootstrapManager(
1262
 
                'foobar', client, client,
1263
 
                None, [], None, None, None, None, log_dir, False,
1264
 
                permanent=True, jes_enabled=True)
1265
 
            with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1266
 
                with patch.object(bs_manager, '_should_dump',
1267
 
                                  return_value=True):
1268
 
                    bs_manager.dump_all_logs()
1269
 
 
1270
 
        clients = dict((c[1][0].env.environment, c[1][0])
1271
 
                       for c in del_mock.mock_calls)
1272
 
        self.assertItemsEqual(
1273
 
            [call(client, os.path.join(log_dir, 'name'), None, {}),
1274
 
             call(clients['controller'], os.path.join(log_dir, 'controller'),
1275
 
                  'foo/models/cache.yaml', {})],
1276
 
            del_mock.mock_calls)
1277
 
 
1278
 
    def test_dump_all_multi_model_iter_failure(self):
1279
 
        client = fake_juju_client()
1280
 
        client.bootstrap()
1281
 
        with temp_dir() as log_dir:
1282
 
            bs_manager = BootstrapManager(
1283
 
                'foobar', client, client,
1284
 
                None, [], None, None, None, None, log_dir, False,
1285
 
                permanent=True, jes_enabled=True)
1286
 
            with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1287
 
                with patch.object(client, 'iter_model_clients',
1288
 
                                  side_effect=Exception):
1289
 
                    with patch.object(bs_manager, '_should_dump',
1290
 
                                      return_value=True):
1291
 
                        bs_manager.dump_all_logs()
1292
 
 
1293
 
        clients = dict((c[1][0].env.environment, c[1][0])
1294
 
                       for c in del_mock.mock_calls)
1295
 
 
1296
 
        self.assertItemsEqual(
1297
 
            [call(client, os.path.join(log_dir, 'name'), None, {}),
1298
 
             call(clients['controller'], os.path.join(log_dir, 'controller'),
1299
 
                  'foo/models/cache.yaml', {})],
1300
 
            del_mock.mock_calls)
1301
 
 
1302
 
    def test_dump_all_logs_uses_known_hosts(self):
1303
 
        client = fake_juju_client_optional_jes(jes_enabled=False)
1304
 
        with temp_dir() as log_dir:
1305
 
            bs_manager = BootstrapManager(
1306
 
                'foobar', client, client,
1307
 
                None, [], None, None, None, None, log_dir, False,
1308
 
                False, False)
1309
 
            bs_manager.known_hosts['2'] = 'example.org'
1310
 
            client.bootstrap()
1311
 
            with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1312
 
                with patch.object(bs_manager, '_should_dump',
1313
 
                                  return_value=True):
1314
 
                    bs_manager.dump_all_logs()
 
1157
    def test_runtime_context_uses_known_hosts(self):
 
1158
        client = FakeJujuClient()
 
1159
        bs_manager = BootstrapManager(
 
1160
            'foobar', client, client,
 
1161
            None, [], None, None, None, None, client.env.juju_home, False,
 
1162
            False, False)
 
1163
        bs_manager.known_hosts['2'] = 'example.org'
 
1164
        with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
 
1165
            with bs_manager.runtime_context([]):
 
1166
                pass
1315
1167
        del_mock.assert_called_once_with(
1316
 
            client, os.path.join(log_dir, 'name'),
1317
 
            'foo/environments/name.jenv', {
 
1168
            client, 'foo', 'foo/environments/name.jenv', {
1318
1169
                '2': 'example.org',
1319
1170
                })
1320
1171
 
1321
1172
    def test_runtime_context_looks_up_host(self):
1322
 
        client = fake_juju_client()
 
1173
        client = FakeJujuClient()
1323
1174
        client.bootstrap()
1324
1175
        bs_manager = BootstrapManager(
1325
1176
            'foobar', client, client,
1326
1177
            None, [], None, None, None, None, client.env.juju_home, False,
1327
 
            True, True)
1328
 
        with patch.object(bs_manager, 'dump_all_logs', autospec=True):
 
1178
            False, False)
 
1179
        with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1329
1180
            with bs_manager.runtime_context([]):
1330
 
                self.assertEqual({
1331
 
                    '0': '0.example.com'}, bs_manager.known_hosts)
 
1181
                pass
 
1182
        del_mock.assert_called_once_with(
 
1183
            client, 'foo', 'foo/environments/name.jenv', {
 
1184
                '0': '0.example.com',
 
1185
                })
1332
1186
 
1333
1187
    @patch('deploy_stack.dump_env_logs_known_hosts', autospec=True)
1334
1188
    def test_runtime_context_addable_machines_no_known_hosts(self, del_mock):
1335
 
        client = fake_juju_client()
 
1189
        client = FakeJujuClient()
1336
1190
        client.bootstrap()
1337
1191
        bs_manager = BootstrapManager(
1338
1192
            'foobar', client, client,
1339
1193
            None, [], None, None, None, None, client.env.juju_home, False,
1340
 
            True, True)
 
1194
            False, False)
1341
1195
        bs_manager.known_hosts = {}
1342
1196
        with patch.object(bs_manager.client, 'add_ssh_machines',
1343
1197
                          autospec=True) as ads_mock:
1344
 
            with patch.object(bs_manager, 'dump_all_logs', autospec=True):
1345
 
                with bs_manager.runtime_context(['baz']):
1346
 
                    ads_mock.assert_called_once_with(['baz'])
 
1198
            with bs_manager.runtime_context(['baz']):
 
1199
                ads_mock.assert_called_once_with(['baz'])
1347
1200
 
1348
 
    @patch('deploy_stack.BootstrapManager.dump_all_logs', autospec=True)
1349
 
    def test_runtime_context_addable_machines_with_known_hosts(self, dal_mock):
1350
 
        client = fake_juju_client()
1351
 
        client.bootstrap()
1352
 
        with temp_dir() as log_dir:
1353
 
            bs_manager = BootstrapManager(
1354
 
                'foobar', client, client,
1355
 
                None, [], None, None, None, None, log_dir, False,
1356
 
                True, True)
1357
 
            bs_manager.known_hosts['0'] = 'example.org'
1358
 
            with patch.object(bs_manager.client, 'add_ssh_machines',
1359
 
                              autospec=True) as ads_mock:
1360
 
                with bs_manager.runtime_context(['baz']):
1361
 
                    ads_mock.assert_called_once_with(['baz'])
 
1201
    @patch('deploy_stack.dump_env_logs_known_hosts', autospec=True)
 
1202
    def test_runtime_context_addable_machines_with_known_hosts(self, del_mock):
 
1203
        client = FakeJujuClient()
 
1204
        bs_manager = BootstrapManager(
 
1205
            'foobar', client, client,
 
1206
            None, [], None, None, None, None, client.env.juju_home, False,
 
1207
            False, False)
 
1208
        bs_manager.known_hosts['0'] = 'example.org'
 
1209
        with patch.object(bs_manager.client, 'add_ssh_machines',
 
1210
                          autospec=True) as ads_mock:
 
1211
            with bs_manager.runtime_context(['baz']):
 
1212
                ads_mock.assert_called_once_with(['baz'])
1362
1213
 
1363
1214
    def test_booted_context_handles_logged_exception(self):
1364
 
        client = fake_juju_client()
1365
 
        with temp_dir() as root:
1366
 
            log_dir = os.path.join(root, 'log-dir')
1367
 
            os.mkdir(log_dir)
1368
 
            bs_manager = BootstrapManager(
1369
 
                'foobar', client, client,
1370
 
                None, [], None, None, None, None, log_dir, False,
1371
 
                True, True)
1372
 
            juju_home = os.path.join(root, 'juju-home')
1373
 
            os.mkdir(juju_home)
 
1215
        client = FakeJujuClient()
 
1216
        bs_manager = BootstrapManager(
 
1217
            'foobar', client, client,
 
1218
            None, [], None, None, None, None, client.env.juju_home, False,
 
1219
            False, False)
 
1220
        with temp_dir() as juju_home:
1374
1221
            client.env.juju_home = juju_home
1375
1222
            with self.assertRaises(SystemExit):
1376
 
                with patch.object(bs_manager, 'dump_all_logs'):
1377
 
                    with bs_manager.booted_context(False):
1378
 
                        raise LoggedException()
 
1223
                with bs_manager.booted_context(False):
 
1224
                    raise LoggedException()
1379
1225
 
1380
1226
    def test_booted_context_omits_supported(self):
1381
 
        client = fake_juju_client()
 
1227
        client = FakeJujuClient(jes_enabled=True)
1382
1228
        client.env.juju_home = use_context(self, temp_dir())
1383
1229
        client.bootstrap_replaces = {'agent-version', 'series',
1384
1230
                                     'bootstrap-host', 'agent-stream'}
1396
1242
        self.assertEqual({
1397
1243
            'name': 'bar',
1398
1244
            'default-series': 'wacky',
1399
 
            'agent-metadata-url': 'url',
 
1245
            'tools-metadata-url': 'url',
1400
1246
            'type': 'foo',
1401
 
            'region': 'bar',
1402
 
            'test-mode': True,
1403
1247
            }, client.get_model_config())
1404
1248
        ue_mock.assert_called_with(client.env, 'bar', agent_url='url',
1405
1249
                                   region=None)
1422
1266
 
1423
1267
    @contextmanager
1424
1268
    def bc_context(self, client, log_dir=None, jes=None, keep_env=False):
1425
 
        dal_mock = self.addContext(
1426
 
            patch('deploy_stack.BootstrapManager.dump_all_logs'))
 
1269
        dl_mock = self.addContext(
 
1270
            patch('deploy_stack.dump_env_logs_known_hosts'))
1427
1271
        self.addContext(patch('deploy_stack.get_machine_dns_name',
1428
1272
                              return_value='foo', autospec=True))
1429
 
        if isinstance(client, EnvJujuClient1X):
1430
 
            models = []
1431
 
        else:
1432
 
            models = [{'name': 'controller'}, {'name': 'bar'}]
1433
 
        self.addContext(patch.object(client, '_get_models',
1434
 
                                     return_value=models, autospec=True))
1435
1273
        c_mock = self.addContext(patch('subprocess.call', autospec=True,
1436
1274
                                 return_value=0))
1437
 
        juju_name = os.path.basename(client.full_path)
1438
1275
        if jes:
1439
1276
            output = jes
1440
1277
            po_count = 0
1446
1283
            yield
1447
1284
        for help_index in range(po_count):
1448
1285
            assert_juju_call(self, po_mock, client, (
1449
 
                juju_name, '--show-log', 'help', 'commands'),
 
1286
                'juju', '--show-log', 'help', 'commands'),
1450
1287
                call_index=help_index)
1451
1288
        self.assertEqual(po_count, po_mock.call_count)
1452
 
        dal_mock.assert_called_once_with()
 
1289
        if jes:
 
1290
            runtime_config = client.get_cache_path()
 
1291
        else:
 
1292
            runtime_config = os.path.join(client.env.juju_home, 'environments',
 
1293
                                          'bar.jenv')
 
1294
        dl_mock.assert_called_once_with(client, log_dir, runtime_config,
 
1295
                                        {'0': 'foo'})
1453
1296
        if keep_env:
1454
1297
            tear_down_count = 1
1455
1298
        else:
1458
1301
            if jes:
1459
1302
                assert_juju_call(
1460
1303
                    self, c_mock, client, get_timeout_prefix(600) + (
1461
 
                        juju_name, '--show-log', jes, 'bar', '-y'), call_index)
 
1304
                        'juju', '--show-log', jes, 'bar', '-y'), call_index)
1462
1305
            else:
1463
1306
                assert_juju_call(
1464
1307
                    self, c_mock, client, get_timeout_prefix(600) + (
1465
 
                        juju_name, '--show-log', 'destroy-environment', 'bar',
 
1308
                        'juju', '--show-log', 'destroy-environment', 'bar',
1466
1309
                        '-y'), call_index)
1467
1310
        self.assertEqual(tear_down_count, c_mock.call_count)
1468
1311
 
1477
1320
                                  upload_tools=False):
1478
1321
                    pass
1479
1322
        assert_juju_call(self, cc_mock, client, (
1480
 
            'path', '--show-log', 'bootstrap', '--constraints',
 
1323
            'juju', '--show-log', 'bootstrap', '--constraints',
1481
1324
            'mem=2G', 'bar', 'paas/qux', '--config', config_file.name,
1482
 
            '--default-model', 'bar', '--agent-version', '1.23'), 0)
1483
 
        assert_juju_call(self, cc_mock, client, (
1484
 
            'path', '--show-log', 'list-controllers'), 1)
1485
 
        assert_juju_call(self, cc_mock, client, (
1486
 
            'path', '--show-log', 'list-models', '-c', 'bar'), 2)
1487
 
        assert_juju_call(self, cc_mock, client, (
1488
 
            'path', '--show-log', 'show-status', '-m', 'bar:controller',
1489
 
            '--format', 'yaml'), 3)
1490
 
        assert_juju_call(self, cc_mock, client, (
1491
 
            'path', '--show-log', 'show-status', '-m', 'bar:bar',
1492
 
            '--format', 'yaml'), 4)
 
1325
            '--agent-version', '1.23'), 0)
 
1326
        assert_juju_call(self, cc_mock, client, (
 
1327
            'juju', '--show-log', 'show-status', '-m', 'bar',
 
1328
            '--format', 'yaml'), 1)
1493
1329
 
1494
1330
    def test_bootstrap_context_non_jes(self):
1495
1331
        cc_mock = self.addContext(patch('subprocess.check_call'))
1500
1336
                              'log_dir', keep_env=False, upload_tools=False):
1501
1337
                pass
1502
1338
        assert_juju_call(self, cc_mock, client, (
1503
 
            'path', '--show-log', 'bootstrap', '-e', 'bar', '--constraints',
 
1339
            'juju', '--show-log', 'bootstrap', '-e', 'bar', '--constraints',
1504
1340
            'mem=2G'), 0)
1505
1341
        assert_juju_call(self, cc_mock, client, (
1506
 
            'path', '--show-log', 'status', '-e', 'bar',
 
1342
            'juju', '--show-log', 'status', '-e', 'bar',
1507
1343
            '--format', 'yaml'), 1)
1508
1344
 
1509
1345
    def test_keep_env(self):
1516
1352
                                  None, keep_env=True, upload_tools=False):
1517
1353
                    pass
1518
1354
        assert_juju_call(self, cc_mock, client, (
1519
 
            'path', '--show-log', 'bootstrap', '--constraints',
 
1355
            'juju', '--show-log', 'bootstrap', '--constraints',
1520
1356
            'mem=2G', 'bar', 'paas/qux', '--config', config_file.name,
1521
 
            '--default-model', 'bar', '--agent-version', '1.23'), 0)
1522
 
        assert_juju_call(self, cc_mock, client, (
1523
 
            'path', '--show-log', 'list-controllers'), 1)
1524
 
        assert_juju_call(self, cc_mock, client, (
1525
 
            'path', '--show-log', 'list-models', '-c', 'bar'), 2)
1526
 
        assert_juju_call(self, cc_mock, client, (
1527
 
            'path', '--show-log', 'show-status', '-m', 'bar:controller',
1528
 
            '--format', 'yaml'), 3)
1529
 
        assert_juju_call(self, cc_mock, client, (
1530
 
            'path', '--show-log', 'show-status', '-m', 'bar:bar',
1531
 
            '--format', 'yaml'), 4)
 
1357
            '--agent-version', '1.23'), 0)
 
1358
        assert_juju_call(self, cc_mock, client, (
 
1359
            'juju', '--show-log', 'show-status', '-m', 'bar',
 
1360
            '--format', 'yaml'), 1)
1532
1361
 
1533
1362
    def test_keep_env_non_jes(self):
1534
1363
        cc_mock = self.addContext(patch('subprocess.check_call'))
1539
1368
                              keep_env=True, upload_tools=False):
1540
1369
                pass
1541
1370
        assert_juju_call(self, cc_mock, client, (
1542
 
            'path', '--show-log', 'bootstrap', '-e', 'bar', '--constraints',
 
1371
            'juju', '--show-log', 'bootstrap', '-e', 'bar', '--constraints',
1543
1372
            'mem=2G'), 0)
1544
1373
        assert_juju_call(self, cc_mock, client, (
1545
 
            'path', '--show-log', 'status', '-e', 'bar',
 
1374
            'juju', '--show-log', 'status', '-e', 'bar',
1546
1375
            '--format', 'yaml'), 1)
1547
1376
 
1548
1377
    def test_upload_tools(self):
1555
1384
                                  None, keep_env=False, upload_tools=True):
1556
1385
                    pass
1557
1386
        assert_juju_call(self, cc_mock, client, (
1558
 
            'path', '--show-log', 'bootstrap', '--upload-tools',
 
1387
            'juju', '--show-log', 'bootstrap', '--upload-tools',
1559
1388
            '--constraints', 'mem=2G', 'bar', 'paas/qux', '--config',
1560
 
            config_file.name, '--default-model', 'bar'), 0)
 
1389
            config_file.name), 0)
1561
1390
 
1562
1391
    def test_upload_tools_non_jes(self):
1563
1392
        cc_mock = self.addContext(patch('subprocess.check_call'))
1568
1397
                              keep_env=False, upload_tools=True):
1569
1398
                pass
1570
1399
        assert_juju_call(self, cc_mock, client, (
1571
 
            'path', '--show-log', 'bootstrap', '-e', 'bar', '--upload-tools',
 
1400
            'juju', '--show-log', 'bootstrap', '-e', 'bar', '--upload-tools',
1572
1401
            '--constraints', 'mem=2G'), 0)
1573
1402
 
1574
1403
    def test_calls_update_env_2(self):
1587
1416
            client.env, 'bar', agent_url='url', agent_stream='devel',
1588
1417
            series='wacky', bootstrap_host=None, region=None)
1589
1418
        assert_juju_call(self, cc_mock, client, (
1590
 
            'path', '--show-log', 'bootstrap', '--constraints', 'mem=2G',
 
1419
            'juju', '--show-log', 'bootstrap', '--constraints', 'mem=2G',
1591
1420
            'bar', 'paas/qux', '--config', config_file.name,
1592
 
            '--default-model', 'bar', '--agent-version', '1.23',
1593
 
            '--bootstrap-series', 'wacky'), 0)
 
1421
            '--agent-version', '1.23', '--bootstrap-series', 'wacky'), 0)
1594
1422
 
1595
1423
    def test_calls_update_env_1(self):
1596
1424
        cc_mock = self.addContext(patch('subprocess.check_call'))
1606
1434
            client.env, 'bar', series='wacky', bootstrap_host=None,
1607
1435
            agent_url='url', agent_stream='devel', region=None)
1608
1436
        assert_juju_call(self, cc_mock, client, (
1609
 
            'path', '--show-log', 'bootstrap', '-e', 'bar',
 
1437
            'juju', '--show-log', 'bootstrap', '-e', 'bar',
1610
1438
            '--constraints', 'mem=2G'), 0)
1611
1439
 
1612
1440
    def test_calls_update_env_non_jes(self):
1623
1451
            client.env, 'bar', series='wacky', bootstrap_host=None,
1624
1452
            agent_url='url', agent_stream='devel', region=None)
1625
1453
        assert_juju_call(self, cc_mock, client, (
1626
 
            'path', '--show-log', 'bootstrap', '-e', 'bar',
 
1454
            'juju', '--show-log', 'bootstrap', '-e', 'bar',
1627
1455
            '--constraints', 'mem=2G'), 0)
1628
1456
 
1629
1457
    def test_with_bootstrap_failure(self):
1661
1489
        timeout_path = get_timeout_path()
1662
1490
        assert_juju_call(self, call_mock, client, (
1663
1491
            sys.executable, timeout_path, '600.00', '--',
1664
 
            'path', '--show-log', 'kill-controller', 'bar', '-y'
 
1492
            'juju', '--show-log', 'kill-controller', 'bar', '-y'
1665
1493
            ), 0)
1666
1494
        assert_juju_call(self, call_mock, client, (
1667
1495
            sys.executable, timeout_path, '600.00', '--',
1668
 
            'path', '--show-log', 'kill-controller', 'bar', '-y'
 
1496
            'juju', '--show-log', 'kill-controller', 'bar', '-y'
1669
1497
            ), 1)
1670
1498
        self.assertEqual(2, call_mock.call_count)
1671
1499
        self.assertEqual(0, po_mock.call_count)
1704
1532
        timeout_path = get_timeout_path()
1705
1533
        assert_juju_call(self, call_mock, client, (
1706
1534
            sys.executable, timeout_path, '600.00', '--',
1707
 
            'path', '--show-log', 'destroy-environment', 'bar', '-y'
 
1535
            'juju', '--show-log', 'destroy-environment', 'bar', '-y'
1708
1536
            ), 0)
1709
1537
        assert_juju_call(self, call_mock, client, (
1710
1538
            sys.executable, timeout_path, '600.00', '--',
1711
 
            'path', '--show-log', 'destroy-environment', 'bar', '-y'
 
1539
            'juju', '--show-log', 'destroy-environment', 'bar', '-y'
1712
1540
            ), 1)
1713
1541
        self.assertEqual(2, call_mock.call_count)
1714
1542
        assert_juju_call(self, po_mock, client, (
1715
 
            'path', '--show-log', 'help', 'commands'), 0)
 
1543
            'juju', '--show-log', 'help', 'commands'), 0)
1716
1544
        assert_juju_call(self, po_mock, client, (
1717
 
            'path', '--show-log', 'help', 'commands'), 1)
 
1545
            'juju', '--show-log', 'help', 'commands'), 1)
1718
1546
        self.assertEqual(2, po_mock.call_count)
1719
1547
 
1720
1548
    def test_jes(self):
1748
1576
                pass
1749
1577
        self.assertEqual('steve', client.env.config['region'])
1750
1578
 
1751
 
    def test_status_error_raises(self):
1752
 
        """An error on final show-status propagates so an assess will fail."""
1753
 
        error = subprocess.CalledProcessError(1, ['juju'], '')
1754
 
        effects = [None, None, None, None, None, None, error]
1755
 
        cc_mock = self.addContext(patch('subprocess.check_call', autospec=True,
1756
 
                                        side_effect=effects))
1757
 
        client = EnvJujuClient(JujuData(
1758
 
            'foo', {'type': 'paas', 'region': 'qux'}), '1.23', 'path')
1759
 
        with self.bc_context(client, 'log_dir', jes='kill-controller'):
1760
 
            with observable_temp_file() as config_file:
1761
 
                with self.assertRaises(subprocess.CalledProcessError) as ctx:
1762
 
                    with boot_context('bar', client, None, [], None, None,
1763
 
                                      None, 'log_dir', keep_env=False,
1764
 
                                      upload_tools=False):
1765
 
                        pass
1766
 
                self.assertIs(ctx.exception, error)
1767
 
        assert_juju_call(self, cc_mock, client, (
1768
 
            'path', '--show-log', 'bootstrap', '--constraints',
1769
 
            'mem=2G', 'bar', 'paas/qux', '--config', config_file.name,
1770
 
            '--default-model', 'bar', '--agent-version', '1.23'), 0)
1771
 
        assert_juju_call(self, cc_mock, client, (
1772
 
            'path', '--show-log', 'list-controllers'), 1)
1773
 
        assert_juju_call(self, cc_mock, client, (
1774
 
            'path', '--show-log', 'list-models', '-c', 'bar'), 2)
1775
 
        assert_juju_call(self, cc_mock, client, (
1776
 
            'path', '--show-log', 'show-status', '-m', 'bar:controller',
1777
 
            '--format', 'yaml'), 3)
1778
 
        assert_juju_call(self, cc_mock, client, (
1779
 
            'path', '--show-log', 'show-status', '-m', 'bar:bar',
1780
 
            '--format', 'yaml'), 4)
1781
 
 
1782
1579
 
1783
1580
class TestDeployJobParseArgs(FakeHomeTestCase):
1784
1581