~andrewjbeach/juju-ci-tools/make-local-patcher

« back to all changes in this revision

Viewing changes to test_substrate.py

  • Committer: Aaron Bentley
  • Date: 2015-09-02 17:46:47 UTC
  • mto: This revision was merged to the branch mainline in revision 1082.
  • Revision ID: aaron.bentley@canonical.com-20150902174647-06vmnsooo6yzd46t
Stop supplying env to subprocess calls.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from contextlib import contextmanager
2
1
import json
3
2
import os
4
3
from subprocess import CalledProcessError
29
28
    get_job_instances,
30
29
    get_libvirt_domstate,
31
30
    JoyentAccount,
32
 
    LXDAccount,
33
31
    make_substrate_manager,
34
32
    MAASAccount,
35
33
    OpenStackAccount,
52
50
        })
53
51
 
54
52
 
55
 
def get_lxd_env():
56
 
    return SimpleEnvironment('mas', {
57
 
        'type': 'lxd'
58
 
        })
59
 
 
60
 
 
61
53
def get_maas_env():
62
54
    return SimpleEnvironment('mas', {
63
55
        'type': 'maas',
78
70
    })
79
71
 
80
72
 
81
 
def get_rax_env():
82
 
    return SimpleEnvironment('rax', {
83
 
        'type': 'rackspace',
84
 
        'region': 'DFW',
85
 
        'username': 'a-user',
86
 
        'password': 'a-pasword',
87
 
        'tenant-name': '100',
88
 
        'auth-url': 'http://rax.testing',
89
 
    })
90
 
 
91
 
 
92
73
def get_aws_environ(env):
93
74
    environ = dict(os.environ)
94
75
    environ.update(get_euca_env(env.config))
202
183
        self.assertEqual(out_mock.write.mock_calls, [
203
184
            call('No instances to delete.'), call('\n')])
204
185
 
205
 
    def test_terminate_rackspace(self):
206
 
        env = get_rax_env()
207
 
        with patch('subprocess.check_call') as cc_mock:
208
 
            with patch('sys.stdout') as out_mock:
209
 
                terminate_instances(env, ['foo', 'bar'])
210
 
        environ = dict(os.environ)
211
 
        environ.update(translate_to_env(env.config))
212
 
        cc_mock.assert_called_with(
213
 
            ['nova', 'delete', 'foo', 'bar'], env=environ)
214
 
        self.assertEqual(out_mock.write.mock_calls, [
215
 
            call('Deleting foo, bar.'), call('\n')])
216
 
 
217
186
    def test_terminate_joyent(self):
218
187
        with patch('substrate.JoyentAccount.terminate_instances') as ti_mock:
219
188
            terminate_instances(
220
189
                SimpleEnvironment('foo', get_joyent_config()), ['ab', 'cd'])
221
190
        ti_mock.assert_called_once_with(['ab', 'cd'])
222
191
 
223
 
    def test_terminate_lxd(self):
224
 
        env = get_lxd_env()
225
 
        with patch('subprocess.check_call') as cc_mock:
226
 
            terminate_instances(env, ['foo', 'bar'])
227
 
        self.assertEqual(
228
 
            [call(['lxc', 'stop', '--force', 'foo']),
229
 
             call(['lxc', 'delete', '--force', 'foo']),
230
 
             call(['lxc', 'stop', '--force', 'bar']),
231
 
             call(['lxc', 'delete', '--force', 'bar'])],
232
 
            cc_mock.mock_calls)
233
 
 
234
192
    def test_terminate_uknown(self):
235
193
        env = SimpleEnvironment('foo', {'type': 'unknown'})
236
194
        with patch('subprocess.check_call') as cc_mock:
252
210
                'secret-key': 'hoover',
253
211
                }) as aws:
