646
def output(*args, **kwargs):
512
def output(args, **kwargs):
648
('show-status', '--format', 'yaml'): status,
649
('ssh', 'dummy-sink/0', GET_TOKEN_SCRIPT): 'fake-token',
514
('juju', '--show-log', 'status', '-e', 'foo'): status,
515
get_timeout_prefix(120) + (
516
'juju', '--show-log', 'ssh', '-e', 'foo', 'dummy-sink/0',
517
GET_TOKEN_SCRIPT): 'fake-token',
651
519
return output[args]
653
client.version = '2.0.0'
654
with patch.object(client, 'get_juju_output', side_effect=output,
655
autospec=True) as gjo_mock:
656
with patch('subprocess.check_call', autospec=True) as cc_mock:
657
with patch('deploy_stack.get_random_string',
658
return_value='fake-token', autospec=True):
659
with patch('sys.stdout', autospec=True):
660
with temp_os_env('JUJU_REPOSITORY', '/tmp/repo'):
661
deploy_dummy_stack(client, 'bar-')
662
assert_juju_call(self, cc_mock, client, (
663
'juju', '--show-log', 'deploy', '-m', 'foo',
664
'/tmp/repo/charms/dummy-source', '--series', 'bar-'), 0)
665
assert_juju_call(self, cc_mock, client, (
666
'juju', '--show-log', 'deploy', '-m', 'foo',
667
'/tmp/repo/charms/dummy-sink', '--series', 'bar-'), 1)
668
assert_juju_call(self, cc_mock, client, (
669
'juju', '--show-log', 'add-relation', '-m', 'foo',
670
'dummy-source', 'dummy-sink'), 2)
671
assert_juju_call(self, cc_mock, client, (
672
'juju', '--show-log', 'expose', '-m', 'foo', 'dummy-sink'), 3)
673
self.assertEqual(cc_mock.call_count, 4)
676
call('show-status', '--format', 'yaml', admin=False)
678
gjo_mock.call_args_list)
680
client.version = '1.25.0'
681
with patch.object(client, 'get_juju_output', side_effect=output,
682
autospec=True) as gjo_mock:
683
with patch('subprocess.check_call', autospec=True) as cc_mock:
684
with patch('deploy_stack.get_random_string',
685
return_value='fake-token', autospec=True):
686
with patch('sys.stdout', autospec=True):
687
with temp_os_env('JUJU_REPOSITORY', '/tmp/repo'):
688
deploy_dummy_stack(client, 'bar-')
689
assert_juju_call(self, cc_mock, client, (
690
'juju', '--show-log', 'deploy', '-m', 'foo',
691
'local:bar-/dummy-source', '--series', 'bar-'), 0)
692
assert_juju_call(self, cc_mock, client, (
693
'juju', '--show-log', 'deploy', '-m', 'foo',
694
'local:bar-/dummy-sink', '--series', 'bar-'), 1)
521
with patch('subprocess.check_output', side_effect=output,
522
autospec=True) as co_mock:
523
with patch('subprocess.check_call', autospec=True) as cc_mock:
524
with patch('deploy_stack.get_random_string',
525
return_value='fake-token', autospec=True):
526
with patch('sys.stdout', autospec=True):
527
deploy_dummy_stack(client, 'bar-')
528
assert_juju_call(self, cc_mock, client, (
529
'juju', '--show-log', 'deploy', '-e', 'foo', 'bar-dummy-source'),
531
assert_juju_call(self, cc_mock, client, (
532
'juju', '--show-log', 'set', '-e', 'foo', 'dummy-source',
533
'token=fake-token'), 1)
534
assert_juju_call(self, cc_mock, client, (
535
'juju', '--show-log', 'deploy', '-e', 'foo', 'bar-dummy-sink'), 2)
536
assert_juju_call(self, cc_mock, client, (
537
'juju', '--show-log', 'add-relation', '-e', 'foo',
538
'dummy-source', 'dummy-sink'), 3)
539
assert_juju_call(self, cc_mock, client, (
540
'juju', '--show-log', 'expose', '-e', 'foo', 'dummy-sink'), 4)
541
self.assertEqual(cc_mock.call_count, 5)
542
assert_juju_call(self, co_mock, client, (
543
'juju', '--show-log', 'status', '-e', 'foo'), 0,
545
assert_juju_call(self, co_mock, client, (
546
'juju', '--show-log', 'status', '-e', 'foo'), 1,
548
assert_juju_call(self, co_mock, client, get_timeout_prefix(120) + (
549
'juju', '--show-log', 'ssh', '-e', 'foo', 'dummy-sink/0',
550
GET_TOKEN_SCRIPT), 2, assign_stderr=True)
551
self.assertEqual(co_mock.call_count, 3)
697
554
def fake_SimpleEnvironment(name):
702
559
return EnvJujuClient(env=env, version='1.2.3.4', full_path=path)
705
class FakeBootstrapManager:
707
def __init__(self, client):
709
self.tear_down_client = client
710
self.entered_top = False
711
self.exited_top = False
712
self.entered_bootstrap = False
713
self.exited_bootstrap = False
714
self.entered_runtime = False
715
self.exited_runtime = False
716
self.torn_down = False
717
self.permanent = False
718
self.known_hosts = {'0': '0.example.org'}
721
def top_context(self):
723
self.entered_top = True
726
self.exited_top = True
729
def bootstrap_context(self, machines):
730
initial_home = self.client.env.juju_home
731
self.client.env.environment = self.client.env.environment + '-temp'
733
self.entered_bootstrap = True
734
self.client.env.juju_home = os.path.join(initial_home, 'isolated')
737
self.exited_bootstrap = True
738
if not self.permanent:
739
self.client.env.juju_home = initial_home
742
def runtime_context(self, machines):
744
self.entered_runtime = True
748
self.exited_runtime = True
751
self.tear_down_client.destroy_environment()
752
self.tear_down_client.torn_down = True
755
def booted_context(self, upload_tools):
756
with self.top_context() as machines:
757
with self.bootstrap_context(machines):
758
self.client.bootstrap(upload_tools)
759
with self.runtime_context(machines):
763
class TestDeployJob(FakeHomeTestCase):
767
env = JujuData('foo', {})
768
client = fake_EnvJujuClient(env)
769
bc_cxt = patch('jujupy.EnvJujuClient.by_version',
771
fc_cxt = patch('jujupy.SimpleEnvironment.from_config',
774
bm_cxt = patch('deploy_stack.BootstrapManager', autospec=True,
776
juju_cxt = patch('deploy_stack.EnvJujuClient.juju', autospec=True)
777
ajr_cxt = patch('deploy_stack.assess_juju_run', autospec=True)
778
dds_cxt = patch('deploy_stack.deploy_dummy_stack', autospec=True)
779
with bc_cxt, fc_cxt, bm_cxt as bm_mock, juju_cxt, ajr_cxt, dds_cxt:
780
yield client, bm_mock
562
class TestDeployJob(TestCase):
782
564
@skipIf(sys.platform in ('win32', 'darwin'),
783
565
'Not supported on Windown and OS X')
784
def test_background_chaos_used(self):
786
env='base', juju_bin='/fake/juju', logs='log', temp_env_name='foo',
787
charm_prefix=None, bootstrap_host=None, machine=None,
788
series='trusty', debug=False, agent_url=None, agent_stream=None,
789
keep_env=False, upload_tools=False, with_chaos=1, jes=False,
790
region=None, verbose=False, upgrade=False,
793
with patch('deploy_stack.background_chaos',
794
autospec=True) as bc_mock:
795
with patch('deploy_stack.assess_juju_relations',
797
with patch('subprocess.Popen', autospec=True,
798
return_value=FakePopen('', '', 0)):
799
_deploy_job(args, 'local:trusty/', 'trusty')
800
self.assertEqual(bc_mock.call_count, 1)
566
@patch('jujupy.EnvJujuClient.by_version', side_effect=fake_EnvJujuClient)
567
@patch('jujupy.SimpleEnvironment.from_config',
568
side_effect=fake_SimpleEnvironment)
569
@patch('deploy_stack.boot_context', autospec=True)
570
@patch('deploy_stack.EnvJujuClient.juju', autospec=True)
571
def test_background_chaos_used(self, *args):
572
with patch('deploy_stack.background_chaos', autospec=True) as bc_mock:
573
with patch('deploy_stack.deploy_dummy_stack', autospec=True):
574
with patch('deploy_stack.assess_juju_run', autospec=True):
575
_deploy_job('foo', None, None, '', None, None, None, 'log',
576
None, None, None, None, None, None, 1, False,
801
578
self.assertEqual(bc_mock.mock_calls[0][1][0], 'foo')
802
579
self.assertEqual(bc_mock.mock_calls[0][1][2], 'log')
803
580
self.assertEqual(bc_mock.mock_calls[0][1][3], 1)
805
582
@skipIf(sys.platform in ('win32', 'darwin'),
806
583
'Not supported on Windown and OS X')
807
def test_background_chaos_not_used(self):
809
env='base', juju_bin='/fake/juju', logs='log', temp_env_name='foo',
810
charm_prefix=None, bootstrap_host=None, machine=None,
811
series='trusty', debug=False, agent_url=None, agent_stream=None,
812
keep_env=False, upload_tools=False, with_chaos=0, jes=False,
813
region=None, verbose=False, upgrade=False,
816
with patch('deploy_stack.background_chaos',
817
autospec=True) as bc_mock:
818
with patch('deploy_stack.assess_juju_relations',
820
with patch('subprocess.Popen', autospec=True,
821
return_value=FakePopen('', '', 0)):
822
_deploy_job(args, 'local:trusty/', 'trusty')
584
@patch('jujupy.EnvJujuClient.by_version', side_effect=fake_EnvJujuClient)
585
@patch('jujupy.SimpleEnvironment.from_config',
586
side_effect=fake_SimpleEnvironment)
587
@patch('deploy_stack.boot_context', autospec=True)
588
@patch('deploy_stack.EnvJujuClient.juju', autospec=True)
589
def test_background_chaos_not_used(self, *args):
590
with patch('deploy_stack.background_chaos', autospec=True) as bc_mock:
591
with patch('deploy_stack.deploy_dummy_stack', autospec=True):
592
with patch('deploy_stack.assess_juju_run', autospec=True):
593
_deploy_job('foo', None, None, '', None, None, None, None,
594
None, None, None, None, None, None, 0, False,
823
596
self.assertEqual(bc_mock.call_count, 0)
825
def test_region(self):
827
env='base', juju_bin='/fake/juju', logs='log', temp_env_name='foo',
828
charm_prefix=None, bootstrap_host=None, machine=None,
829
series='trusty', debug=False, agent_url=None, agent_stream=None,
830
keep_env=False, upload_tools=False, with_chaos=0, jes=False,
831
region='region-foo', verbose=False, upgrade=False,
833
with self.ds_cxt() as (client, bm_mock):
834
with patch('deploy_stack.assess_juju_relations',
836
with patch('subprocess.Popen', autospec=True,
837
return_value=FakePopen('', '', 0)):
838
_deploy_job(args, 'local:trusty/', 'trusty')
839
jes = client.is_jes_enabled()
840
bm_mock.assert_called_once_with(
841
'foo', client, client, None, None, 'trusty', None, None,
842
'region-foo', 'log', False, permanent=jes, jes_enabled=jes)
844
def test_deploy_job_changes_series_with_win(self):
846
series='windows', temp_env_name=None, env=None, upgrade=None,
847
charm_prefix=None, bootstrap_host=None, machine=None, logs=None,
848
debug=None, juju_bin=None, agent_url=None, agent_stream=None,
849
keep_env=None, upload_tools=None, with_chaos=None, jes=None,
850
region=None, verbose=None)
851
with patch('deploy_stack.deploy_job_parse_args', return_value=args,
853
with patch('deploy_stack._deploy_job', autospec=True) as ds_mock:
855
ds_mock.assert_called_once_with(args, 'windows', 'trusty')
857
def test_deploy_job_changes_series_with_centos(self):
859
series='centos', temp_env_name=None, env=None, upgrade=None,
860
charm_prefix=None, bootstrap_host=None, machine=None, logs=None,
861
debug=None, juju_bin=None, agent_url=None, agent_stream=None,
862
keep_env=None, upload_tools=None, with_chaos=None, jes=None,
863
region=None, verbose=None)
864
with patch('deploy_stack.deploy_job_parse_args', return_value=args,
866
with patch('deploy_stack._deploy_job', autospec=True) as ds_mock:
868
ds_mock.assert_called_once_with(args, 'centos', 'trusty')
871
class TestTestUpgrade(FakeHomeTestCase):
599
class TestTestUpgrade(TestCase):
874
602
'juju', '--show-log', 'run', '-e', 'foo', '--format', 'json',
875
603
'--service', 'dummy-source,dummy-sink', 'uname')
877
'juju', '--show-log', 'show-status', '-m', 'foo', '--format', 'yaml')
878
GET_ENV = ('juju', '--show-log', 'get-model-config', '-m', 'foo',
604
VERSION = ('/bar/juju', '--version')
605
STATUS = ('juju', '--show-log', 'status', '-e', 'foo')
606
GET_ENV = ('juju', '--show-log', 'get-env', '-e', 'foo',
879
607
'tools-metadata-url')
610
setup_test_logging(self)
882
613
def upgrade_output(cls, args, **kwargs):
883
614
status = yaml.safe_dump({
884
615
'machines': {'0': {
885
616
'agent-state': 'started',
886
'agent-version': '2.0-alpha3'}},
617
'agent-version': '1.38'}},
888
619
juju_run_out = json.dumps([
889
620
{"MachineId": "1", "Stdout": "Linux\n"},
892
623
cls.STATUS: status,
893
624
cls.RUN_UNAME: juju_run_out,
894
626
cls.GET_ENV: 'testing'
896
return FakePopen(output[args], '', 0)
899
631
def upgrade_mocks(self):
900
with patch('subprocess.Popen', side_effect=self.upgrade_output,
632
with patch('subprocess.check_output', side_effect=self.upgrade_output,
901
633
autospec=True) as co_mock:
902
634
with patch('subprocess.check_call', autospec=True) as cc_mock:
903
635
with patch('deploy_stack.check_token', autospec=True):
904
636
with patch('deploy_stack.get_random_string',
905
637
return_value="FAKETOKEN", autospec=True):
906
with patch('jujupy.EnvJujuClient.get_version',
907
side_effect=lambda cls:
908
'2.0-alpha3-arch-series'):
638
with patch('sys.stdout', autospec=True):
909
639
yield (co_mock, cc_mock)
911
641
def test_assess_upgrade(self):
912
env = JujuData('foo', {'type': 'foo'})
642
env = SimpleEnvironment('foo', {'type': 'foo'})
913
643
old_client = EnvJujuClient(env, None, '/foo/juju')
914
644
with self.upgrade_mocks() as (co_mock, cc_mock):
915
645
assess_upgrade(old_client, '/bar/juju')
916
646
new_client = EnvJujuClient(env, None, '/bar/juju')
917
647
assert_juju_call(self, cc_mock, new_client, (
918
'juju', '--show-log', 'upgrade-juju', '-m', 'foo', '--version',
920
self.assertEqual(cc_mock.call_count, 1)
921
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 0)
922
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 1)
923
assert_juju_call(self, co_mock, new_client, self.STATUS, 2)
924
self.assertEqual(co_mock.call_count, 3)
648
'juju', '--show-log', 'upgrade-juju', '-e', 'foo', '--version',
650
assert_juju_call(self, cc_mock, new_client, (
651
'juju', '--show-log', 'set', '-e', 'foo', 'dummy-source',
652
'token=FAKETOKEN'), 1)
653
self.assertEqual(cc_mock.call_count, 2)
654
self.assertEqual(co_mock.mock_calls[0], call(self.VERSION))
655
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 1,
657
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 2,
659
assert_juju_call(self, co_mock, new_client, self.STATUS, 3,
661
assert_juju_call(self, co_mock, new_client, self.RUN_UNAME, 4,
663
self.assertEqual(co_mock.call_count, 5)
926
665
def test_mass_timeout(self):
927
666
config = {'type': 'foo'}
928
old_client = EnvJujuClient(JujuData('foo', config), None, '/foo/juju')
667
old_client = EnvJujuClient(SimpleEnvironment('foo', config),
929
669
with self.upgrade_mocks():
930
670
with patch.object(EnvJujuClient, 'wait_for_version') as wfv_mock:
931
671
assess_upgrade(old_client, '/bar/juju')
932
wfv_mock.assert_called_once_with('2.0-alpha3', 600)
672
wfv_mock.assert_called_once_with('1.38', 600)
933
673
config['type'] = 'maas'
934
674
with patch.object(EnvJujuClient, 'wait_for_version') as wfv_mock:
935
675
assess_upgrade(old_client, '/bar/juju')
936
wfv_mock.assert_called_once_with('2.0-alpha3', 1200)
939
class TestBootstrapManager(FakeHomeTestCase):
941
def test_from_args(self):
943
env='foo', juju_bin='bar', debug=True, temp_env_name='baz',
944
bootstrap_host='example.org', machine=['example.com'],
945
series='angsty', agent_url='qux', agent_stream='escaped',
946
region='eu-west-northwest-5', logs='pine', keep_env=True)
947
with patch.object(SimpleEnvironment, 'from_config') as fc_mock:
948
with patch.object(EnvJujuClient, 'by_version') as bv_mock:
949
bs_manager = BootstrapManager.from_args(args)
950
fc_mock.assert_called_once_with('foo')
951
bv_mock.assert_called_once_with(fc_mock.return_value, 'bar',
953
self.assertEqual('baz', bs_manager.temp_env_name)
954
self.assertIs(bv_mock.return_value, bs_manager.client)
955
self.assertIs(bv_mock.return_value, bs_manager.tear_down_client)
956
self.assertEqual('example.org', bs_manager.bootstrap_host)
957
self.assertEqual(['example.com'], bs_manager.machines)
958
self.assertEqual('angsty', bs_manager.series)
959
self.assertEqual('qux', bs_manager.agent_url)
960
self.assertEqual('escaped', bs_manager.agent_stream)
961
self.assertEqual('eu-west-northwest-5', bs_manager.region)
962
self.assertIs(True, bs_manager.keep_env)
963
self.assertEqual('pine', bs_manager.log_dir)
964
jes_enabled = bs_manager.client.is_jes_enabled.return_value
965
self.assertEqual(jes_enabled, bs_manager.permanent)
966
self.assertEqual(jes_enabled, bs_manager.jes_enabled)
967
self.assertEqual({'0': 'example.org'}, bs_manager.known_hosts)
969
def test_jes_not_permanent(self):
970
with self.assertRaisesRegexp(ValueError, 'Cannot set permanent False'
971
' if jes_enabled is True.'):
973
jes_enabled=True, permanent=False,
974
temp_env_name=None, client=None, tear_down_client=None,
975
bootstrap_host=None, machines=[], series=None, agent_url=None,
976
agent_stream=None, region=None, log_dir=None, keep_env=None)
978
def test_aws_machines_updates_bootstrap_host(self):
979
client = FakeJujuClient()
980
client.env.config['type'] = 'manual'
981
bs_manager = BootstrapManager(
982
'foobar', client, client, None, [], None, None, None, None,
983
client.env.juju_home, False, False, False)
984
with patch('deploy_stack.run_instances',
985
return_value=[('foo', 'aws.example.org')]):
986
with patch('deploy_stack.destroy_job_instances'):
987
with bs_manager.aws_machines():
988
self.assertEqual({'0': 'aws.example.org'},
989
bs_manager.known_hosts)
991
def test_from_args_no_host(self):
993
env='foo', juju_bin='bar', debug=True, temp_env_name='baz',
994
bootstrap_host=None, machine=['example.com'],
995
series='angsty', agent_url='qux', agent_stream='escaped',
996
region='eu-west-northwest-5', logs='pine', keep_env=True)
997
with patch.object(SimpleEnvironment, 'from_config'):
998
with patch.object(EnvJujuClient, 'by_version'):
999
bs_manager = BootstrapManager.from_args(args)
1000
self.assertIs(None, bs_manager.bootstrap_host)
1001
self.assertEqual({}, bs_manager.known_hosts)
1003
def make_client(self):
1004
client = MagicMock()
1005
client.env = SimpleEnvironment(
1006
'foo', {'type': 'baz'}, use_context(self, temp_dir()))
1007
client.is_jes_enabled.return_value = False
1008
client.get_matching_agent_version.return_value = '3.14'
1009
client.get_cache_path.return_value = get_cache_path(
1010
client.env.juju_home)
1013
def test_bootstrap_context_tear_down(self):
1014
client = FakeJujuClient()
1015
client.env.juju_home = use_context(self, temp_dir())
1016
initial_home = client.env.juju_home
1017
bs_manager = BootstrapManager(
1018
'foobar', client, client, None, [], None, None, None, None,
1019
client.env.juju_home, False, False, False)
1021
def check_config(client_, jes_enabled, try_jes=False):
1022
self.assertEqual(0, client.is_jes_enabled.call_count)
1023
jenv_path = get_jenv_path(client.env.juju_home, 'foobar')
1024
self.assertFalse(os.path.exists(jenv_path))
1025
environments_path = get_environments_path(client.env.juju_home)
1026
self.assertTrue(os.path.isfile(environments_path))
1027
self.assertNotEqual(initial_home, client.env.juju_home)
1029
ije_cxt = patch.object(client, 'is_jes_enabled')
1030
with patch('deploy_stack.tear_down',
1031
side_effect=check_config) as td_mock, ije_cxt:
1032
with bs_manager.bootstrap_context([]):
1033
td_mock.assert_called_once_with(client, False, try_jes=True)
1035
def test_bootstrap_context_tear_down_jenv(self):
1036
client = self.make_client()
1037
initial_home = client.env.juju_home
1038
jenv_path = get_jenv_path(client.env.juju_home, 'foobar')
1039
os.makedirs(os.path.dirname(jenv_path))
1040
with open(jenv_path, 'w'):
1043
bs_manager = BootstrapManager(
1044
'foobar', client, client, None, [], None, None, None, None,
1045
client.env.juju_home, False, False, False)
1047
def check_config(client_, jes_enabled, try_jes=False):
1048
self.assertEqual(0, client.is_jes_enabled.call_count)
1049
self.assertTrue(os.path.isfile(jenv_path))
1050
environments_path = get_environments_path(client.env.juju_home)
1051
self.assertFalse(os.path.exists(environments_path))
1052
self.assertEqual(initial_home, client.env.juju_home)
1054
with patch('deploy_stack.tear_down',
1055
side_effect=check_config) as td_mock:
1056
with bs_manager.bootstrap_context([]):
1057
td_mock.assert_called_once_with(client, False, try_jes=False)
1059
def test_bootstrap_context_tear_down_client(self):
1060
client = self.make_client()
1061
tear_down_client = self.make_client()
1062
tear_down_client.env = client.env
1063
bs_manager = BootstrapManager(
1064
'foobar', client, tear_down_client, None, [], None, None, None,
1065
None, client.env.juju_home, False, False, False)
1067
def check_config(client_, jes_enabled, try_jes=False):
1068
self.assertEqual(0, client.is_jes_enabled.call_count)
1069
tear_down_client.is_jes_enabled.assert_called_once_with()
1071
with patch('deploy_stack.tear_down',
1072
side_effect=check_config) as td_mock:
1073
with bs_manager.bootstrap_context([]):
1074
td_mock.assert_called_once_with(tear_down_client,
1075
False, try_jes=True)
1077
def test_bootstrap_context_tear_down_client_jenv(self):
1078
client = self.make_client()
1079
tear_down_client = self.make_client()
1080
tear_down_client.env = client.env
1081
jenv_path = get_jenv_path(client.env.juju_home, 'foobar')
1082
os.makedirs(os.path.dirname(jenv_path))
1083
with open(jenv_path, 'w'):
1086
bs_manager = BootstrapManager(
1087
'foobar', client, tear_down_client,
1088
None, [], None, None, None, None, client.env.juju_home, False,
1091
def check_config(client_, jes_enabled, try_jes=False):
1092
self.assertEqual(0, client.is_jes_enabled.call_count)
1093
tear_down_client.is_jes_enabled.assert_called_once_with()
1095
with patch('deploy_stack.tear_down',
1096
side_effect=check_config) as td_mock:
1097
with bs_manager.bootstrap_context([]):
1098
td_mock.assert_called_once_with(tear_down_client, False,
1101
def test_bootstrap_context_no_set_home(self):
1102
orig_home = get_juju_home()
1103
client = self.make_client()
1104
jenv_path = get_jenv_path(client.env.juju_home, 'foobar')
1105
os.makedirs(os.path.dirname(jenv_path))
1106
with open(jenv_path, 'w'):
1109
bs_manager = BootstrapManager(
1110
'foobar', client, client, None, [], None, None, None, None,
1111
client.env.juju_home, False, False, False)
1112
with bs_manager.bootstrap_context([]):
1113
self.assertEqual(orig_home, get_juju_home())
1115
def test_bootstrap_context_calls_update_env(self):
1116
client = FakeJujuClient()
1117
client.env.juju_home = use_context(self, temp_dir())
1118
ue_mock = use_context(
1119
self, patch('deploy_stack.update_env', wraps=update_env))
1120
wfp_mock = use_context(
1121
self, patch('deploy_stack.wait_for_port', autospec=True))
1122
bs_manager = BootstrapManager(
1123
'bar', client, client, None,
1124
[], 'wacky', 'url', 'devel', None, client.env.juju_home, False,
1126
bs_manager.known_hosts['0'] = 'bootstrap.example.org'
1127
with bs_manager.bootstrap_context([]):
1129
ue_mock.assert_called_with(
1130
client.env, 'bar', series='wacky',
1131
bootstrap_host='bootstrap.example.org',
1132
agent_url='url', agent_stream='devel', region=None)
1133
wfp_mock.assert_called_once_with(
1134
'bootstrap.example.org', 22, timeout=120)
1136
def test_bootstrap_context_calls_update_env_omit(self):
1137
client = FakeJujuClient()
1138
client.env.juju_home = use_context(self, temp_dir())
1139
ue_mock = use_context(
1140
self, patch('deploy_stack.update_env', wraps=update_env))
1141
wfp_mock = use_context(
1142
self, patch('deploy_stack.wait_for_port', autospec=True))
1143
bs_manager = BootstrapManager(
1144
'bar', client, client, None,
1145
[], 'wacky', 'url', 'devel', None, client.env.juju_home, True,
1147
bs_manager.known_hosts['0'] = 'bootstrap.example.org'
1148
with bs_manager.bootstrap_context(
1149
[], omit_config={'bootstrap_host', 'series'}):
1151
ue_mock.assert_called_with(client.env, 'bar', agent_url='url',
1152
agent_stream='devel', region=None)
1153
wfp_mock.assert_called_once_with(
1154
'bootstrap.example.org', 22, timeout=120)
1156
def test_tear_down_requires_same_env(self):
1157
client = self.make_client()
1158
client.env.juju_home = 'foobar'
1159
tear_down_client = self.make_client()
1160
tear_down_client.env.juju_home = 'barfoo'
1161
bs_manager = BootstrapManager(
1162
'foobar', client, tear_down_client,
1163
None, [], None, None, None, None, client.env.juju_home, False,
1166
def check_home(foo, bar, try_jes):
1167
self.assertEqual(client.env.juju_home,
1168
tear_down_client.env.juju_home)
1170
with self.assertRaisesRegexp(AssertionError,
1171
'Tear down client needs same env'):
1172
with patch('deploy_stack.tear_down', autospec=True,
1173
side_effect=check_home):
1174
bs_manager.tear_down()
1175
self.assertEqual('barfoo', tear_down_client.env.juju_home)
1177
def test_dump_all_no_jes_one_model(self):
1178
client = FakeJujuClient()
1180
with temp_dir() as log_dir:
1181
bs_manager = BootstrapManager(
1182
'foobar', client, client,
1183
None, [], None, None, None, None, log_dir, False,
1184
False, jes_enabled=False)
1185
with patch('deploy_stack.dump_env_logs_known_hosts'):
1186
with patch.object(client, 'iter_model_clients') as imc_mock:
1187
bs_manager.dump_all_logs()
1188
self.assertEqual(0, imc_mock.call_count)
1190
def test_dump_all_multi_model(self):
1191
client = FakeJujuClient(jes_enabled=True)
1193
with temp_dir() as log_dir:
1194
bs_manager = BootstrapManager(
1195
'foobar', client, client,
1196
None, [], None, None, None, None, log_dir, False,
1197
permanent=True, jes_enabled=True)
1198
with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1199
bs_manager.dump_all_logs()
1201
clients = dict((c[1][0].env.environment, c[1][0])
1202
for c in del_mock.mock_calls)
1204
self.assertItemsEqual(
1205
[call(client, os.path.join(log_dir, 'name'), None, {}),
1206
call(clients['admin'], os.path.join(log_dir, 'admin'),
1207
'foo/models/cache.yaml', {})],
1208
del_mock.mock_calls)
1210
def test_dump_all_multi_model_iter_failure(self):
1211
client = FakeJujuClient(jes_enabled=True)
1213
with temp_dir() as log_dir:
1214
bs_manager = BootstrapManager(
1215
'foobar', client, client,
1216
None, [], None, None, None, None, log_dir, False,
1217
permanent=True, jes_enabled=True)
1218
with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1219
with patch.object(client, 'iter_model_clients',
1220
side_effect=Exception):
1221
bs_manager.dump_all_logs()
1223
clients = dict((c[1][0].env.environment, c[1][0])
1224
for c in del_mock.mock_calls)
1226
self.assertItemsEqual(
1227
[call(client, os.path.join(log_dir, 'name'), None, {}),
1228
call(clients['admin'], os.path.join(log_dir, 'admin'),
1229
'foo/models/cache.yaml', {})],
1230
del_mock.mock_calls)
1232
def test_dump_all_logs_uses_known_hosts(self):
1233
client = FakeJujuClient()
1234
with temp_dir() as log_dir:
1235
bs_manager = BootstrapManager(
1236
'foobar', client, client,
1237
None, [], None, None, None, None, log_dir, False,
1239
bs_manager.known_hosts['2'] = 'example.org'
1241
with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1242
bs_manager.dump_all_logs()
1243
del_mock.assert_called_once_with(
1244
client, os.path.join(log_dir, 'name'),
1245
'foo/environments/name.jenv', {
1249
def test_runtime_context_looks_up_host(self):
1250
client = FakeJujuClient()
1252
bs_manager = BootstrapManager(
1253
'foobar', client, client,
1254
None, [], None, None, None, None, client.env.juju_home, False,
1256
with patch.object(bs_manager, 'dump_all_logs', autospec=True):
1257
with bs_manager.runtime_context([]):
1259
'0': '0.example.com'}, bs_manager.known_hosts)
1261
@patch('deploy_stack.dump_env_logs_known_hosts', autospec=True)
1262
def test_runtime_context_addable_machines_no_known_hosts(self, del_mock):
1263
client = FakeJujuClient()
1265
bs_manager = BootstrapManager(
1266
'foobar', client, client,
1267
None, [], None, None, None, None, client.env.juju_home, False,
1269
bs_manager.known_hosts = {}
1270
with patch.object(bs_manager.client, 'add_ssh_machines',
1271
autospec=True) as ads_mock:
1272
with patch.object(bs_manager, 'dump_all_logs', autospec=True):
1273
with bs_manager.runtime_context(['baz']):
1274
ads_mock.assert_called_once_with(['baz'])
1276
@patch('deploy_stack.BootstrapManager.dump_all_logs', autospec=True)
1277
def test_runtime_context_addable_machines_with_known_hosts(self, dal_mock):
1278
client = FakeJujuClient()
1279
with temp_dir() as log_dir:
1280
bs_manager = BootstrapManager(
1281
'foobar', client, client,
1282
None, [], None, None, None, None, log_dir, False,
1284
bs_manager.known_hosts['0'] = 'example.org'
1285
with patch.object(bs_manager.client, 'add_ssh_machines',
1286
autospec=True) as ads_mock:
1287
with bs_manager.runtime_context(['baz']):
1288
ads_mock.assert_called_once_with(['baz'])
1290
def test_booted_context_handles_logged_exception(self):
1291
client = FakeJujuClient()
1292
bs_manager = BootstrapManager(
1293
'foobar', client, client,
1294
None, [], None, None, None, None, client.env.juju_home, False,
1296
with temp_dir() as juju_home:
1297
client.env.juju_home = juju_home
1298
with self.assertRaises(SystemExit):
1299
with bs_manager.booted_context(False):
1300
raise LoggedException()
1302
def test_booted_context_omits_supported(self):
1303
client = FakeJujuClient(jes_enabled=True)
1304
client.env.juju_home = use_context(self, temp_dir())
1305
client.bootstrap_replaces = {'agent-version', 'series',
1306
'bootstrap-host', 'agent-stream'}
1307
ue_mock = use_context(
1308
self, patch('deploy_stack.update_env', wraps=update_env))
1309
wfp_mock = use_context(
1310
self, patch('deploy_stack.wait_for_port', autospec=True))
1311
bs_manager = BootstrapManager(
1312
'bar', client, client, 'bootstrap.example.org',
1313
[], 'wacky', 'url', 'devel', None, client.env.juju_home, False,
1315
with patch.object(bs_manager, 'runtime_context'):
1316
with bs_manager.booted_context([]):
1320
'default-series': 'wacky',
1321
'tools-metadata-url': 'url',
1323
}, client.get_model_config())
1324
ue_mock.assert_called_with(client.env, 'bar', agent_url='url',
1326
wfp_mock.assert_called_once_with(
1327
'bootstrap.example.org', 22, timeout=120)
1330
class TestBootContext(FakeHomeTestCase):
676
wfv_mock.assert_called_once_with('1.38', 1200)
679
class TestBootContext(TestCase):
1332
681
def setUp(self):
1333
super(TestBootContext, self).setUp()
682
self.addContext(patch('subprocess.Popen', side_effect=Exception))
1334
683
self.addContext(patch('sys.stdout'))
1336
685
def addContext(self, cxt):
1470
767
'juju', '--show-log', 'bootstrap', '-e', 'bar', '--upload-tools',
1471
768
'--constraints', 'mem=2G'), 0)
1473
def test_calls_update_env_2(self):
1474
cc_mock = self.addContext(patch('subprocess.check_call'))
1475
client = EnvJujuClient(JujuData(
1476
'foo', {'type': 'paas', 'region': 'qux'}), '1.23', 'path')
1477
ue_mock = self.addContext(
1478
patch('deploy_stack.update_env', wraps=update_env))
1479
with self.bc_context(client, jes='kill-controller'):
1480
with observable_temp_file() as config_file:
1481
with boot_context('bar', client, None, [], 'wacky', 'url',
1482
'devel', None, keep_env=False,
1483
upload_tools=False):
1485
ue_mock.assert_called_with(
1486
client.env, 'bar', agent_url='url', agent_stream='devel',
1487
series='wacky', bootstrap_host=None, region=None)
1488
assert_juju_call(self, cc_mock, client, (
1489
'juju', '--show-log', 'bootstrap', '--constraints', 'mem=2G',
1490
'bar', 'paas/qux', '--config', config_file.name,
1491
'--default-model', 'bar', '--agent-version', '1.23',
1492
'--bootstrap-series', 'wacky'), 0)
1494
def test_calls_update_env_1(self):
1495
cc_mock = self.addContext(patch('subprocess.check_call'))
1496
client = EnvJujuClient1X(SimpleEnvironment(
1497
'foo', {'type': 'paas'}), '1.23', 'path')
1498
ue_mock = self.addContext(
1499
patch('deploy_stack.update_env', wraps=update_env))
1500
with self.bc_context(client):
1501
with boot_context('bar', client, None, [], 'wacky', 'url', 'devel',
1502
None, keep_env=False, upload_tools=False):
1504
ue_mock.assert_called_with(
1505
client.env, 'bar', series='wacky', bootstrap_host=None,
1506
agent_url='url', agent_stream='devel', region=None)
1507
assert_juju_call(self, cc_mock, client, (
1508
'juju', '--show-log', 'bootstrap', '-e', 'bar',
1509
'--constraints', 'mem=2G'), 0)
1511
def test_calls_update_env_non_jes(self):
1512
cc_mock = self.addContext(patch('subprocess.check_call'))
1513
client = EnvJujuClient1X(SimpleEnvironment(
1514
'foo', {'type': 'paas'}), '1.23', 'path')
1515
ue_mock = self.addContext(
1516
patch('deploy_stack.update_env', wraps=update_env))
1517
with self.bc_context(client):
1518
with boot_context('bar', client, None, [], 'wacky', 'url', 'devel',
1519
None, keep_env=False, upload_tools=False):
1521
ue_mock.assert_called_with(
1522
client.env, 'bar', series='wacky', bootstrap_host=None,
1523
agent_url='url', agent_stream='devel', region=None)
770
def test_calls_update_env(self):
771
cc_mock = self.addContext(patch('subprocess.check_call'))
772
client = EnvJujuClient(SimpleEnvironment(
773
'foo', {'type': 'paas'}), '1.23', 'path')
774
ue_mock = self.addContext(
775
patch('deploy_stack.update_env', wraps=update_env))
776
with self.bc_context(client):
777
with boot_context('bar', client, None, [], 'wacky', 'url', 'devel',
778
None, keep_env=False, upload_tools=False):
780
ue_mock.assert_called_with(
781
client.env, 'bar', series='wacky', bootstrap_host=None,
782
agent_url='url', agent_stream='devel')
1524
783
assert_juju_call(self, cc_mock, client, (
1525
784
'juju', '--show-log', 'bootstrap', '-e', 'bar',
1526
785
'--constraints', 'mem=2G'), 0)
1530
789
class FakeException(Exception):
1531
790
"""A sentry exception to be raised by bootstrap."""
1533
client = EnvJujuClient(JujuData(
1534
'foo', {'type': 'paas'}), '1.23', 'path')
1535
self.addContext(patch('deploy_stack.get_machine_dns_name',
1536
return_value='foo'))
1537
self.addContext(patch('subprocess.check_call'))
1538
call_mock = self.addContext(patch('subprocess.call', return_value=0))
1539
po_mock = self.addContext(patch(
1540
'subprocess.Popen', autospec=True,
1541
return_value=FakePopen('kill-controller', '', 0)))
1542
self.addContext(patch('deploy_stack.wait_for_port'))
1543
fake_exception = FakeException()
1544
self.addContext(patch.object(client, 'bootstrap',
1545
side_effect=fake_exception))
1546
crl_mock = self.addContext(patch('deploy_stack.copy_remote_logs'))
1547
al_mock = self.addContext(patch('deploy_stack.archive_logs'))
1548
le_mock = self.addContext(patch('logging.exception'))
1549
with self.assertRaises(SystemExit):
1550
with boot_context('bar', client, 'baz', [], None, None, None,
1551
'log_dir', keep_env=False, upload_tools=True):
1553
le_mock.assert_called_once_with(fake_exception)
1554
self.assertEqual(crl_mock.call_count, 1)
1555
call_args = crl_mock.call_args[0]
1556
self.assertIsInstance(call_args[0], _Remote)
1557
self.assertEqual(call_args[0].get_address(), 'baz')
1558
self.assertEqual(call_args[1], 'log_dir')
1559
al_mock.assert_called_once_with('log_dir')
1560
timeout_path = get_timeout_path()
1561
assert_juju_call(self, call_mock, client, (
1562
sys.executable, timeout_path, '600.00', '--',
1563
'juju', '--show-log', 'kill-controller', 'bar', '-y'
1565
assert_juju_call(self, call_mock, client, (
1566
sys.executable, timeout_path, '600.00', '--',
1567
'juju', '--show-log', 'kill-controller', 'bar', '-y'
1569
self.assertEqual(2, call_mock.call_count)
1570
self.assertEqual(0, po_mock.call_count)
1572
def test_with_bootstrap_failure_non_jes(self):
1574
class FakeException(Exception):
1575
"""A sentry exception to be raised by bootstrap."""
1577
client = EnvJujuClient1X(SimpleEnvironment(
1578
'foo', {'type': 'paas'}), '1.23', 'path')
1579
self.addContext(patch('deploy_stack.get_machine_dns_name',
1580
return_value='foo'))
1581
self.addContext(patch('subprocess.check_call'))
1582
call_mock = self.addContext(patch('subprocess.call', return_value=0))
1583
po_mock = self.addContext(patch('subprocess.Popen', autospec=True,
1584
return_value=FakePopen('', '', 0)))
1585
self.addContext(patch('deploy_stack.wait_for_port'))
1586
fake_exception = FakeException()
1587
self.addContext(patch.object(client, 'bootstrap',
1588
side_effect=fake_exception))
1589
crl_mock = self.addContext(patch('deploy_stack.copy_remote_logs'))
1590
al_mock = self.addContext(patch('deploy_stack.archive_logs'))
1591
le_mock = self.addContext(patch('logging.exception'))
1592
with self.assertRaises(SystemExit):
1593
with boot_context('bar', client, 'baz', [], None, None, None,
1594
'log_dir', keep_env=False, upload_tools=True):
1596
le_mock.assert_called_once_with(fake_exception)
1597
self.assertEqual(crl_mock.call_count, 1)
1598
call_args = crl_mock.call_args[0]
1599
self.assertIsInstance(call_args[0], _Remote)
1600
self.assertEqual(call_args[0].get_address(), 'baz')
1601
self.assertEqual(call_args[1], 'log_dir')
1602
al_mock.assert_called_once_with('log_dir')
1603
timeout_path = get_timeout_path()
1604
assert_juju_call(self, call_mock, client, (
1605
sys.executable, timeout_path, '600.00', '--',
1606
'juju', '--show-log', 'destroy-environment', 'bar', '-y'
1608
assert_juju_call(self, call_mock, client, (
1609
sys.executable, timeout_path, '600.00', '--',
1610
'juju', '--show-log', 'destroy-environment', 'bar', '-y'
1612
self.assertEqual(2, call_mock.call_count)
1613
assert_juju_call(self, po_mock, client, (
1614
'juju', '--show-log', 'help', 'commands'), 0)
1615
assert_juju_call(self, po_mock, client, (
1616
'juju', '--show-log', 'help', 'commands'), 1)
1617
self.assertEqual(2, po_mock.call_count)
792
client = EnvJujuClient(SimpleEnvironment(
793
'foo', {'type': 'paas'}), '1.23', 'path')
794
self.addContext(patch('deploy_stack.get_machine_dns_name',
796
self.addContext(patch('subprocess.check_call'))
797
call_mock = self.addContext(patch('subprocess.call'))
798
co_mock = self.addContext(patch('subprocess.check_output',
800
self.addContext(patch('deploy_stack.wait_for_port'))
801
self.addContext(patch.object(client, 'bootstrap',
802
side_effect=FakeException))
803
crl_mock = self.addContext(patch('deploy_stack.copy_remote_logs'))
804
al_mock = self.addContext(patch('deploy_stack.archive_logs'))
805
with self.assertRaises(FakeException):
806
with boot_context('bar', client, 'baz', [], None, None, None,
807
'log_dir', keep_env=False, upload_tools=True):
809
self.assertEqual(crl_mock.call_count, 1)
810
call_args = crl_mock.call_args[0]
811
self.assertIsInstance(call_args[0], _Remote)
812
self.assertEqual(call_args[0].get_address(), 'baz')
813
self.assertEqual(call_args[1], 'log_dir')
814
al_mock.assert_called_once_with('log_dir')
815
timeout_path = get_timeout_path()
816
assert_juju_call(self, call_mock, client, (
817
sys.executable, timeout_path, '600.00', '--',
818
'juju', '--show-log', 'destroy-environment', 'bar', '--force',
821
assert_juju_call(self, co_mock, client, (
822
'juju', '--show-log', 'help', 'commands'), assign_stderr=True)
1619
824
def test_jes(self):
1620
825
self.addContext(patch('subprocess.check_call', autospec=True))
1621
client = EnvJujuClient(JujuData(
1622
'foo', {'type': 'paas', 'region': 'qux'}), '1.26', 'path')
1623
with self.bc_context(client, 'log_dir', jes=KILL_CONTROLLER):
826
client = EnvJujuClient(SimpleEnvironment(
827
'foo', {'type': 'paas'}), '1.23', 'path')
828
with self.bc_context(client, 'log_dir', jes=True):
1624
829
with boot_context('bar', client, None, [], None, None, None,
1625
830
'log_dir', keep_env=False, upload_tools=False):
1628
def test_region(self):
1629
self.addContext(patch('subprocess.check_call', autospec=True))
1630
client = EnvJujuClient(JujuData(
1631
'foo', {'type': 'paas'}), '1.23', 'path')
1632
with self.bc_context(client, 'log_dir', jes='kill-controller'):
1633
with boot_context('bar', client, None, [], None, None, None,
1634
'log_dir', keep_env=False, upload_tools=False,
1637
self.assertEqual('steve', client.env.config['region'])
1639
def test_region_non_jes(self):
1640
self.addContext(patch('subprocess.check_call', autospec=True))
1641
client = EnvJujuClient1X(SimpleEnvironment(
1642
'foo', {'type': 'paas'}), '1.23', 'path')
1643
with self.bc_context(client, 'log_dir'):
1644
with boot_context('bar', client, None, [], None, None, None,
1645
'log_dir', keep_env=False, upload_tools=False,
1648
self.assertEqual('steve', client.env.config['region'])
1651
class TestDeployJobParseArgs(FakeHomeTestCase):
834
class TestDeployJobParseArgs(TestCase):
1653
836
def test_deploy_job_parse_args(self):
1654
args = deploy_job_parse_args(['foo', 'bar/juju', 'baz', 'qux'])
837
args = deploy_job_parse_args(['foo', 'bar', 'baz', 'qux'])
1655
838
self.assertEqual(args, Namespace(
1656
839
agent_stream=None,