928
554
return EnvJujuClient(env=env, version='1.2.3.4', full_path=path)
931
class FakeBootstrapManager:
933
def __init__(self, client, keep_env=False):
935
self.tear_down_client = client
936
self.entered_top = False
937
self.exited_top = False
938
self.entered_bootstrap = False
939
self.exited_bootstrap = False
940
self.entered_runtime = False
941
self.exited_runtime = False
942
self.torn_down = False
943
self.permanent = False
944
self.known_hosts = {'0': '0.example.org'}
945
self.keep_env = keep_env
948
def top_context(self):
950
self.entered_top = True
953
self.exited_top = True
956
def bootstrap_context(self, machines):
957
initial_home = self.client.env.juju_home
958
self.client.env.environment = self.client.env.environment + '-temp'
959
self.client.env.controller.name = self.client.env.environment
961
self.entered_bootstrap = True
962
self.client.env.juju_home = os.path.join(initial_home, 'isolated')
963
self.client.bootstrap()
966
self.exited_bootstrap = True
967
if not self.permanent:
968
self.client.env.juju_home = initial_home
971
def runtime_context(self, machines):
973
self.entered_runtime = True
976
if not self.keep_env:
978
self.exited_runtime = True
981
tear_down_meth = getattr(
982
self.tear_down_client, 'destroy_environment',
983
self.tear_down_client.kill_controller)
985
self.torn_down = True
988
def booted_context(self, upload_tools):
989
with self.top_context() as machines:
990
with self.bootstrap_context(machines):
991
self.client.bootstrap(upload_tools)
992
with self.runtime_context(machines):
996
class TestDeployJob(FakeHomeTestCase):
1000
env = JujuData('foo', {})
1001
client = fake_EnvJujuClient(env)
1002
bc_cxt = patch('deploy_stack.client_from_config',
1003
return_value=client)
1004
fc_cxt = patch('jujupy.SimpleEnvironment.from_config',
1007
bm_cxt = patch('deploy_stack.BootstrapManager', autospec=True,
1009
juju_cxt = patch('jujupy.EnvJujuClient.juju', autospec=True)
1010
ajr_cxt = patch('deploy_stack.assess_juju_run', autospec=True)
1011
dds_cxt = patch('deploy_stack.deploy_dummy_stack', autospec=True)
1012
with bc_cxt, fc_cxt, bm_cxt as bm_mock, juju_cxt, ajr_cxt, dds_cxt:
1013
yield client, bm_mock
557
class TestDeployJob(TestCase):
1015
559
@skipIf(sys.platform in ('win32', 'darwin'),
1016
560
'Not supported on Windown and OS X')
1017
def test_background_chaos_used(self):
1019
env='base', juju_bin='/fake/juju', logs='log', temp_env_name='foo',
1020
charm_prefix=None, bootstrap_host=None, machine=None,
1021
series='trusty', debug=False, agent_url=None, agent_stream=None,
1022
keep_env=False, upload_tools=False, with_chaos=1, jes=False,
1023
region=None, verbose=False, upgrade=False, deadline=None,
1026
with patch('deploy_stack.background_chaos',
1027
autospec=True) as bc_mock:
1028
with patch('deploy_stack.assess_juju_relations',
1030
with patch('subprocess.Popen', autospec=True,
1031
return_value=FakePopen('', '', 0)):
1032
_deploy_job(args, 'local:trusty/', 'trusty')
1033
self.assertEqual(bc_mock.call_count, 1)
561
@patch('jujupy.EnvJujuClient.by_version', side_effect=fake_EnvJujuClient)
562
@patch('jujupy.SimpleEnvironment.from_config',
563
side_effect=fake_SimpleEnvironment)
564
@patch('deploy_stack.boot_context', autospec=True)
565
@patch('deploy_stack.EnvJujuClient.juju', autospec=True)
566
def test_background_chaos_used(self, *args):
567
with patch('deploy_stack.background_chaos', autospec=True) as bc_mock:
568
with patch('deploy_stack.deploy_dummy_stack', autospec=True):
569
with patch('deploy_stack.assess_juju_run', autospec=True):
570
_deploy_job('foo', None, None, '', None, None, None, 'log',
571
None, None, None, None, None, None, 1, False,
1034
573
self.assertEqual(bc_mock.mock_calls[0][1][0], 'foo')
1035
574
self.assertEqual(bc_mock.mock_calls[0][1][2], 'log')
1036
575
self.assertEqual(bc_mock.mock_calls[0][1][3], 1)
1038
577
@skipIf(sys.platform in ('win32', 'darwin'),
1039
578
'Not supported on Windown and OS X')
1040
def test_background_chaos_not_used(self):
1042
env='base', juju_bin='/fake/juju', logs='log', temp_env_name='foo',
1043
charm_prefix=None, bootstrap_host=None, machine=None,
1044
series='trusty', debug=False, agent_url=None, agent_stream=None,
1045
keep_env=False, upload_tools=False, with_chaos=0, jes=False,
1046
region=None, verbose=False, upgrade=False, deadline=None,
1049
with patch('deploy_stack.background_chaos',
1050
autospec=True) as bc_mock:
1051
with patch('deploy_stack.assess_juju_relations',
1053
with patch('subprocess.Popen', autospec=True,
1054
return_value=FakePopen('', '', 0)):
1055
_deploy_job(args, 'local:trusty/', 'trusty')
579
@patch('jujupy.EnvJujuClient.by_version', side_effect=fake_EnvJujuClient)
580
@patch('jujupy.SimpleEnvironment.from_config',
581
side_effect=fake_SimpleEnvironment)
582
@patch('deploy_stack.boot_context', autospec=True)
583
@patch('deploy_stack.EnvJujuClient.juju', autospec=True)
584
def test_background_chaos_not_used(self, *args):
585
with patch('deploy_stack.background_chaos', autospec=True) as bc_mock:
586
with patch('deploy_stack.deploy_dummy_stack', autospec=True):
587
with patch('deploy_stack.assess_juju_run', autospec=True):
588
_deploy_job('foo', None, None, '', None, None, None, None,
589
None, None, None, None, None, None, 0, False,
1056
591
self.assertEqual(bc_mock.call_count, 0)
1058
def test_region(self):
1060
env='base', juju_bin='/fake/juju', logs='log', temp_env_name='foo',
1061
charm_prefix=None, bootstrap_host=None, machine=None,
1062
series='trusty', debug=False, agent_url=None, agent_stream=None,
1063
keep_env=False, upload_tools=False, with_chaos=0, jes=False,
1064
region='region-foo', verbose=False, upgrade=False, deadline=None,
1066
with self.ds_cxt() as (client, bm_mock):
1067
with patch('deploy_stack.assess_juju_relations',
1069
with patch('subprocess.Popen', autospec=True,
1070
return_value=FakePopen('', '', 0)):
1071
_deploy_job(args, 'local:trusty/', 'trusty')
1072
jes = client.is_jes_enabled()
1073
bm_mock.assert_called_once_with(
1074
'foo', client, client, None, None, 'trusty', None, None,
1075
'region-foo', 'log', False, permanent=jes, jes_enabled=jes)
1077
def test_deploy_job_changes_series_with_win(self):
1079
series='windows', temp_env_name=None, env=None, upgrade=None,
1080
charm_prefix=None, bootstrap_host=None, machine=None, logs=None,
1081
debug=None, juju_bin=None, agent_url=None, agent_stream=None,
1082
keep_env=None, upload_tools=None, with_chaos=None, jes=None,
1083
region=None, verbose=None)
1084
with patch('deploy_stack.deploy_job_parse_args', return_value=args,
1086
with patch('deploy_stack._deploy_job', autospec=True) as ds_mock:
1088
ds_mock.assert_called_once_with(args, 'windows', 'trusty')
1090
def test_deploy_job_changes_series_with_centos(self):
1092
series='centos', temp_env_name=None, env=None, upgrade=None,
1093
charm_prefix=None, bootstrap_host=None, machine=None, logs=None,
1094
debug=None, juju_bin=None, agent_url=None, agent_stream=None,
1095
keep_env=None, upload_tools=None, with_chaos=None, jes=None,
1096
region=None, verbose=None)
1097
with patch('deploy_stack.deploy_job_parse_args', return_value=args,
1099
with patch('deploy_stack._deploy_job', autospec=True) as ds_mock:
1101
ds_mock.assert_called_once_with(args, 'centos', 'trusty')
1104
class TestTestUpgrade(FakeHomeTestCase):
594
class TestTestUpgrade(TestCase):
1107
597
'juju', '--show-log', 'run', '-e', 'foo', '--format', 'json',
1108
598
'--service', 'dummy-source,dummy-sink', 'uname')
1110
'juju', '--show-log', 'show-status', '-m', 'foo:foo',
1112
CONTROLLER_STATUS = (
1113
'juju', '--show-log', 'show-status', '-m', 'foo:controller',
1115
GET_ENV = ('juju', '--show-log', 'model-config', '-m', 'foo:foo',
1116
'agent-metadata-url')
1117
GET_CONTROLLER_ENV = (
1118
'juju', '--show-log', 'model-config', '-m', 'foo:controller',
1119
'agent-metadata-url')
1121
'juju', '--show-log', 'list-models', '-c', 'foo', '--format', 'yaml')
599
VERSION = ('/bar/juju', '--version')
600
STATUS = ('juju', '--show-log', 'status', '-e', 'foo')
601
GET_ENV = ('juju', '--show-log', 'get-env', '-e', 'foo',
602
'tools-metadata-url')
605
setup_test_logging(self)
1124
608
def upgrade_output(cls, args, **kwargs):
1125
609
status = yaml.safe_dump({
1126
610
'machines': {'0': {
1127
611
'agent-state': 'started',
1128
'agent-version': '2.0-rc2'}},
612
'agent-version': '1.38'}},
1129
613
'services': {}})
1130
614
juju_run_out = json.dumps([
1131
615
{"MachineId": "1", "Stdout": "Linux\n"},
1132
616
{"MachineId": "2", "Stdout": "Linux\n"}])
1133
list_models = json.dumps(
1135
{'name': 'controller'},
1139
618
cls.STATUS: status,
1140
cls.CONTROLLER_STATUS: status,
1141
619
cls.RUN_UNAME: juju_run_out,
1142
cls.GET_ENV: 'testing',
1143
cls.GET_CONTROLLER_ENV: 'testing',
1144
cls.LIST_MODELS: list_models,
621
cls.GET_ENV: 'testing'
1146
return FakePopen(output[args], '', 0)
1149
626
def upgrade_mocks(self):
1150
with patch('subprocess.Popen', side_effect=self.upgrade_output,
627
with patch('subprocess.check_output', side_effect=self.upgrade_output,
1151
628
autospec=True) as co_mock:
1152
629
with patch('subprocess.check_call', autospec=True) as cc_mock:
1153
630
with patch('deploy_stack.check_token', autospec=True):
1154
631
with patch('deploy_stack.get_random_string',
1155
632
return_value="FAKETOKEN", autospec=True):
1156
with patch('jujupy.EnvJujuClient.get_version',
1157
side_effect=lambda cls:
1158
'2.0-rc2-arch-series'):
1160
'jujupy.get_timeout_prefix',
1161
autospec=True, return_value=()):
1162
yield (co_mock, cc_mock)
633
with patch('sys.stdout', autospec=True):
634
yield (co_mock, cc_mock)
1164
636
def test_assess_upgrade(self):
1165
env = JujuData('foo', {'type': 'foo'})
637
env = SimpleEnvironment('foo', {'type': 'foo'})
1166
638
old_client = EnvJujuClient(env, None, '/foo/juju')
1167
639
with self.upgrade_mocks() as (co_mock, cc_mock):
1168
640
assess_upgrade(old_client, '/bar/juju')
1169
641
new_client = EnvJujuClient(env, None, '/bar/juju')
1170
# Needs to upgrade the controller first.
1171
assert_juju_call(self, cc_mock, new_client, (
1172
'juju', '--show-log', 'upgrade-juju', '-m', 'foo:controller',
1173
'--agent-version', '2.0-rc2'), 0)
1174
assert_juju_call(self, cc_mock, new_client, (
1175
'juju', '--show-log', 'upgrade-juju', '-m', 'foo:foo',
1176
'--agent-version', '2.0-rc2'), 1)
642
assert_juju_call(self, cc_mock, new_client, (
643
'juju', '--show-log', 'upgrade-juju', '-e', 'foo', '--version',
645
assert_juju_call(self, cc_mock, new_client, (
646
'juju', '--show-log', 'set', '-e', 'foo', 'dummy-source',
647
'token=FAKETOKEN'), 1)
1177
648
self.assertEqual(cc_mock.call_count, 2)
1178
assert_juju_call(self, co_mock, new_client, self.LIST_MODELS, 0)
1179
assert_juju_call(self, co_mock, new_client, self.GET_CONTROLLER_ENV, 1)
1180
assert_juju_call(self, co_mock, new_client, self.GET_CONTROLLER_ENV, 2)
1181
assert_juju_call(self, co_mock, new_client, self.CONTROLLER_STATUS, 3)
1182
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 4)
1183
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 5)
1184
assert_juju_call(self, co_mock, new_client, self.STATUS, 6)
1185
self.assertEqual(co_mock.call_count, 7)
1187
def test__get_clients_to_upgrade_returns_new_version_class(self):
1188
env = SimpleEnvironment('foo', {'type': 'foo'})
1189
old_client = fake_juju_client(
1190
env, '/foo/juju', version='1.25', cls=EnvJujuClient25)
1191
with patch('jujupy.EnvJujuClient.get_version',
1192
return_value='1.26-arch-series'):
1193
with patch('jujupy.EnvJujuClient26._get_models', return_value=[]):
1194
[new_client] = _get_clients_to_upgrade(
1195
old_client, '/foo/newer/juju')
1197
self.assertIs(type(new_client), EnvJujuClient26)
1199
def test__get_clients_to_upgrade_returns_controller_and_model(self):
1200
old_client = fake_juju_client()
1201
old_client.bootstrap()
1203
with patch('jujupy.EnvJujuClient.get_version',
1204
return_value='2.0-rc2-arch-series'):
1205
new_clients = _get_clients_to_upgrade(
1206
old_client, '/foo/newer/juju')
1208
self.assertEqual(len(new_clients), 2)
1209
self.assertEqual(new_clients[0].model_name, 'controller')
1210
self.assertEqual(new_clients[1].model_name, 'name')
649
self.assertEqual(co_mock.mock_calls[0], call(self.VERSION))
650
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 1,
652
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 2,
654
assert_juju_call(self, co_mock, new_client, self.STATUS, 3,
656
assert_juju_call(self, co_mock, new_client, self.RUN_UNAME, 4,
658
self.assertEqual(co_mock.call_count, 5)
1212
660
def test_mass_timeout(self):
1213
661
config = {'type': 'foo'}
1214
old_client = EnvJujuClient(JujuData('foo', config), None, '/foo/juju')
662
old_client = EnvJujuClient(SimpleEnvironment('foo', config),
1215
664
with self.upgrade_mocks():
1216
665
with patch.object(EnvJujuClient, 'wait_for_version') as wfv_mock:
1217
666
assess_upgrade(old_client, '/bar/juju')
1218
wfv_mock.assert_has_calls([call('2.0-rc2', 600)] * 2)
667
wfv_mock.assert_called_once_with('1.38', 600)
1219
668
config['type'] = 'maas'
1220
669
with patch.object(EnvJujuClient, 'wait_for_version') as wfv_mock:
1221
670
assess_upgrade(old_client, '/bar/juju')
1222
wfv_mock.assert_has_calls([call('2.0-rc2', 1200)] * 2)
1225
class TestBootstrapManager(FakeHomeTestCase):
1227
def test_from_args(self):
1228
deadline = datetime(2012, 11, 10, 9, 8, 7)
1230
env='foo', juju_bin='bar', debug=True, temp_env_name='baz',
1231
bootstrap_host='example.org', machine=['example.com'],
1232
series='angsty', agent_url='qux', agent_stream='escaped',
1233
region='eu-west-northwest-5', logs='pine', keep_env=True,
1235
with patch('deploy_stack.client_from_config') as fc_mock:
1236
bs_manager = BootstrapManager.from_args(args)
1237
fc_mock.assert_called_once_with('foo', 'bar', debug=True,
1238
soft_deadline=deadline)
1239
self.assertEqual('baz', bs_manager.temp_env_name)
1240
self.assertIs(fc_mock.return_value, bs_manager.client)
1241
self.assertIs(fc_mock.return_value, bs_manager.tear_down_client)
1242
self.assertEqual('example.org', bs_manager.bootstrap_host)
1243
self.assertEqual(['example.com'], bs_manager.machines)
1244
self.assertEqual('angsty', bs_manager.series)
1245
self.assertEqual('qux', bs_manager.agent_url)
1246
self.assertEqual('escaped', bs_manager.agent_stream)
1247
self.assertEqual('eu-west-northwest-5', bs_manager.region)
1248
self.assertIs(True, bs_manager.keep_env)
1249
self.assertEqual('pine', bs_manager.log_dir)
1250
jes_enabled = bs_manager.client.is_jes_enabled.return_value
1251
self.assertEqual(jes_enabled, bs_manager.permanent)
1252
self.assertEqual(jes_enabled, bs_manager.jes_enabled)
1253
self.assertEqual({'0': 'example.org'}, bs_manager.known_hosts)
1255
def test_no_args(self):
1257
env='foo', juju_bin='bar', debug=True, temp_env_name='baz',
1258
bootstrap_host='example.org', machine=['example.com'],
1259
series='angsty', agent_url='qux', agent_stream='escaped',
1260
region='eu-west-northwest-5', logs=None, keep_env=True,
1262
with patch('deploy_stack.client_from_config') as fc_mock:
1263
with patch('utility.os.makedirs'):
1264
bs_manager = BootstrapManager.from_args(args)
1265
fc_mock.assert_called_once_with('foo', 'bar', debug=True,
1267
self.assertEqual('baz', bs_manager.temp_env_name)
1268
self.assertIs(fc_mock.return_value, bs_manager.client)
1269
self.assertIs(fc_mock.return_value, bs_manager.tear_down_client)
1270
self.assertEqual('example.org', bs_manager.bootstrap_host)
1271
self.assertEqual(['example.com'], bs_manager.machines)
1272
self.assertEqual('angsty', bs_manager.series)
1273
self.assertEqual('qux', bs_manager.agent_url)
1274
self.assertEqual('escaped', bs_manager.agent_stream)
1275
self.assertEqual('eu-west-northwest-5', bs_manager.region)
1276
self.assertIs(True, bs_manager.keep_env)
1277
logs_arg = bs_manager.log_dir.split("/")
1278
logs_ts = logs_arg[4]
1279
self.assertEqual(logs_arg[1:4], ['tmp', 'baz', 'logs'])
1280
self.assertTrue(logs_ts, datetime.strptime(logs_ts, "%Y%m%d%H%M%S"))
1281
jes_enabled = bs_manager.client.is_jes_enabled.return_value
1282
self.assertEqual(jes_enabled, bs_manager.permanent)
1283
self.assertEqual(jes_enabled, bs_manager.jes_enabled)
1284
self.assertEqual({'0': 'example.org'}, bs_manager.known_hosts)
1286
def test_jes_not_permanent(self):
1287
with self.assertRaisesRegexp(ValueError, 'Cannot set permanent False'
1288
' if jes_enabled is True.'):
1290
jes_enabled=True, permanent=False,
1291
temp_env_name=None, client=None, tear_down_client=None,
1292
bootstrap_host=None, machines=[], series=None, agent_url=None,
1293
agent_stream=None, region=None, log_dir=None, keep_env=None)
1295
def test_aws_machines_updates_bootstrap_host(self):
1296
client = fake_juju_client()
1297
client.env.config['type'] = 'manual'
1298
bs_manager = BootstrapManager(
1299
'foobar', client, client, None, [], None, None, None, None,
1300
client.env.juju_home, False, False, False)
1301
with patch('deploy_stack.run_instances',
1302
return_value=[('foo', 'aws.example.org')]):
1303
with patch('deploy_stack.destroy_job_instances'):
1304
with bs_manager.aws_machines():
1305
self.assertEqual({'0': 'aws.example.org'},
1306
bs_manager.known_hosts)
1308
def test_from_args_no_host(self):
1310
env='foo', juju_bin='bar', debug=True, temp_env_name='baz',
1311
bootstrap_host=None, machine=['example.com'],
1312
series='angsty', agent_url='qux', agent_stream='escaped',
1313
region='eu-west-northwest-5', logs='pine', keep_env=True,
1315
with patch('deploy_stack.client_from_config'):
1316
bs_manager = BootstrapManager.from_args(args)
1317
self.assertIs(None, bs_manager.bootstrap_host)
1318
self.assertEqual({}, bs_manager.known_hosts)
1320
def make_client(self):
1321
client = MagicMock()
1322
client.env = SimpleEnvironment(
1323
'foo', {'type': 'baz'}, use_context(self, temp_dir()))
1324
client.is_jes_enabled.return_value = False
1325
client.get_matching_agent_version.return_value = '3.14'
1326
client.get_cache_path.return_value = get_cache_path(
1327
client.env.juju_home)
1330
def test_bootstrap_context_tear_down(self):
1331
client = fake_juju_client()
1332
client.env.juju_home = use_context(self, temp_dir())
1333
initial_home = client.env.juju_home
1334
bs_manager = BootstrapManager(
1335
'foobar', client, client, None, [], None, None, None, None,
1336
client.env.juju_home, False, False, False)
1338
def check_config(client_, jes_enabled, try_jes=False):
1339
self.assertEqual(0, client.is_jes_enabled.call_count)
1340
jenv_path = get_jenv_path(client.env.juju_home, 'foobar')
1341
self.assertFalse(os.path.exists(jenv_path))
1342
environments_path = get_environments_path(client.env.juju_home)
1343
self.assertTrue(os.path.isfile(environments_path))
1344
self.assertNotEqual(initial_home, client.env.juju_home)
1346
ije_cxt = patch.object(client, 'is_jes_enabled')
1347
with patch('deploy_stack.tear_down',
1348
side_effect=check_config) as td_mock, ije_cxt:
1349
with bs_manager.bootstrap_context([]):
1350
td_mock.assert_called_once_with(client, False, try_jes=True)
1352
def test_bootstrap_context_tear_down_jenv(self):
1353
client = self.make_client()
1354
initial_home = client.env.juju_home
1355
jenv_path = get_jenv_path(client.env.juju_home, 'foobar')
1356
os.makedirs(os.path.dirname(jenv_path))
1357
with open(jenv_path, 'w'):
1360
bs_manager = BootstrapManager(
1361
'foobar', client, client, None, [], None, None, None, None,
1362
client.env.juju_home, False, False, False)
1364
def check_config(client_, jes_enabled, try_jes=False):
1365
self.assertEqual(0, client.is_jes_enabled.call_count)
1366
self.assertTrue(os.path.isfile(jenv_path))
1367
environments_path = get_environments_path(client.env.juju_home)
1368
self.assertFalse(os.path.exists(environments_path))
1369
self.assertEqual(initial_home, client.env.juju_home)
1371
with patch('deploy_stack.tear_down',
1372
side_effect=check_config) as td_mock:
1373
with bs_manager.bootstrap_context([]):
1374
td_mock.assert_called_once_with(client, False, try_jes=False)
1376
def test_bootstrap_context_tear_down_client(self):
1377
client = self.make_client()
1378
tear_down_client = self.make_client()
1379
tear_down_client.env = client.env
1380
bs_manager = BootstrapManager(
1381
'foobar', client, tear_down_client, None, [], None, None, None,
1382
None, client.env.juju_home, False, False, False)
1384
def check_config(client_, jes_enabled, try_jes=False):
1385
self.assertEqual(0, client.is_jes_enabled.call_count)
1386
tear_down_client.is_jes_enabled.assert_called_once_with()
1388
with patch('deploy_stack.tear_down',
1389
side_effect=check_config) as td_mock:
1390
with bs_manager.bootstrap_context([]):
1391
td_mock.assert_called_once_with(tear_down_client,
1392
False, try_jes=True)
1394
def test_bootstrap_context_tear_down_client_jenv(self):
1395
client = self.make_client()
1396
tear_down_client = self.make_client()
1397
tear_down_client.env = client.env
1398
jenv_path = get_jenv_path(client.env.juju_home, 'foobar')
1399
os.makedirs(os.path.dirname(jenv_path))
1400
with open(jenv_path, 'w'):
1403
bs_manager = BootstrapManager(
1404
'foobar', client, tear_down_client,
1405
None, [], None, None, None, None, client.env.juju_home, False,
1408
def check_config(client_, jes_enabled, try_jes=False):
1409
self.assertEqual(0, client.is_jes_enabled.call_count)
1410
tear_down_client.is_jes_enabled.assert_called_once_with()
1412
with patch('deploy_stack.tear_down',
1413
side_effect=check_config) as td_mock:
1414
with bs_manager.bootstrap_context([]):
1415
td_mock.assert_called_once_with(tear_down_client, False,
1418
def test_bootstrap_context_no_set_home(self):
1419
orig_home = get_juju_home()
1420
client = self.make_client()
1421
jenv_path = get_jenv_path(client.env.juju_home, 'foobar')
1422
os.makedirs(os.path.dirname(jenv_path))
1423
with open(jenv_path, 'w'):
1426
bs_manager = BootstrapManager(
1427
'foobar', client, client, None, [], None, None, None, None,
1428
client.env.juju_home, False, False, False)
1429
with bs_manager.bootstrap_context([]):
1430
self.assertEqual(orig_home, get_juju_home())
1432
def test_bootstrap_context_calls_update_env(self):
1433
client = fake_juju_client()
1434
client.env.juju_home = use_context(self, temp_dir())
1435
ue_mock = use_context(
1436
self, patch('deploy_stack.update_env', wraps=update_env))
1437
wfp_mock = use_context(
1438
self, patch('deploy_stack.wait_for_port', autospec=True))
1439
bs_manager = BootstrapManager(
1440
'bar', client, client, None,
1441
[], 'wacky', 'url', 'devel', None, client.env.juju_home, False,
1443
bs_manager.known_hosts['0'] = 'bootstrap.example.org'
1444
with bs_manager.bootstrap_context([]):
1446
ue_mock.assert_called_with(
1447
client.env, 'bar', series='wacky',
1448
bootstrap_host='bootstrap.example.org',
1449
agent_url='url', agent_stream='devel', region=None)
1450
wfp_mock.assert_called_once_with(
1451
'bootstrap.example.org', 22, timeout=120)
1453
def test_bootstrap_context_calls_update_env_omit(self):
1454
client = fake_juju_client()
1455
client.env.juju_home = use_context(self, temp_dir())
1456
ue_mock = use_context(
1457
self, patch('deploy_stack.update_env', wraps=update_env))
1458
wfp_mock = use_context(
1459
self, patch('deploy_stack.wait_for_port', autospec=True))
1460
bs_manager = BootstrapManager(
1461
'bar', client, client, None,
1462
[], 'wacky', 'url', 'devel', None, client.env.juju_home, True,
1464
bs_manager.known_hosts['0'] = 'bootstrap.example.org'
1465
with bs_manager.bootstrap_context(
1466
[], omit_config={'bootstrap_host', 'series'}):
1468
ue_mock.assert_called_with(client.env, 'bar', agent_url='url',
1469
agent_stream='devel', region=None)
1470
wfp_mock.assert_called_once_with(
1471
'bootstrap.example.org', 22, timeout=120)
1473
def test_handle_bootstrap_exceptions_ignores_soft_deadline(self):
1474
env = JujuData('foo', {'type': 'nonlocal'})
1475
client = EnvJujuClient(env, None, None)
1476
tear_down_client = EnvJujuClient(env, None, None)
1477
soft_deadline = datetime(2015, 1, 2, 3, 4, 6)
1478
now = soft_deadline + timedelta(seconds=1)
1479
client.env.juju_home = use_context(self, temp_dir())
1480
bs_manager = BootstrapManager(
1481
'foobar', client, tear_down_client, None, [], None, None, None,
1482
None, client.env.juju_home, False, permanent=True,
1485
def do_check(*args, **kwargs):
1486
with client.check_timeouts():
1487
with tear_down_client.check_timeouts():
1490
with patch.object(bs_manager.tear_down_client, 'juju',
1491
side_effect=do_check, autospec=True):
1492
with patch.object(client._backend, '_now', return_value=now):
1493
fake_exception = Exception()
1494
with self.assertRaises(LoggedException) as exc:
1495
with bs_manager.handle_bootstrap_exceptions():
1496
client._backend.soft_deadline = soft_deadline
1497
tear_down_client._backend.soft_deadline = soft_deadline
1498
raise fake_exception
1499
self.assertIs(fake_exception, exc.exception.exception)
1501
def test_tear_down_requires_same_env(self):
1502
client = self.make_client()
1503
client.env.juju_home = 'foobar'
1504
tear_down_client = self.make_client()
1505
tear_down_client.env.juju_home = 'barfoo'
1506
bs_manager = BootstrapManager(
1507
'foobar', client, tear_down_client,
1508
None, [], None, None, None, None, client.env.juju_home, False,
1511
def check_home(foo, bar, try_jes):
1512
self.assertEqual(client.env.juju_home,
1513
tear_down_client.env.juju_home)
1515
with self.assertRaisesRegexp(AssertionError,
1516
'Tear down client needs same env'):
1517
with patch('deploy_stack.tear_down', autospec=True,
1518
side_effect=check_home):
1519
bs_manager.tear_down()
1520
self.assertEqual('barfoo', tear_down_client.env.juju_home)
1522
def test_dump_all_no_jes_one_model(self):
1523
client = fake_juju_client()
1525
with temp_dir() as log_dir:
1526
bs_manager = BootstrapManager(
1527
'foobar', client, client,
1528
None, [], None, None, None, None, log_dir, False,
1529
False, jes_enabled=False)
1530
with patch('deploy_stack.dump_env_logs_known_hosts'):
1531
with patch.object(client, 'iter_model_clients') as imc_mock:
1532
bs_manager.dump_all_logs()
1533
self.assertEqual(0, imc_mock.call_count)
1535
def test_dump_all_multi_model(self):
1536
client = fake_juju_client()
1538
with temp_dir() as log_dir:
1539
bs_manager = BootstrapManager(
1540
'foobar', client, client,
1541
None, [], None, None, None, None, log_dir, False,
1542
permanent=True, jes_enabled=True)
1543
with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1544
with patch.object(bs_manager, '_should_dump',
1546
bs_manager.dump_all_logs()
1548
clients = dict((c[1][0].env.environment, c[1][0])
1549
for c in del_mock.mock_calls)
1550
self.assertItemsEqual(
1551
[call(client, os.path.join(log_dir, 'name'), None, {}),
1552
call(clients['controller'], os.path.join(log_dir, 'controller'),
1553
'foo/models/cache.yaml', {})],
1554
del_mock.mock_calls)
1556
def test_dump_all_multi_model_iter_failure(self):
1557
client = fake_juju_client()
1559
with temp_dir() as log_dir:
1560
bs_manager = BootstrapManager(
1561
'foobar', client, client,
1562
None, [], None, None, None, None, log_dir, False,
1563
permanent=True, jes_enabled=True)
1564
with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1565
with patch.object(client, 'iter_model_clients',
1566
side_effect=Exception):
1567
with patch.object(bs_manager, '_should_dump',
1569
bs_manager.dump_all_logs()
1571
clients = dict((c[1][0].env.environment, c[1][0])
1572
for c in del_mock.mock_calls)
1574
self.assertItemsEqual(
1575
[call(client, os.path.join(log_dir, 'name'), None, {}),
1576
call(clients['controller'], os.path.join(log_dir, 'controller'),
1577
'foo/models/cache.yaml', {})],
1578
del_mock.mock_calls)
1580
def test_dump_all_logs_uses_known_hosts(self):
1581
client = fake_juju_client_optional_jes(jes_enabled=False)
1582
with temp_dir() as log_dir:
1583
bs_manager = BootstrapManager(
1584
'foobar', client, client,
1585
None, [], None, None, None, None, log_dir, False,
1587
bs_manager.known_hosts['2'] = 'example.org'
1589
with patch('deploy_stack.dump_env_logs_known_hosts') as del_mock:
1590
with patch.object(bs_manager, '_should_dump',
1592
bs_manager.dump_all_logs()
1593
del_mock.assert_called_once_with(
1594
client, os.path.join(log_dir, 'name'),
1595
'foo/environments/name.jenv', {
1599
def test_runtime_context_raises_logged_exception(self):
1600
client = fake_juju_client()
1602
bs_manager = BootstrapManager(
1603
'foobar', client, client,
1604
None, [], None, None, None, None, client.env.juju_home, False,
1606
test_error = Exception("Some exception")
1607
test_error.output = "a stdout value"
1608
test_error.stderr = "a stderr value"
1609
with patch.object(bs_manager, 'dump_all_logs', autospec=True):
1610
with self.assertRaises(LoggedException) as err_ctx:
1611
with bs_manager.runtime_context([]):
1613
self.assertIs(err_ctx.exception.exception, test_error)
1614
self.assertIn("a stdout value", self.log_stream.getvalue())
1615
self.assertIn("a stderr value", self.log_stream.getvalue())
1617
def test_runtime_context_looks_up_host(self):
1618
client = fake_juju_client()
1620
bs_manager = BootstrapManager(
1621
'foobar', client, client,
1622
None, [], None, None, None, None, client.env.juju_home, False,
1624
with patch.object(bs_manager, 'dump_all_logs', autospec=True):
1625
with bs_manager.runtime_context([]):
1627
'0': '0.example.com'}, bs_manager.known_hosts)
1629
@patch('deploy_stack.dump_env_logs_known_hosts', autospec=True)
1630
def test_runtime_context_addable_machines_no_known_hosts(self, del_mock):
1631
client = fake_juju_client()
1633
bs_manager = BootstrapManager(
1634
'foobar', client, client,
1635
None, [], None, None, None, None, client.env.juju_home, False,
1637
bs_manager.known_hosts = {}
1638
with patch.object(bs_manager.client, 'add_ssh_machines',
1639
autospec=True) as ads_mock:
1640
with patch.object(bs_manager, 'dump_all_logs', autospec=True):
1641
with bs_manager.runtime_context(['baz']):
1642
ads_mock.assert_called_once_with(['baz'])
1644
@patch('deploy_stack.BootstrapManager.dump_all_logs', autospec=True)
1645
def test_runtime_context_addable_machines_with_known_hosts(self, dal_mock):
1646
client = fake_juju_client()
1648
with temp_dir() as log_dir:
1649
bs_manager = BootstrapManager(
1650
'foobar', client, client,
1651
None, [], None, None, None, None, log_dir, False,
1653
bs_manager.known_hosts['0'] = 'example.org'
1654
with patch.object(bs_manager.client, 'add_ssh_machines',
1655
autospec=True) as ads_mock:
1656
with bs_manager.runtime_context(['baz']):
1657
ads_mock.assert_called_once_with(['baz'])
1659
def test_booted_context_handles_logged_exception(self):
1660
client = fake_juju_client()
1661
with temp_dir() as root:
1662
log_dir = os.path.join(root, 'log-dir')
1664
bs_manager = BootstrapManager(
1665
'foobar', client, client,
1666
None, [], None, None, None, None, log_dir, False,
1668
juju_home = os.path.join(root, 'juju-home')
1670
client.env.juju_home = juju_home
1671
with self.assertRaises(SystemExit):
1672
with patch.object(bs_manager, 'dump_all_logs'):
1673
with bs_manager.booted_context(False):
1674
raise LoggedException()
1676
def test_booted_context_omits_supported(self):
1677
client = fake_juju_client()
1678
client.env.juju_home = use_context(self, temp_dir())
1679
client.bootstrap_replaces = {'agent-version', 'series',
1680
'bootstrap-host', 'agent-stream'}
1681
ue_mock = use_context(
1682
self, patch('deploy_stack.update_env', wraps=update_env))
1683
wfp_mock = use_context(
1684
self, patch('deploy_stack.wait_for_port', autospec=True))
1685
bs_manager = BootstrapManager(
1686
'bar', client, client, 'bootstrap.example.org',
1687
[], 'wacky', 'url', 'devel', None, client.env.juju_home, False,
1689
with patch.object(bs_manager, 'runtime_context'):
1690
with bs_manager.booted_context([]):
1694
'default-series': 'wacky',
1695
'agent-metadata-url': 'url',
1699
}, client.get_model_config())
1700
ue_mock.assert_called_with(client.env, 'bar', agent_url='url',
1702
wfp_mock.assert_called_once_with(
1703
'bootstrap.example.org', 22, timeout=120)
1706
def booted_to_bootstrap(self, bs_manager):
1707
"""Preform patches to focus on the call to bootstrap."""
1708
with patch.object(bs_manager, 'dump_all_logs'):
1709
with patch.object(bs_manager, 'runtime_context'):
1710
with patch.object(bs_manager.client, 'juju'):
1711
with patch.object(bs_manager.client, 'bootstrap') as mock:
1714
def test_booted_context_kwargs(self):
1715
client = fake_juju_client()
1716
with temp_dir() as root:
1717
log_dir = os.path.join(root, 'log-dir')
1719
bs_manager = BootstrapManager(
1720
'foobar', client, client,
1721
None, [], None, None, None, None, log_dir, False,
1723
juju_home = os.path.join(root, 'juju-home')
1725
client.env.juju_home = juju_home
1726
with self.booted_to_bootstrap(bs_manager) as bootstrap_mock:
1727
with bs_manager.booted_context(False, to='test'):
1728
bootstrap_mock.assert_called_once_with(
1729
upload_tools=False, to='test', bootstrap_series=None)
1730
with self.booted_to_bootstrap(bs_manager) as bootstrap_mock:
1731
with bs_manager.existing_booted_context(False, to='test'):
1732
bootstrap_mock.assert_called_once_with(
1733
upload_tools=False, to='test', bootstrap_series=None)
1735
def test_runtime_context_teardown_ignores_soft_deadline(self):
1736
env = JujuData('foo', {'type': 'nonlocal'})
1737
soft_deadline = datetime(2015, 1, 2, 3, 4, 6)
1738
now = soft_deadline + timedelta(seconds=1)
1739
client = EnvJujuClient(env, None, None)
1740
tear_down_client = EnvJujuClient(env, None, None)
1742
def do_check_client(*args, **kwargs):
1743
with client.check_timeouts():
1746
def do_check_teardown_client(*args, **kwargs):
1747
with tear_down_client.check_timeouts():
1750
with temp_dir() as log_dir:
1751
bs_manager = BootstrapManager(
1752
'foobar', client, tear_down_client,
1753
None, [], None, None, None, None, log_dir, False,
1755
bs_manager.known_hosts['0'] = 'example.org'
1756
with patch.object(bs_manager.client, 'juju',
1757
side_effect=do_check_client, autospec=True):
1758
with patch.object(bs_manager.client, 'iter_model_clients',
1759
side_effect=do_check_client, autospec=True,
1761
with patch.object(bs_manager, 'tear_down',
1762
do_check_teardown_client):
1763
with patch.object(client._backend, '_now',
1765
with bs_manager.runtime_context(['baz']):
1766
client._backend.soft_deadline = soft_deadline
1767
td_backend = tear_down_client._backend
1768
td_backend.soft_deadline = soft_deadline
1771
def make_bootstrap_manager(self):
1772
client = fake_juju_client()
1773
with temp_dir() as log_dir:
1774
bs_manager = BootstrapManager(
1775
'foobar', client, client,
1776
None, [], None, None, None, None, log_dir, False,
1780
def test_top_context_dumps_timings(self):
1781
with self.make_bootstrap_manager() as bs_manager:
1782
with patch('deploy_stack.dump_juju_timings') as djt_mock:
1783
with bs_manager.top_context():
1785
djt_mock.assert_called_once_with(bs_manager.client, bs_manager.log_dir)
1787
def test_top_context_dumps_timings_on_exception(self):
1788
with self.make_bootstrap_manager() as bs_manager:
1789
with patch('deploy_stack.dump_juju_timings') as djt_mock:
1790
with self.assertRaises(ValueError):
1791
with bs_manager.top_context():
1793
djt_mock.assert_called_once_with(bs_manager.client, bs_manager.log_dir)
1795
def test_top_context_no_log_dir_skips_timings(self):
1796
with self.make_bootstrap_manager() as bs_manager:
1797
bs_manager.log_dir = None
1798
with patch('deploy_stack.dump_juju_timings') as djt_mock:
1799
with bs_manager.top_context():
1801
self.assertEqual(djt_mock.call_count, 0)
1804
class TestBootContext(FakeHomeTestCase):
671
wfv_mock.assert_called_once_with('1.38', 1200)
674
class TestBootContext(TestCase):
1806
676
def setUp(self):
1807
super(TestBootContext, self).setUp()
677
self.addContext(patch('subprocess.Popen', side_effect=Exception))
1808
678
self.addContext(patch('sys.stdout'))
1810
680
def addContext(self, cxt):
1813
683
:return: The value emitted by cxt.__enter__.
1815
return use_context(self, cxt)
685
result = cxt.__enter__()
686
self.addCleanup(lambda: cxt.__exit__(None, None, None))
1818
def bc_context(self, client, log_dir=None, jes=None, keep_env=False):
1819
dal_mock = self.addContext(
1820
patch('deploy_stack.BootstrapManager.dump_all_logs'))
690
def bc_context(self, client, log_dir=None, jes=False, keep_env=False):
691
dl_mock = self.addContext(patch('deploy_stack.dump_env_logs'))
1821
692
self.addContext(patch('deploy_stack.get_machine_dns_name',
1822
693
return_value='foo', autospec=True))
1823
if isinstance(client, EnvJujuClient1X):
1826
models = [{'name': 'controller'}, {'name': 'bar'}]
1827
self.addContext(patch.object(client, '_get_models',
1828
return_value=models, autospec=True))
1829
c_mock = self.addContext(patch('subprocess.call', autospec=True,
1831
juju_name = os.path.basename(client.full_path)
694
c_mock = self.addContext(patch('subprocess.call', autospec=True))
1838
with patch('subprocess.Popen', autospec=True,
1839
return_value=FakePopen(output, '', 0)) as po_mock:
699
with patch('subprocess.check_output', autospec=True,
700
return_value=co_return) as co_mock:
1841
for help_index in range(po_count):
1842
assert_juju_call(self, po_mock, client, (
1843
juju_name, '--show-log', 'help', 'commands'),
1844
call_index=help_index)
1845
self.assertEqual(po_count, po_mock.call_count)
1846
dal_mock.assert_called_once_with()
702
assert_juju_call(self, co_mock, client, (
703
'juju', '--show-log', 'help', 'commands'), assign_stderr=True)
705
runtime_config = os.path.join(client.juju_home, 'environments',
708
runtime_config = os.path.join(client.juju_home, 'environments',
710
dl_mock.assert_called_once_with(
711
client, 'foo', log_dir, runtime_config=runtime_config)
713
self.assertEqual(c_mock.call_count, 0)
1851
for call_index in range(tear_down_count):
1854
self, c_mock, client, get_timeout_prefix(600) + (
1855
juju_name, '--show-log', jes, 'bar', '-y'), call_index)
1858
self, c_mock, client, get_timeout_prefix(600) + (
1859
juju_name, '--show-log', 'destroy-environment', 'bar',
1861
self.assertEqual(tear_down_count, c_mock.call_count)
715
assert_juju_call(self, c_mock, client, (
716
'timeout', '600.00s', 'juju', '--show-log',
717
'destroy-environment', 'bar', '--force', '-y'))
1863
719
def test_bootstrap_context(self):
1864
720
cc_mock = self.addContext(patch('subprocess.check_call'))
1865
client = EnvJujuClient(JujuData(
1866
'foo', {'type': 'paas', 'region': 'qux'}), '1.23', 'path')
1867
with self.bc_context(client, 'log_dir', jes='kill-controller'):
1868
with observable_temp_file() as config_file:
1869
with boot_context('bar', client, None, [], None, None, None,
1870
'log_dir', keep_env=False,
1871
upload_tools=False):
1873
assert_juju_call(self, cc_mock, client, (
1874
'path', '--show-log', 'bootstrap', '--constraints',
1875
'mem=2G', 'bar', 'paas/qux', '--config', config_file.name,
1876
'--default-model', 'bar', '--agent-version', '1.23'), 0)
1877
assert_juju_call(self, cc_mock, client, (
1878
'path', '--show-log', 'list-controllers'), 1)
1879
assert_juju_call(self, cc_mock, client, (
1880
'path', '--show-log', 'list-models', '-c', 'bar'), 2)
1881
assert_juju_call(self, cc_mock, client, (
1882
'path', '--show-log', 'show-status', '-m', 'bar:controller',
1883
'--format', 'yaml'), 3)
1884
assert_juju_call(self, cc_mock, client, (
1885
'path', '--show-log', 'show-status', '-m', 'bar:bar',
1886
'--format', 'yaml'), 4)
1888
def test_bootstrap_context_non_jes(self):
1889
cc_mock = self.addContext(patch('subprocess.check_call'))
1890
client = EnvJujuClient1X(SimpleEnvironment(
721
client = EnvJujuClient(SimpleEnvironment(
1891
722
'foo', {'type': 'paas'}), '1.23', 'path')
1892
723
with self.bc_context(client, 'log_dir'):
1893
724
with boot_context('bar', client, None, [], None, None, None,
1894
725
'log_dir', keep_env=False, upload_tools=False):
1896
727
assert_juju_call(self, cc_mock, client, (
1897
'path', '--show-log', 'bootstrap', '-e', 'bar', '--constraints',
728
'juju', '--show-log', 'bootstrap', '-e', 'bar', '--constraints',
1899
730
assert_juju_call(self, cc_mock, client, (
1900
'path', '--show-log', 'status', '-e', 'bar',
1901
'--format', 'yaml'), 1)
731
'juju', '--show-log', 'status', '-e', 'bar'), 1)
1903
733
def test_keep_env(self):
1904
734
cc_mock = self.addContext(patch('subprocess.check_call'))
1905
client = EnvJujuClient(JujuData(
1906
'foo', {'type': 'paas', 'region': 'qux'}), '1.23', 'path')
1907
with self.bc_context(client, keep_env=True, jes='kill-controller'):
1908
with observable_temp_file() as config_file:
1909
with boot_context('bar', client, None, [], None, None, None,
1910
None, keep_env=True, upload_tools=False):
1912
assert_juju_call(self, cc_mock, client, (
1913
'path', '--show-log', 'bootstrap', '--constraints',
1914
'mem=2G', 'bar', 'paas/qux', '--config', config_file.name,
1915
'--default-model', 'bar', '--agent-version', '1.23'), 0)
1916
assert_juju_call(self, cc_mock, client, (
1917
'path', '--show-log', 'list-controllers'), 1)
1918
assert_juju_call(self, cc_mock, client, (
1919
'path', '--show-log', 'list-models', '-c', 'bar'), 2)
1920
assert_juju_call(self, cc_mock, client, (
1921
'path', '--show-log', 'show-status', '-m', 'bar:controller',
1922
'--format', 'yaml'), 3)
1923
assert_juju_call(self, cc_mock, client, (
1924
'path', '--show-log', 'show-status', '-m', 'bar:bar',
1925
'--format', 'yaml'), 4)
1927
def test_keep_env_non_jes(self):
1928
cc_mock = self.addContext(patch('subprocess.check_call'))
1929
client = EnvJujuClient1X(SimpleEnvironment(
735
client = EnvJujuClient(SimpleEnvironment(
1930
736
'foo', {'type': 'paas'}), '1.23', 'path')
1931
737
with self.bc_context(client, keep_env=True):
1932
738
with boot_context('bar', client, None, [], None, None, None, None,
1933
739
keep_env=True, upload_tools=False):
1935
741
assert_juju_call(self, cc_mock, client, (
1936
'path', '--show-log', 'bootstrap', '-e', 'bar', '--constraints',
742
'juju', '--show-log', 'bootstrap', '-e', 'bar', '--constraints',
1938
744
assert_juju_call(self, cc_mock, client, (
1939
'path', '--show-log', 'status', '-e', 'bar',
1940
'--format', 'yaml'), 1)
745
'juju', '--show-log', 'status', '-e', 'bar'), 1)
1942
747
def test_upload_tools(self):
1943
748
cc_mock = self.addContext(patch('subprocess.check_call'))
1944
client = EnvJujuClient(JujuData(
1945
'foo', {'type': 'paas', 'region': 'qux'}), '1.23', 'path')
1946
with self.bc_context(client, jes='kill-controller'):
1947
with observable_temp_file() as config_file:
1948
with boot_context('bar', client, None, [], None, None, None,
1949
None, keep_env=False, upload_tools=True):
1951
assert_juju_call(self, cc_mock, client, (
1952
'path', '--show-log', 'bootstrap', '--upload-tools',
1953
'--constraints', 'mem=2G', 'bar', 'paas/qux', '--config',
1954
config_file.name, '--default-model', 'bar'), 0)
1956
def test_upload_tools_non_jes(self):
1957
cc_mock = self.addContext(patch('subprocess.check_call'))
1958
client = EnvJujuClient1X(SimpleEnvironment(
749
client = EnvJujuClient(SimpleEnvironment(
1959
750
'foo', {'type': 'paas'}), '1.23', 'path')
1960
751
with self.bc_context(client):
1961
752
with boot_context('bar', client, None, [], None, None, None, None,
1962
753
keep_env=False, upload_tools=True):
1964
755
assert_juju_call(self, cc_mock, client, (
1965
'path', '--show-log', 'bootstrap', '-e', 'bar', '--upload-tools',
1966
'--constraints', 'mem=2G'), 0)
1968
def test_calls_update_env_2(self):
1969
cc_mock = self.addContext(patch('subprocess.check_call'))
1970
client = EnvJujuClient(JujuData(
1971
'foo', {'type': 'paas', 'region': 'qux'}), '1.23', 'path')
1972
ue_mock = self.addContext(
1973
patch('deploy_stack.update_env', wraps=update_env))
1974
with self.bc_context(client, jes='kill-controller'):
1975
with observable_temp_file() as config_file:
1976
with boot_context('bar', client, None, [], 'wacky', 'url',
1977
'devel', None, keep_env=False,
1978
upload_tools=False):
1980
ue_mock.assert_called_with(
1981
client.env, 'bar', agent_url='url', agent_stream='devel',
1982
series='wacky', bootstrap_host=None, region=None)
1983
assert_juju_call(self, cc_mock, client, (
1984
'path', '--show-log', 'bootstrap', '--constraints', 'mem=2G',
1985
'bar', 'paas/qux', '--config', config_file.name,
1986
'--default-model', 'bar', '--agent-version', '1.23',
1987
'--bootstrap-series', 'wacky'), 0)
1989
def test_calls_update_env_1(self):
1990
cc_mock = self.addContext(patch('subprocess.check_call'))
1991
client = EnvJujuClient1X(SimpleEnvironment(
1992
'foo', {'type': 'paas'}), '1.23', 'path')
1993
ue_mock = self.addContext(
1994
patch('deploy_stack.update_env', wraps=update_env))
1995
with self.bc_context(client):
1996
with boot_context('bar', client, None, [], 'wacky', 'url', 'devel',
1997
None, keep_env=False, upload_tools=False):
1999
ue_mock.assert_called_with(
2000
client.env, 'bar', series='wacky', bootstrap_host=None,
2001
agent_url='url', agent_stream='devel', region=None)
2002
assert_juju_call(self, cc_mock, client, (
2003
'path', '--show-log', 'bootstrap', '-e', 'bar',
2004
'--constraints', 'mem=2G'), 0)
2006
def test_calls_update_env_non_jes(self):
2007
cc_mock = self.addContext(patch('subprocess.check_call'))
2008
client = EnvJujuClient1X(SimpleEnvironment(
2009
'foo', {'type': 'paas'}), '1.23', 'path')
2010
ue_mock = self.addContext(
2011
patch('deploy_stack.update_env', wraps=update_env))
2012
with self.bc_context(client):
2013
with boot_context('bar', client, None, [], 'wacky', 'url', 'devel',
2014
None, keep_env=False, upload_tools=False):
2016
ue_mock.assert_called_with(
2017
client.env, 'bar', series='wacky', bootstrap_host=None,
2018
agent_url='url', agent_stream='devel', region=None)
2019
assert_juju_call(self, cc_mock, client, (
2020
'path', '--show-log', 'bootstrap', '-e', 'bar',
756
'juju', '--show-log', 'bootstrap', '-e', 'bar', '--upload-tools',
757
'--constraints', 'mem=2G'), 0)
759
def test_calls_update_env(self):
760
cc_mock = self.addContext(patch('subprocess.check_call'))
761
client = EnvJujuClient(SimpleEnvironment(
762
'foo', {'type': 'paas'}), '1.23', 'path')
763
ue_mock = self.addContext(
764
patch('deploy_stack.update_env', wraps=update_env))
765
with self.bc_context(client):
766
with boot_context('bar', client, None, [], 'wacky', 'url', 'devel',
767
None, keep_env=False, upload_tools=False):
769
ue_mock.assert_called_with(
770
client.env, 'bar', series='wacky', bootstrap_host=None,
771
agent_url='url', agent_stream='devel')
772
assert_juju_call(self, cc_mock, client, (
773
'juju', '--show-log', 'bootstrap', '-e', 'bar',
2021
774
'--constraints', 'mem=2G'), 0)
2023
776
def test_with_bootstrap_failure(self):
2025
778
class FakeException(Exception):
2026
779
"""A sentry exception to be raised by bootstrap."""
2028
client = EnvJujuClient(JujuData(
2029
'foo', {'type': 'paas'}), '1.23', 'path')
2030
self.addContext(patch('deploy_stack.get_machine_dns_name',
2031
return_value='foo'))
2032
self.addContext(patch('subprocess.check_call'))
2033
call_mock = self.addContext(patch('subprocess.call', return_value=0))
2034
po_mock = self.addContext(patch(
2035
'subprocess.Popen', autospec=True,
2036
return_value=FakePopen('kill-controller', '', 0)))
2037
self.addContext(patch('deploy_stack.wait_for_port'))
2038
fake_exception = FakeException()
2039
self.addContext(patch.object(client, 'bootstrap',
2040
side_effect=fake_exception))
2041
crl_mock = self.addContext(patch('deploy_stack.copy_remote_logs'))
2042
al_mock = self.addContext(patch('deploy_stack.archive_logs'))
2043
le_mock = self.addContext(patch('logging.exception'))
2044
with self.assertRaises(SystemExit):
2045
with boot_context('bar', client, 'baz', [], None, None, None,
2046
'log_dir', keep_env=False, upload_tools=True):
2048
le_mock.assert_called_once_with(fake_exception)
2049
self.assertEqual(crl_mock.call_count, 1)
2050
call_args = crl_mock.call_args[0]
2051
self.assertIsInstance(call_args[0], _Remote)
2052
self.assertEqual(call_args[0].get_address(), 'baz')
2053
self.assertEqual(call_args[1], 'log_dir')
2054
al_mock.assert_called_once_with('log_dir')
2055
timeout_path = get_timeout_path()
2056
assert_juju_call(self, call_mock, client, (
2057
sys.executable, timeout_path, '600.00', '--',
2058
'path', '--show-log', 'kill-controller', 'bar', '-y'
2060
assert_juju_call(self, call_mock, client, (
2061
sys.executable, timeout_path, '600.00', '--',
2062
'path', '--show-log', 'kill-controller', 'bar', '-y'
2064
self.assertEqual(2, call_mock.call_count)
2065
self.assertEqual(0, po_mock.call_count)
2067
def test_with_bootstrap_failure_non_jes(self):
2069
class FakeException(Exception):
2070
"""A sentry exception to be raised by bootstrap."""
2072
client = EnvJujuClient1X(SimpleEnvironment(
2073
'foo', {'type': 'paas'}), '1.23', 'path')
2074
self.addContext(patch('deploy_stack.get_machine_dns_name',
2075
return_value='foo'))
2076
self.addContext(patch('subprocess.check_call'))
2077
call_mock = self.addContext(patch('subprocess.call', return_value=0))
2078
po_mock = self.addContext(patch('subprocess.Popen', autospec=True,
2079
return_value=FakePopen('', '', 0)))
2080
self.addContext(patch('deploy_stack.wait_for_port'))
2081
fake_exception = FakeException()
2082
self.addContext(patch.object(client, 'bootstrap',
2083
side_effect=fake_exception))
2084
crl_mock = self.addContext(patch('deploy_stack.copy_remote_logs'))
2085
al_mock = self.addContext(patch('deploy_stack.archive_logs'))
2086
le_mock = self.addContext(patch('logging.exception'))
2087
with self.assertRaises(SystemExit):
2088
with boot_context('bar', client, 'baz', [], None, None, None,
2089
'log_dir', keep_env=False, upload_tools=True):
2091
le_mock.assert_called_once_with(fake_exception)
2092
self.assertEqual(crl_mock.call_count, 1)
2093
call_args = crl_mock.call_args[0]
2094
self.assertIsInstance(call_args[0], _Remote)
2095
self.assertEqual(call_args[0].get_address(), 'baz')
2096
self.assertEqual(call_args[1], 'log_dir')
2097
al_mock.assert_called_once_with('log_dir')
2098
timeout_path = get_timeout_path()
2099
assert_juju_call(self, call_mock, client, (
2100
sys.executable, timeout_path, '600.00', '--',
2101
'path', '--show-log', 'destroy-environment', 'bar', '-y'
2103
assert_juju_call(self, call_mock, client, (
2104
sys.executable, timeout_path, '600.00', '--',
2105
'path', '--show-log', 'destroy-environment', 'bar', '-y'
2107
self.assertEqual(2, call_mock.call_count)
2108
assert_juju_call(self, po_mock, client, (
2109
'path', '--show-log', 'help', 'commands'), 0)
2110
assert_juju_call(self, po_mock, client, (
2111
'path', '--show-log', 'help', 'commands'), 1)
2112
self.assertEqual(2, po_mock.call_count)
781
client = EnvJujuClient(SimpleEnvironment(
782
'foo', {'type': 'paas'}), '1.23', 'path')
783
self.addContext(patch('deploy_stack.get_machine_dns_name',
785
self.addContext(patch('subprocess.check_call'))
786
self.addContext(patch('subprocess.call'))
787
self.addContext(patch('deploy_stack.wait_for_port'))
788
self.addContext(patch.object(client, 'bootstrap',
789
side_effect=FakeException))
790
crl_mock = self.addContext(patch('deploy_stack.copy_remote_logs'))
791
al_mock = self.addContext(patch('deploy_stack.archive_logs'))
792
with self.assertRaises(FakeException):
793
with boot_context('bar', client, 'baz', [], None, None, None,
794
'log_dir', keep_env=False, upload_tools=True):
796
self.assertEqual(crl_mock.call_count, 1)
797
call_args = crl_mock.call_args[0]
798
self.assertIsInstance(call_args[0], _Remote)
799
self.assertEqual(call_args[0].get_address(), 'baz')
800
self.assertEqual(call_args[1], 'log_dir')
801
al_mock.assert_called_once_with('log_dir')
2114
803
def test_jes(self):
2115
804
self.addContext(patch('subprocess.check_call', autospec=True))
2116
client = EnvJujuClient(JujuData(
2117
'foo', {'type': 'paas', 'region': 'qux'}), '1.26', 'path')
2118
with self.bc_context(client, 'log_dir', jes=KILL_CONTROLLER):
805
client = EnvJujuClient(SimpleEnvironment(
806
'foo', {'type': 'paas'}), '1.23', 'path')
807
with self.bc_context(client, 'log_dir', jes=True):
2119
808
with boot_context('bar', client, None, [], None, None, None,
2120
809
'log_dir', keep_env=False, upload_tools=False):
2123
def test_region(self):
2124
self.addContext(patch('subprocess.check_call', autospec=True))
2125
client = EnvJujuClient(JujuData(
2126
'foo', {'type': 'paas'}), '1.23', 'path')
2127
with self.bc_context(client, 'log_dir', jes='kill-controller'):
2128
with boot_context('bar', client, None, [], None, None, None,
2129
'log_dir', keep_env=False, upload_tools=False,
2132
self.assertEqual('steve', client.env.config['region'])
2134
def test_region_non_jes(self):
2135
self.addContext(patch('subprocess.check_call', autospec=True))
2136
client = EnvJujuClient1X(SimpleEnvironment(
2137
'foo', {'type': 'paas'}), '1.23', 'path')
2138
with self.bc_context(client, 'log_dir'):
2139
with boot_context('bar', client, None, [], None, None, None,
2140
'log_dir', keep_env=False, upload_tools=False,
2143
self.assertEqual('steve', client.env.config['region'])
2145
def test_status_error_raises(self):
2146
"""An error on final show-status propagates so an assess will fail."""
2147
error = subprocess.CalledProcessError(1, ['juju'], '')
2148
effects = [None, None, None, None, None, None, error]
2149
cc_mock = self.addContext(patch('subprocess.check_call', autospec=True,
2150
side_effect=effects))
2151
client = EnvJujuClient(JujuData(
2152
'foo', {'type': 'paas', 'region': 'qux'}), '1.23', 'path')
2153
with self.bc_context(client, 'log_dir', jes='kill-controller'):
2154
with observable_temp_file() as config_file:
2155
with self.assertRaises(subprocess.CalledProcessError) as ctx:
2156
with boot_context('bar', client, None, [], None, None,
2157
None, 'log_dir', keep_env=False,
2158
upload_tools=False):
2160
self.assertIs(ctx.exception, error)
2161
assert_juju_call(self, cc_mock, client, (
2162
'path', '--show-log', 'bootstrap', '--constraints',
2163
'mem=2G', 'bar', 'paas/qux', '--config', config_file.name,
2164
'--default-model', 'bar', '--agent-version', '1.23'), 0)
2165
assert_juju_call(self, cc_mock, client, (
2166
'path', '--show-log', 'list-controllers'), 1)
2167
assert_juju_call(self, cc_mock, client, (
2168
'path', '--show-log', 'list-models', '-c', 'bar'), 2)
2169
assert_juju_call(self, cc_mock, client, (
2170
'path', '--show-log', 'show-status', '-m', 'bar:controller',
2171
'--format', 'yaml'), 3)
2172
assert_juju_call(self, cc_mock, client, (
2173
'path', '--show-log', 'show-status', '-m', 'bar:bar',
2174
'--format', 'yaml'), 4)
2177
class TestDeployJobParseArgs(FakeHomeTestCase):
813
class TestDeployJobParseArgs(TestCase):
2179
815
def test_deploy_job_parse_args(self):
2180
args = deploy_job_parse_args(['foo', 'bar/juju', 'baz', 'qux'])
816
args = deploy_job_parse_args(['foo', 'bar', 'baz', 'qux'])
2181
817
self.assertEqual(args, Namespace(
2182
818
agent_stream=None,