254
212
            self.assertEqual(aws.euca_environ, {
255
 
                'AWS_ACCESS_KEY': 'skeleton',
256
 
                'AWS_SECRET_KEY': 'hoover',
257
213
                'EC2_ACCESS_KEY': 'skeleton',
258
214
                'EC2_SECRET_KEY': 'hoover',
259
215
                'EC2_URL': 'https://france.ec2.amazonaws.com',
260
216
                })
261
217
            self.assertEqual(aws.region, 'france')
262
218
 
 
219
    def test_get_environ(self):
 
220
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
221
            environ = dict(os.environ)
 
222
            environ.update({
 
223
                'EC2_ACCESS_KEY': 'skeleton-key',
 
224
                'EC2_SECRET_KEY': 'secret-skeleton-key',
 
225
                'EC2_URL': 'https://ca-west.ec2.amazonaws.com',
 
226
                })
 
227
            self.assertEqual(aws.get_environ(), environ)
 
228
 
 
229
    def test_euca(self):
 
230
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
231
            with patch('subprocess.check_call',
 
232
                       return_value='quxx') as co_mock:
 
233
                result = aws.euca('foo-bar', ['baz', 'qux'])
 
234
            co_mock.assert_called_once_with(['euca-foo-bar', 'baz', 'qux'],
 
235
                                            env=aws.get_environ())
 
236
            self.assertEqual(result, 'quxx')
 
237
 
 
238
    def test_get_euca_output(self):
 
239
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
240
            with patch('subprocess.check_output',
 
241
                       return_value='quxx') as co_mock:
 
242
                result = aws.get_euca_output('foo-bar', ['baz', 'qux'])
 
243
            co_mock.assert_called_once_with(['euca-foo-bar', 'baz', 'qux'],
 
244
                                            env=aws.get_environ())
 
245
            self.assertEqual(result, 'quxx')
 
246
 
263
247
    def test_iter_security_groups(self):
264
 
 
265
 
        def make_group():
266
 
            class FakeGroup:
267
 
                def __init__(self, name):
268
 
                    self.name, self.id = name, name + "-id"
269
 
 
270
 
            for name in ['foo', 'foobar', 'baz']:
271
 
                group = FakeGroup(name)
272
 
                yield group
273
 
 
274
 
        client = MagicMock(spec=['get_all_security_groups'])
275
 
        client.get_all_security_groups.return_value = list(make_group())
276
 
        with patch('substrate.ec2.connect_to_region',
277
 
                   return_value=client) as ctr_mock:
278
 
            with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
248
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
249
 
 
250
            def make_group(name):
 
251
                return '\t'.join([
 
252
                    'GROUP', name + '-id', '689913858002',
 
253
                    name, 'juju group', 'vpc-1f40b47a'])
 
254
 
 
255
            return_value = ''.join(
 
256
                make_group(g) + '\n' for g in ['foo', 'foobar', 'baz'])
 
257
            return_value += 'RANDOM\n'
 
258
            return_value += '\n'
 
259
            with patch('subprocess.check_output',
 
260
                       return_value=return_value) as co_mock:
279
261
                groups = list(aws.iter_security_groups())
280
 
        self.assertEqual(groups, [
281
 
            ('foo-id', 'foo'), ('foobar-id', 'foobar'), ('baz-id', 'baz')])
282
 
        self.assert_ec2_connection_call(ctr_mock)
283
 
 
284
 
    def assert_ec2_connection_call(self, ctr_mock):
285
 
        ctr_mock.assert_called_once_with(
286
 
            'ca-west', aws_access_key_id='skeleton-key',
287
 
            aws_secret_access_key='secret-skeleton-key')
 
262
            co_mock.assert_called_once_with(
 
263
                ['euca-describe-groups', '--filter', 'description=juju group'],
 
264
                env=aws.get_environ())
 
265
            self.assertEqual(groups, [
 
266
                ('foo-id', 'foo'), ('foobar-id', 'foobar'), ('baz-id', 'baz')])
288
267
 
289
268
    def test_iter_instance_security_groups(self):
290
 
        instances = [
291
 
            MagicMock(instances=[MagicMock(groups=[
292
 
                SecurityGroup(id='foo', name='bar'), ])]),
293
 
            MagicMock(instances=[MagicMock(groups=[
294
 
                SecurityGroup(id='baz', name='qux'),
295
 
                SecurityGroup(id='quxx-id', name='quxx'), ])]),
296
 
        ]
297
 
        client = MagicMock(spec=['get_all_instances'])
298
 
        client.get_all_instances.return_value = instances
299
 
        with patch('substrate.ec2.connect_to_region',
300
 
                   return_value=client) as ctr_mock:
301
 
            with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
269
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
270
            with patch.object(aws, 'get_ec2_connection') as gec_mock:
 
271
                instances = [
 
272
                    MagicMock(instances=[MagicMock(groups=[
 
273
                        SecurityGroup(id='foo', name='bar'),
 
274
                        ])]),
 
275
                    MagicMock(instances=[MagicMock(groups=[
 
276
                        SecurityGroup(id='baz', name='qux'),
 
277
                        SecurityGroup(id='quxx-id', name='quxx'),
 
278
                        ])]),
 
279
                ]
 
280
                gai_mock = gec_mock.return_value.get_all_instances
 
281
                gai_mock.return_value = instances
302
282
                groups = list(aws.iter_instance_security_groups())
303
 
        self.assertEqual(
304
 
            groups, [('foo', 'bar'), ('baz', 'qux'), ('quxx-id', 'quxx')])
305
 
        client.get_all_instances.assert_called_once_with(instance_ids=None)
306
 
        self.assert_ec2_connection_call(ctr_mock)
 
283
            gec_mock.assert_called_once_with()
 
284
            self.assertEqual(groups, [
 
285
                ('foo', 'bar'), ('baz', 'qux'), ('quxx-id', 'quxx')])
 
286
        gai_mock.assert_called_once_with(instance_ids=None)
307
287
 
308
288
    def test_iter_instance_security_groups_instances(self):
309
 
        instances = [
310
 
            MagicMock(instances=[MagicMock(groups=[
311
 
                SecurityGroup(id='foo', name='bar'),
312
 
                ])]),
313
 
            MagicMock(instances=[MagicMock(groups=[
314
 
                SecurityGroup(id='baz', name='qux'),
315
 
                SecurityGroup(id='quxx-id', name='quxx'),
316
 
                ])]),
317
 
        ]
318
 
        client = MagicMock(spec=['get_all_instances'])
319
 
        client.get_all_instances.return_value = instances
320
 
        with patch('substrate.ec2.connect_to_region',
321
 
                   return_value=client) as ctr_mock:
322
 
            with AWSAccount.manager_from_config(get_aws_env().config) as aws:
323
 
                    list(aws.iter_instance_security_groups(['abc', 'def']))
324
 
        client.get_all_instances.assert_called_once_with(
325
 
            instance_ids=['abc', 'def'])
326
 
        self.assert_ec2_connection_call(ctr_mock)
 
289
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
290
            with patch.object(aws, 'get_ec2_connection') as gec_mock:
 
291
                instances = [
 
292
                    MagicMock(instances=[MagicMock(groups=[
 
293
                        SecurityGroup(id='foo', name='bar'),
 
294
                        ])]),
 
295
                    MagicMock(instances=[MagicMock(groups=[
 
296
                        SecurityGroup(id='baz', name='qux'),
 
297
                        SecurityGroup(id='quxx-id', name='quxx'),
 
298
                        ])]),
 
299
                ]
 
300
                gai_mock = gec_mock.return_value.get_all_instances
 
301
                gai_mock.return_value = instances
 
302
                list(aws.iter_instance_security_groups(['abc', 'def']))
 
303
        gai_mock.assert_called_once_with(instance_ids=['abc', 'def'])
327
304
 
328
305
    def test_destroy_security_groups(self):
329
 
        client = MagicMock(spec=['delete_security_group'])
330
 
        client.delete_security_group.return_value = True
331
 
        with patch('substrate.ec2.connect_to_region',
332
 
                   return_value=client) as ctr_mock:
333
 
            with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
306
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
307
            with patch('subprocess.check_call') as cc_mock:
334
308
                failures = aws.destroy_security_groups(
335
309
                    ['foo', 'foobar', 'baz'])
336
 
        calls = [call(name='foo'), call(name='foobar'), call(name='baz')]
337
 
        self.assertEqual(client.delete_security_group.mock_calls, calls)
338
 
        self.assertEqual(failures, [])
339
 
        self.assert_ec2_connection_call(ctr_mock)
 
310
            self.assertEqual(cc_mock.mock_calls[0], call(
 
311
                ['euca-delete-group', 'foo'], env=aws.get_environ()))
 
312
            self.assertEqual(cc_mock.mock_calls[1], call(
 
313
                ['euca-delete-group', 'foobar'], env=aws.get_environ()))
 
314
            self.assertEqual(cc_mock.mock_calls[2], call(
 
315
                ['euca-delete-group', 'baz'], env=aws.get_environ()))
 
316
            self.assertEqual(3, cc_mock.call_count)
 
317
            self.assertEqual(failures, [])
340
318
 
341
319
    def test_destroy_security_failures(self):
342
 
        client = MagicMock(spec=['delete_security_group'])
343
 
        client.delete_security_group.return_value = False
344
 
        with patch('substrate.ec2.connect_to_region',
345
 
                   return_value=client) as ctr_mock:
346
 
            with AWSAccount.manager_from_config(get_aws_env().config) as aws:
347
 
                failures = aws.destroy_security_groups(
348
 
                    ['foo', 'foobar', 'baz'])
349
 
        self.assertEqual(failures, ['foo', 'foobar', 'baz'])
350
 
        self.assert_ec2_connection_call(ctr_mock)
351
 
 
352
 
    @contextmanager
353
 
    def make_aws_connection(self, return_value):
354
 
        client = MagicMock(spec=['get_all_network_interfaces'])
355
 
        client.get_all_network_interfaces.return_value = return_value
356
 
        with patch('substrate.ec2.connect_to_region',
357
 
                   return_value=client) as ctr_mock:
358
 
            with AWSAccount.manager_from_config(get_aws_env().config) as aws:
359
 
                yield aws
360
 
        self.assert_ec2_connection_call(ctr_mock)
 
320
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
321
            with patch('subprocess.check_call',
 
322
                       side_effect=CalledProcessError(1, 'foo')):
 
323
                failures = aws.destroy_security_groups(['foo', 'foobar',
 
324
                                                        'baz'])
 
325
            self.assertEqual(failures, ['foo', 'foobar', 'baz'])
 
326
 
 
327
    def test_get_ec2_connection(self):
 
328
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
329
            return_value = object()
 
330
            with patch('boto.ec2.connect_to_region',
 
331
                       return_value=return_value) as ctr_mock:
 
332
                connection = aws.get_ec2_connection()
 
333
            ctr_mock.assert_called_once_with(
 
334
                'ca-west', aws_access_key_id='skeleton-key',
 
335
                aws_secret_access_key='secret-skeleton-key')
 
336
            self.assertIs(connection, return_value)
 
337
 
 
338
    def make_aws_connection(self):
 
339
        with AWSAccount.manager_from_config(get_aws_env().config) as aws:
 
340
            aws.get_ec2_connection = MagicMock()
 
341
            connection = aws.get_ec2_connection.return_value
 
342
            return aws, connection
361
343
 
362
344
    def make_interface(self, group_ids):
363
 
        interface = MagicMock(spec=['groups', 'delete', 'id'])
 
345
        interface = MagicMock()
364
346
        interface.groups = [SecurityGroup(id=g) for g in group_ids]
365
347
        return interface
366
348
 
367
349
    def test_delete_detached_interfaces_with_id(self):
 
350
        aws, connection = self.make_aws_connection()
368
351
        foo_interface = self.make_interface(['bar-id'])
369
352
        baz_interface = self.make_interface(['baz-id', 'bar-id'])
370
 
        with self.make_aws_connection([foo_interface, baz_interface]) as aws:
371
 
            unclean = aws.delete_detached_interfaces(['bar-id'])
372
 
            foo_interface.delete.assert_called_once_with()
373
 
            baz_interface.delete.assert_called_once_with()
 
353
        gani_mock = connection.get_all_network_interfaces
 
354
        gani_mock.return_value = [foo_interface, baz_interface]
 
355
        unclean = aws.delete_detached_interfaces(['bar-id'])
 
356
        gani_mock.assert_called_once_with(
 
357
            filters={'status': 'available'})
 
358
        foo_interface.delete.assert_called_once_with()
 
359
        baz_interface.delete.assert_called_once_with()
374
360
        self.assertEqual(unclean, set())
375
361
 
376
362
    def test_delete_detached_interfaces_without_id(self):
 
363
        aws, connection = self.make_aws_connection()
377
364
        baz_interface = self.make_interface(['baz-id'])
378
 
        with self.make_aws_connection([baz_interface]) as aws:
379
 
            unclean = aws.delete_detached_interfaces(['bar-id'])
 
365
        connection.get_all_network_interfaces.return_value = [baz_interface]
 
366
        unclean = aws.delete_detached_interfaces(['bar-id'])
380
367
        self.assertEqual(baz_interface.delete.call_count, 0)
381
368
        self.assertEqual(unclean, set())
382
369
 
383
370
    def prepare_delete_exception(self, error_code):
 
371
        aws, connection = self.make_aws_connection()
384
372
        baz_interface = self.make_interface(['bar-id'])
385
373
        e = EC2ResponseError('status', 'reason')
386
374
        e.error_code = error_code
387
375
        baz_interface.delete.side_effect = e
388
 
        return baz_interface
 
376
        connection.get_all_network_interfaces.return_value = [baz_interface]
 
377
        return aws, baz_interface
389
378
 
390
379
    def test_delete_detached_interfaces_in_use(self):
391
 
        baz_interface = self.prepare_delete_exception(
 
380
        aws, baz_interface = self.prepare_delete_exception(
392
381
            'InvalidNetworkInterface.InUse')
393
 
        with self.make_aws_connection([baz_interface]) as aws:
394
 
            unclean = aws.delete_detached_interfaces(['bar-id', 'foo-id'])
 
382
        unclean = aws.delete_detached_interfaces(['bar-id', 'foo-id'])
395
383
        baz_interface.delete.assert_called_once_with()
396
384
        self.assertEqual(unclean, set(['bar-id']))
397
385
 
398
386
    def test_delete_detached_interfaces_not_found(self):
399
 
        baz_interface = self.prepare_delete_exception(
 
387
        aws, baz_interface = self.prepare_delete_exception(
400
388
            'InvalidNetworkInterfaceID.NotFound')
401
 
        with self.make_aws_connection([baz_interface]) as aws:
402
 
            unclean = aws.delete_detached_interfaces(['bar-id', 'foo-id'])
 
389
        unclean = aws.delete_detached_interfaces(['bar-id', 'foo-id'])
403
390
        baz_interface.delete.assert_called_once_with()
404
391
        self.assertEqual(unclean, set(['bar-id']))
405
392
 
406
393
    def test_delete_detached_interfaces_other(self):
407
 
        baz_interface = self.prepare_delete_exception(
 
394
        aws, baz_interface = self.prepare_delete_exception(
408
395
            'InvalidNetworkInterfaceID')
409
 
        with self.make_aws_connection([baz_interface]) as aws:
410
 
            with self.assertRaises(EC2ResponseError):
411
 
                aws.delete_detached_interfaces(['bar-id', 'foo-id'])
 
396
        with self.assertRaises(EC2ResponseError):
 
397
            aws.delete_detached_interfaces(['bar-id', 'foo-id'])
412
398
 
413
399
 
414
400
def get_os_config():
568
554
        client.delete_machine.assert_called_once_with('a')
569
555
 
570
556
 
571
 
def get_lxd_config():
572
 
    return {'type': 'lxd'}
573
 
 
574
 
 
575
 
class TestLXDAccount(TestCase):
576
 
 
577
 
    def test_manager_from_config(self):
578
 
        config = get_lxd_config()
579
 
        with LXDAccount.manager_from_config(config) as account:
580
 
            self.assertIsNone(account.remote)
581
 
        config['region'] = 'lxd-server'
582
 
        with LXDAccount.manager_from_config(config) as account:
583
 
            self.assertEqual('lxd-server', account.remote)
584
 
 
585
 
    def test_terminate_instances(self):
586
 
        account = LXDAccount()
587
 
        with patch('subprocess.check_call', autospec=True) as cc_mock:
588
 
            account.terminate_instances(['asdf'])
589
 
        self.assertEqual(
590
 
            [call(['lxc', 'stop', '--force', 'asdf']),
591
 
             call(['lxc', 'delete', '--force', 'asdf'])],
592
 
            cc_mock.mock_calls)
593
 
 
594
 
    def test_terminate_instances_with_remote(self):
595
 
        account = LXDAccount(remote='lxd-server')
596
 
        with patch('subprocess.check_call', autospec=True) as cc_mock:
597
 
            account.terminate_instances(['asdf'])
598
 
        self.assertEqual(
599
 
            [call(['lxc', 'stop', '--force', 'asdf']),
600
 
             call(['lxc', 'delete', '--force', 'lxd-server:asdf'])],
601
 
            cc_mock.mock_calls)
602
 
 
603
 
 
604
557
def make_sms(instance_ids):
605
558
    from azure import servicemanagement as sm
606
559
    client = create_autospec(sm.ServiceManagementService('foo', 'bar'))
746
699
            ips = account.get_allocated_ips()
747
700
        self.assertEqual('10.0.30.165', ips['maas-node-1.maas'])
748
701
 
749
 
    @patch('subprocess.check_call', autospec=True)
750
 
    def test_get_allocated_ips_empty(self, cc_mock):
751
 
        config = get_maas_env().config
752
 
        account = MAASAccount(
753
 
            config['name'], config['maas-server'], config['maas-oauth'])
754
 
        node = make_maas_node('maas-node-1.maas')
755
 
        node['ip_addresses'] = []
756
 
        allocated_nodes_string = '[%s]' % json.dumps(node)
757
 
        with patch('subprocess.check_output', autospec=True,
758
 
                   return_value=allocated_nodes_string):
759
 
            ips = account.get_allocated_ips()
760
 
        self.assertEqual({}, ips)
761
 
 
762
702
 
763
703
class TestMakeSubstrateManager(TestCase):
764
704
 
767
707
        with make_substrate_manager(aws_env.config) as aws:
768
708
            self.assertIs(type(aws), AWSAccount)
769
709
            self.assertEqual(aws.euca_environ, {
770
 
                'AWS_ACCESS_KEY': 'skeleton-key',
771
 
                'AWS_SECRET_KEY': 'secret-skeleton-key',
772
710
                'EC2_ACCESS_KEY': 'skeleton-key',
773
711
                'EC2_SECRET_KEY': 'secret-skeleton-key',
774
712
                'EC2_URL': 'https://ca-west.ec2.amazonaws.com',
785
723
            self.assertEqual(account._auth_url, 'qux')
786
724
            self.assertEqual(account._region_name, 'quxx')
787
725
 
788
 
    def test_make_substrate_manager_rackspace(self):
789
 
        config = get_os_config()
790
 
        config['type'] = 'rackspace'
791
 
        with make_substrate_manager(config) as account:
792
 
            self.assertIs(type(account), OpenStackAccount)
793
 
            self.assertEqual(account._username, 'foo')
794
 
            self.assertEqual(account._password, 'bar')
795
 
            self.assertEqual(account._tenant_name, 'baz')
796
 
            self.assertEqual(account._auth_url, 'qux')
797
 
            self.assertEqual(account._region_name, 'quxx')
798
 
 
799
726
    def test_make_substrate_manager_joyent(self):
800
727
        config = get_joyent_config()
801
728
        with make_substrate_manager(config) as account:
925
852
        self.assertEqual(
926
853
            [('i-foo', 'bar-0'), ('i-baz', 'bar-1')], [d for d in description])
927
854
 
928
 
    def test_run_instances_without_series(self):
 
855
    def test_run_instances(self):
929
856
        euca_data = dedent("""
930
857
            header
931
858
            INSTANCE\ti-foo\tblah\tbar-0
940
867
                           return_value=description, autospec=True) as di_mock:
941
868
                    with patch('get_ami.query_ami',
942
869
                               return_value=ami, autospec=True) as qa_mock:
943
 
                        run_instances(2, 'qux', None)
 
870
                        run_instances(2, 'qux')
944
871
        co_mock.assert_called_once_with(
945
872
            ['euca-run-instances', '-k', 'id_rsa', '-n', '2',
946
873
             '-t', 'm1.large', '-g', 'manual-juju-test', ami],
949
876
            ['euca-create-tags', '--tag', 'job_name=qux', 'i-foo', 'i-baz'],
950
877
            env=os.environ)
951
878
        di_mock.assert_called_once_with(['i-foo', 'i-baz'], env=os.environ)
952
 
        qa_mock.assert_called_once_with('precise', 'amd64', region=None)
953
 
 
954
 
    @patch('get_ami.query_ami', autospec=True)
955
 
    @patch('substrate.describe_instances', autospec=True)
956
 
    @patch('subprocess.check_call', autospec=True)
957
 
    @patch('subprocess.check_output', autospec=True)
958
 
    def test_run_instances_with_series(self,
959
 
                                       co_mock, cc_mock, di_mock, qa_mock):
960
 
        co_mock.return_value = dedent("""
961
 
            header
962
 
            INSTANCE\ti-foo\tblah\tbar-0
963
 
            INSTANCE\ti-baz\tblah\tbar-1
964
 
            """)
965
 
        di_mock.return_value = [('i-foo', 'bar-0'), ('i-baz', 'bar-1')]
966
 
        qa_mock.return_value = "ami-atest"
967
 
        run_instances(2, 'qux', 'wily')
968
 
        qa_mock.assert_called_once_with('wily', 'amd64', region=None)
 
879
        qa_mock.assert_called_once_with('precise', 'amd64')
969
880
 
970
881
    def test_run_instances_tagging_failed(self):
971
882
        euca_data = 'INSTANCE\ti-foo\tblah\tbar-0'
978
889
                           return_value=description, autospec=True):
979
890
                    with patch('subprocess.call', autospec=True) as c_mock:
980
891
                        with self.assertRaises(CalledProcessError):
981
 
                            run_instances(1, 'qux', 'trusty')
 
892
                            run_instances(1, 'qux')
982
893
        c_mock.assert_called_with(['euca-terminate-instances', 'i-foo'])
983
894
 
984
895
    def test_run_instances_describe_failed(self):
989
900
                       side_effect=CalledProcessError('', '')):
990
901
                with patch('subprocess.call', autospec=True) as c_mock:
991
902
                    with self.assertRaises(CalledProcessError):
992
 
                        run_instances(1, 'qux', 'trusty')
 
903
                        run_instances(1, 'qux')
993
904
        c_mock.assert_called_with(['euca-terminate-instances', 'i-foo'])
994
905
 
995
906
    def test_destroy_job_instances_none(self):